mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Working on the time tracker
This commit is contained in:
parent
57a6f0c053
commit
6a66000db7
@ -14,11 +14,13 @@
|
|||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
|
/*
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
#formDiv {
|
#formDiv {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
#clock,
|
#clock,
|
||||||
@ -124,6 +126,10 @@
|
|||||||
xpadding-bottom: 10px !important;
|
xpadding-bottom: 10px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui-timepicker-wrapper {
|
||||||
|
width: 10em !important;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@ -184,7 +190,7 @@
|
|||||||
|
|
||||||
<!-- Task Form -->
|
<!-- Task Form -->
|
||||||
<div class="col-sm-7 col-sm-push-5">
|
<div class="col-sm-7 col-sm-push-5">
|
||||||
<div id="formDiv" class="panel panel-default affix" data-bind="visible: selectedTask" style="margin:20px; display:none;">
|
<div id="formDiv" class="panel panel-default x-affix" data-bind="visible: selectedTask" style="margin:20px; display:none;">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form id="taskForm">
|
<form id="taskForm">
|
||||||
<span data-bind="event: { keypress: onFormKeyPress, change: onFormChange, input: onFormChange }">
|
<span data-bind="event: { keypress: onFormKeyPress, change: onFormChange, input: onFormChange }">
|
||||||
@ -214,21 +220,22 @@
|
|||||||
<tr data-bindx="event: { mouseover: showActions, mouseout: hideActions }">
|
<tr data-bindx="event: { mouseover: showActions, mouseout: hideActions }">
|
||||||
<td style="padding: 0 6px 10px 0">
|
<td style="padding: 0 6px 10px 0">
|
||||||
{!! Former::text('date')
|
{!! Former::text('date')
|
||||||
->data_bindx('timepicker: startTime')
|
->data_bindx("")
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 0 6px 10px 6px">
|
<td style="padding: 0 6px 10px 6px">
|
||||||
{!! Former::text('start_time')
|
{!! Former::text('start_time')
|
||||||
->data_bind('timepicker: startTime')
|
->data_bind("timepicker: startTime, timepickerOptions: {scrollDefault: 'now', timeFormat: '" . ($account->military_time ? 'H:i:s' : 'g:i:s A') . "'}")
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 0 6px 10px 6px">
|
<td style="padding: 0 6px 10px 6px">
|
||||||
{!! Former::text('end_time')
|
{!! Former::text('end_time')
|
||||||
->data_bind('timepicker: endTime')
|
->data_bind("timepicker: endTime, timepickerOptions: {scrollDefault: 'now', timeFormat: '" . ($account->military_time ? 'H:i:s' : 'g:i:s A') . "'}")
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 0 0 10px 6px">
|
<td style="padding: 0 0 10px 6px">
|
||||||
{!! Former::text('duration')
|
{!! Former::text('duration')
|
||||||
|
->data_bind("timepicker: duration, timepickerOptions: {timeFormat: 'H:i:s', showAsDuration: true}")
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@ -239,12 +246,6 @@
|
|||||||
class="form-control time-input time-input-start" placeholder="{{ trans('texts.start_time') }}"/>
|
class="form-control time-input time-input-start" placeholder="{{ trans('texts.start_time') }}"/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 0px 12px 12px 0 !important">
|
|
||||||
<div data-bind="css: { 'has-error': !isEndValid() }">
|
|
||||||
<input type="text" data-bind="dateTimePicker: endTime.pretty, event:{ change: $root.refresh }"
|
|
||||||
class="form-control time-input time-input-end" placeholder="{{ trans('texts.end_time') }}"/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td style="padding: 0px 12px 12px 0 !important; width:100px">
|
<td style="padding: 0px 12px 12px 0 !important; width:100px">
|
||||||
<input type="text" data-bind="value: duration.pretty, visible: !isEmpty()" class="form-control"></div>
|
<input type="text" data-bind="value: duration.pretty, visible: !isEmpty()" class="form-control"></div>
|
||||||
<a href="#" data-bind="click: function() { setNow(), $root.refresh() }, visible: isEmpty()">{{ trans('texts.set_now') }}</a>
|
<a href="#" data-bind="click: function() { setNow(), $root.refresh() }, visible: isEmpty()">{{ trans('texts.set_now') }}</a>
|
||||||
@ -455,38 +456,6 @@
|
|||||||
}, 1000 * 60 * 15);
|
}, 1000 * 60 * 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
ko.bindingHandlers.timepicker = {
|
|
||||||
init: function (element, valueAccessor, allBindingsAccessor) {
|
|
||||||
var options = allBindingsAccessor().dropdownOptions|| {};
|
|
||||||
var value = ko.utils.unwrapObservable(valueAccessor());
|
|
||||||
var options = {
|
|
||||||
scrollDefault: 'now',
|
|
||||||
showDuration: true,
|
|
||||||
step: 15,
|
|
||||||
};
|
|
||||||
$(element).timepicker(options);
|
|
||||||
|
|
||||||
ko.utils.registerEventHandler(element, "change", function () {
|
|
||||||
var value = valueAccessor();
|
|
||||||
value($(element).val());
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
var id = (value && value.public_id) ? value.public_id() : (value && value.id) ? value.id() : value ? value : false;
|
|
||||||
if (id) $(element).val(id);
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
update: function (element, valueAccessor) {
|
|
||||||
var value = ko.utils.unwrapObservable(valueAccessor());
|
|
||||||
var field = $(element).attr('name');
|
|
||||||
if (field == 'start_time') {
|
|
||||||
$input = $(element).closest('td').next('td').find('input').show();
|
|
||||||
$input.timepicker('option', 'durationTime', $(element).val());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
// setup clients and project comboboxes
|
// setup clients and project comboboxes
|
||||||
|
@ -1,5 +1,63 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function intToTime(seconds)
|
||||||
|
{
|
||||||
|
if (seconds === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate seconds, minutes, hours
|
||||||
|
var duration = seconds*1000
|
||||||
|
var milliseconds = parseInt((duration%1000)/100)
|
||||||
|
, seconds = parseInt((duration/1000)%60)
|
||||||
|
, minutes = parseInt((duration/(1000*60))%60)
|
||||||
|
, hours = parseInt((duration/(1000*60*60))%24);
|
||||||
|
|
||||||
|
hours = (hours < 10) ? "0" + hours : hours;
|
||||||
|
minutes = (minutes < 10) ? "0" + minutes : minutes;
|
||||||
|
seconds = (seconds < 10) ? "0" + seconds : seconds;
|
||||||
|
|
||||||
|
return new Date(1970, 0, 1, hours, minutes, seconds, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ko.bindingHandlers.timepicker = {
|
||||||
|
init: function (element, valueAccessor, allBindingsAccessor) {
|
||||||
|
var options = allBindingsAccessor().timepickerOptions || {};
|
||||||
|
$.extend(options, {
|
||||||
|
wrapHours: false,
|
||||||
|
showDuration: true,
|
||||||
|
step: 15,
|
||||||
|
});
|
||||||
|
$(element).timepicker(options);
|
||||||
|
|
||||||
|
ko.utils.registerEventHandler(element, 'change', function () {
|
||||||
|
var value = valueAccessor();
|
||||||
|
var dateTime = $(element).timepicker('getTime');
|
||||||
|
if (dateTime) {
|
||||||
|
time = dateTime.getTime() / 1000;
|
||||||
|
}
|
||||||
|
value(time);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
update: function (element, valueAccessor) {
|
||||||
|
var value = ko.utils.unwrapObservable(valueAccessor());
|
||||||
|
var field = $(element).attr('name');
|
||||||
|
|
||||||
|
if (field == 'duration') {
|
||||||
|
$(element).timepicker('setTime', intToTime(value));
|
||||||
|
} else {
|
||||||
|
$(element).timepicker('setTime', new Date(value * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(field + ': ' + value);
|
||||||
|
if (field == 'start_time') {
|
||||||
|
$input = $(element).closest('td').next('td').find('input').show();
|
||||||
|
$input.timepicker('option', 'durationTime', $(element).val());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function ViewModel() {
|
function ViewModel() {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.tasks = ko.observableArray();
|
self.tasks = ko.observableArray();
|
||||||
@ -881,7 +939,6 @@
|
|||||||
var self = this;
|
var self = this;
|
||||||
self.startTime = ko.observable(0);
|
self.startTime = ko.observable(0);
|
||||||
self.endTime = ko.observable(0);
|
self.endTime = ko.observable(0);
|
||||||
self.duration = ko.observable(0);
|
|
||||||
self.actionsVisible = ko.observable(false);
|
self.actionsVisible = ko.observable(false);
|
||||||
self.isStartValid = ko.observable(true);
|
self.isStartValid = ko.observable(true);
|
||||||
self.isEndValid = ko.observable(true);
|
self.isEndValid = ko.observable(true);
|
||||||
@ -908,9 +965,17 @@
|
|||||||
return moment.unix(self.startTime()).fromNow();
|
return moment.unix(self.startTime()).fromNow();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.duration = ko.computed(function() {
|
self.duration = ko.computed({
|
||||||
model.clock(); // bind to the clock
|
read: function () {
|
||||||
return (self.endTime() || moment().unix()) - self.startTime();
|
model.clock(); // bind to the clock
|
||||||
|
var endTime = self.endTime() ? self.endTime() : moment().unix();
|
||||||
|
//console.log('duration: ' + (endTime - self.startTime()));
|
||||||
|
return endTime - self.startTime();
|
||||||
|
},
|
||||||
|
write: function(value) {
|
||||||
|
console.log('duration: ' + value);
|
||||||
|
//self.endTime(value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user