1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-16 16:13:20 +01:00
invoiceninja/resources/views/tasks/time_tracker.blade.php

686 lines
24 KiB
PHP
Raw Normal View History

2017-09-24 14:42:24 +02:00
@extends('master')
@section('head')
@parent
<link href="{{ asset('css/built.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
2017-09-29 11:59:53 +02:00
<link href="{{ asset('css/jquery.timepicker.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
<script src="{{ asset('js/jquery.timepicker.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script>
2017-09-24 14:42:24 +02:00
@stop
@section('head_css')
@parent
<style type="text/css">
2017-09-26 09:58:34 +02:00
@media (max-width: 768px) {
#clock,
#startLabel {
display: none;
}
2017-10-08 16:35:56 +02:00
#taskList {
position: relative !important;
}
2017-09-26 09:58:34 +02:00
.navbar-right button {
padding-left: 0px;
}
}
2017-10-08 16:35:56 +02:00
@media (max-width: 992px) {
.no-padding-mobile {
padding-left: 15px !important;
padding-right: 15px !important;
}
}
2017-09-24 14:42:24 +02:00
button .glyphicon {
vertical-align: text-top;
}
a:focus {
outline: none;
}
2017-10-02 19:07:41 +02:00
span.archived-link {
color: #888888 !important;
}
2017-09-25 18:59:13 +02:00
.fade-color {
animation-name: fadeToYellow;
}
.list-group-item {
animation-duration: .5s;
}
2017-09-24 14:42:24 +02:00
.list-group-item.active {
background-color: #f8f8f8 !important;
color: black !important;
2017-10-02 14:33:00 +02:00
border: 1px solid rgba(81, 203, 238, 1);
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
2017-09-24 14:42:24 +02:00
}
2017-09-25 18:59:13 +02:00
.list-group-item.changed {
background-color: #ffffaa !important;
}
@keyframes fadeToYellow {
from {background-color: #f8f8f8}
to {background-color: #ffffaa}
}
2017-09-24 22:25:56 +02:00
.list-group-item.active .list-group-item-text,
.list-group-item.active:focus .list-group-item-text,
.list-group-item.active:hover .list-group-item-text {
color: black !important;
}
2017-09-24 14:42:24 +02:00
span.link {
cursor:pointer;
color:#337ab7;
text-decoration:none;
}
span.link:hover {
text-decoration:underline;
}
.list-group-item:before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 6px;
content: "";
}
.list-group-item-type1:before { background-color: #1c9f77; }
.list-group-item-type2:before { background-color: #d95d02; }
.list-group-item-type3:before { background-color: #716cb1; }
.list-group-item-type4:before { background-color: #e62a8b; }
.list-group-item-type5:before { background-color: #5fa213; }
.list-group-item-type6:before { background-color: #e6aa04; }
.list-group-item-type7:before { background-color: #a87821; }
.list-group-item-type8:before { background-color: #676767; }
2017-09-28 11:34:02 +02:00
.list-group-item-running:after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 6px;
content: "";
2017-10-02 14:33:00 +02:00
background-color: #36c157;
2017-09-28 11:34:02 +02:00
}
2017-09-24 21:44:20 +02:00
body {
margin-bottom: 60px;
2017-10-02 20:03:12 +02:00
overflow-y: scroll;
2017-09-24 21:44:20 +02:00
}
2017-10-02 11:57:38 +02:00
#taskList {
position: fixed;
}
2017-10-01 19:26:53 +02:00
.ui-timepicker-wrapper.start-time {
width: 140px !important;
}
.ui-timepicker-wrapper.end-time {
2017-10-01 12:06:15 +02:00
width: 230px !important;
2017-09-30 23:13:41 +02:00
}
2017-09-24 21:44:20 +02:00
.footer {
position: fixed;
bottom: 0;
width: 100%;
height: 60px;
background-color: #313131;
color: white;
border-top-width: 3px;
border-top-color: #aaa;
border-top-style: ridge;
}
2017-09-24 14:42:24 +02:00
</style>
@stop
@section('body')
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-collapse" style="padding-top:12px; padding-bottom:12px;">
<!-- Navbar Buttons -->
2017-09-27 14:26:55 +02:00
<ul class="nav navbar-right" style="margin-right:0px; padding-left:12px; float:right; display: none;">
2017-10-02 20:26:17 +02:00
<span id="clock" data-bind="text: selectedTask().duration || '0:00:00'" class="hidden-xs"
style="font-size:28px; color:white; padding-right:12px; vertical-align:middle;"></span>
2017-09-24 14:42:24 +02:00
<button type='button' data-bind="click: onStartClick, css: startClass" class="btn btn-lg">
2017-09-26 09:58:34 +02:00
<span id="startLabel" data-bind="text: startLabel"></span>
2017-09-24 14:42:24 +02:00
<span data-bind="css: startIcon"></span>
</button>
</ul>
<!-- Navbar Filter -->
<div class="input-group input-group-lg">
2017-12-20 09:41:40 +01:00
<span class="input-group-addon" style="width:1%;" data-bind="click: onFilterClick, style: { 'background-color': (filterState() != 'all' || filterStatusId() != '') ? '#ffffaa' : '' }" title="{{ trans('texts.filter_sort') }}"><span class="glyphicon glyphicon-filter"></span></span>
2017-09-24 16:04:32 +02:00
<input id="search" type="search" class="form-control search" autocomplete="off" autofocus="autofocus"
2017-10-02 17:21:11 +02:00
data-bind="event: { focus: onFilterFocus, input: onFilterChanged, keypress: onFilterKeyPress }, value: filter, valueUpdate: 'afterkeydown', attr: {placeholder: placeholder, style: filterStyle, disabled: selectedTask().isChanged }">
2017-10-02 21:09:15 +02:00
<span class="input-group-addon" style="width:1%;" data-bind="click: onClearClick, visible: filter()" title="{{ trans('texts.clear') }}">
2017-10-02 20:22:19 +02:00
<span class="glyphicon glyphicon-remove"></span>
</span>
<span class="input-group-addon" style="width:1%;" data-bind="click: onRefreshClick, visible: ! filter()" title="{{ trans('texts.refresh') }}">
<span class="glyphicon glyphicon-repeat"></span>
</span>
2017-09-24 14:42:24 +02:00
</div>
</div>
</div>
</nav>
2017-09-28 19:57:55 +02:00
<div style="height:72px"></div>
2017-09-24 14:42:24 +02:00
<!--
<div data-bind="text: ko.toJSON(model.selectedTask().client_id)"></div>
<div data-bind="text: ko.toJSON(model.selectedTask().project_id)"></div>
2017-09-25 15:46:02 +02:00
<div data-bind="text: ko.toJSON(model.selectedTask().client)"></div>
2017-09-24 14:42:24 +02:00
<div data-bind="text: ko.toJSON(model.selectedTask().project)"></div>
2017-09-25 15:46:02 +02:00
Client: <span data-bind="text: ko.toJSON(model.selectedClient().public_id)"></span>
Project: <span data-bind="text: ko.toJSON(model.selectedProject().public_id)"></span>
2017-09-24 14:42:24 +02:00
-->
<div class="container" style="margin: 0 auto;width: 100%;">
<div class="row no-gutter">
<!-- Task Form -->
2017-10-03 08:37:19 +02:00
<div id="taskForm" class="col-sm-8 col-sm-push-4 col-md-7 col-md-push-5">
2017-09-30 23:13:41 +02:00
<div id="formDiv" class="panel panel-default x-affix" data-bind="visible: selectedTask" style="margin:20px; display:none;">
2017-09-24 16:35:24 +02:00
<div class="panel-body">
<form id="taskForm">
2017-10-02 17:21:11 +02:00
<span data-bind="event: { keypress: onFormKeyPress }">
2017-10-02 20:03:12 +02:00
<div class="row">
2017-10-08 16:35:56 +02:00
<div style="padding-bottom: 20px; padding-right:6px;" class="client-select col-md-6 no-padding-mobile">
2017-10-02 20:03:12 +02:00
{!! Former::select('client_id')
->addOption('', '')
->label('client')
->data_bind("dropdown: selectedTask().client_id, dropdownOptions: {highlighter: comboboxHighlighter}") !!}
2017-10-02 20:03:12 +02:00
</div>
2017-10-08 16:35:56 +02:00
<div style="padding-bottom: 20px; padding-left:6px;" class="project-select col-md-6 no-padding-mobile">
2017-10-02 20:03:12 +02:00
{!! Former::select('project_id')
->addOption('', '')
->data_bind("dropdown: selectedTask().project_id, dropdownOptions: {highlighter: comboboxHighlighter}")
2017-10-02 20:03:12 +02:00
->label(trans('texts.project')) !!}
</div>
2017-09-24 16:35:24 +02:00
</div>
2018-04-04 21:43:32 +02:00
@if (Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS))
<div class="row">
@if ($customLabel = $account->customLabel('task1'))
<div style="padding-bottom: 20px; padding-right:6px;" class="col-md-6 no-padding-mobile">
@include('partials.custom_field', [
'field' => 'custom_value1',
'label' => $customLabel,
'databind' => "value: selectedTask().custom_value1, valueUpdate: 'afterkeydown'",
])
</div>
@endif
@if ($customLabel = $account->customLabel('task2'))
<div style="padding-bottom: 20px; padding-left:6px;" class="col-md-6 no-padding-mobile">
@include('partials.custom_field', [
'field' => 'custom_value2',
'label' => $customLabel,
'databind' => "value: selectedTask().custom_value2, valueUpdate: 'afterkeydown'",
])
</div>
@endif
</div>
@endif
2017-09-29 11:59:53 +02:00
<div style="padding-bottom: 20px">
2017-09-24 16:35:24 +02:00
{!! Former::textarea('description')
2017-10-07 23:34:58 +02:00
->data_bind("value: selectedTask().description, valueUpdate: 'afterkeydown'")
2017-09-24 16:35:24 +02:00
->rows(4) !!}
2017-09-29 11:59:53 +02:00
</div>
<label>{{ trans('texts.times') }}</label>
2017-10-01 13:01:37 +02:00
<table class="table times-table" data-bind="event: { change: selectedTask().onChange }" style="margin-bottom: 0px !important;">
2017-10-02 10:54:22 +02:00
<tbody data-bind="foreach: selectedTask().sortedTimes">
2017-10-01 11:01:31 +02:00
<tr data-bind="event: { mouseover: onMouseOver, mouseout: onMouseOut }">
2017-10-02 20:35:14 +02:00
<td style="width: 25%; padding: 0 6px 10px 0">
2017-09-29 11:59:53 +02:00
{!! Former::text('date')
2017-10-01 12:04:49 +02:00
->placeholder($account->formatDate($account->getDateTime()))
2017-10-01 08:55:45 +02:00
->data_bind("datepicker: startDate, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT, DEFAULT_DATE_PICKER_FORMAT))
2017-09-29 11:59:53 +02:00
->raw() !!}
</td>
2017-10-02 20:35:14 +02:00
<td style="width: 25%; padding: 0 6px 10px 6px">
2017-10-01 15:16:27 +02:00
<div data-bind="css: { 'has-error': !isStartValid() }">
{!! Former::text('start_time')
->placeholder('start_time')
2017-10-01 19:26:53 +02:00
->data_bind("timepicker: startTimeOfDay, timepickerOptions: {className: 'start-time', scrollDefault: 'now', timeFormat: '" . ($account->military_time ? 'H:i:s' : 'g:i:s A') . "'}")
2017-10-01 15:16:27 +02:00
->raw() !!}
</div>
2017-09-29 11:59:53 +02:00
</td>
2017-10-02 20:35:14 +02:00
<td style="width: 25%; padding: 0 6px 10px 6px">
2017-10-01 15:16:27 +02:00
<div data-bind="css: { 'has-error': !isEndValid() }">
{!! Former::text('end_time')
->placeholder('end_time')
2017-10-01 19:26:53 +02:00
->data_bind("timepicker: endTimeOfDay, timepickerOptions: {className: 'end-time', scrollDefault: 'now', timeFormat: '" . ($account->military_time ? 'H:i:s' : 'g:i:s A') . "'}")
2017-10-01 15:16:27 +02:00
->raw() !!}
</div>
2017-09-29 11:59:53 +02:00
</td>
2017-10-08 16:38:09 +02:00
<td style="padding: 0 0 10px 6px" class="hide-phone">
2017-09-29 11:59:53 +02:00
{!! Former::text('duration')
2017-10-01 11:01:31 +02:00
->placeholder('duration')
2017-10-01 18:43:05 +02:00
->data_bind("typeahead: duration")
2017-09-29 11:59:53 +02:00
->raw() !!}
</td>
2017-10-02 20:35:14 +02:00
<td style="width: 38px; padding-top: 0px; padding-right: 8px" class="hide-phone">
2017-10-01 11:01:31 +02:00
<i style="cursor:pointer;float:right" data-bind="click: $root.selectedTask().removeTime, visible: actionButtonVisible" class="fa fa-minus-circle redlink" title="{{ trans('texts.remove') }}"/>
</td>
2017-09-29 11:59:53 +02:00
</tr>
</tbody>
</table>
2017-09-24 16:35:24 +02:00
</span>
2017-09-26 09:58:34 +02:00
<center id="buttons" style="padding-top: 30px">
2017-09-24 16:35:24 +02:00
<span data-bind="visible: showArchive">
{!! DropdownButton::normal(trans('texts.archive'))
2017-09-24 14:42:24 +02:00
->withAttributes([
2017-09-24 16:35:24 +02:00
'class' => 'archive-dropdown',
2017-09-24 14:42:24 +02:00
])
2017-09-24 16:35:24 +02:00
->large()
->withContents([
['label' => trans('texts.delete_task'), 'url' => 'javascript:model.onDeleteClick()'],
]
)->split() !!}
</span>
2017-10-02 19:07:41 +02:00
{!! Button::normal(trans('texts.discard'))
->appendIcon(Icon::create('remove-circle'))
->withAttributes([
'data-bind' => 'click: onCancelClick, visible: showDiscard',
])
->large() !!}
2017-09-24 16:35:24 +02:00
{!! Button::normal(trans('texts.cancel'))
->appendIcon(Icon::create('remove-circle'))
->withAttributes([
'data-bind' => 'click: onCancelClick, visible: showCancel',
])
->large() !!}
&nbsp;
{!! Button::success(trans('texts.save'))
->large()
->appendIcon(Icon::create('floppy-disk'))
->withAttributes([
2017-10-02 17:21:11 +02:00
'data-bind' => 'click: onSaveClick, css: { disabled: ! isSaveEnabled() }',
2017-09-24 16:35:24 +02:00
]) !!}
</center>
</form>
2017-09-24 14:42:24 +02:00
</div>
</div>
</div>
<!-- Task List -->
2017-10-03 08:37:19 +02:00
<div id="taskList" class="list-group col-sm-4 col-sm-pull-8 col-md-5 col-md-pull-7" style="display:none;overflow:auto;margin-bottom:0px;">
2017-09-28 11:21:05 +02:00
<div id="filterPanel" style="margin-bottom:0px;padding-top:20px;padding-bottom:0px;padding-left:10px;display:none;">
2017-10-02 14:33:00 +02:00
<div class="panel panel-default">
<div class="panel-body">
<div class="row" xstyle="padding-bottom:22px;">
2017-12-20 09:41:40 +01:00
@if ($statuses->count())
<div class="col-md-6">
{!! Former::select('filter_status')
->label('status')
->addOption(trans('texts.all'), '')
->fromQuery($statuses, 'name', 'public_id')
->data_bind('value: filterStatusId') !!}
</div>
@endif
<div class="col-md-{{ $statuses->count() ? '6' : '12' }}">
2017-10-02 14:33:00 +02:00
{!! Former::select('filter_state')
->label('filter')
->addOption(trans('texts.all'), 'all')
->addOption(trans('texts.stopped'), 'stopped')
->addOption(trans('texts.running'), 'running')
->data_bind('value: filterState') !!}
</div>
2017-09-27 22:15:42 +02:00
</div>
2017-10-02 14:33:00 +02:00
<div class="row">
<div class="col-md-6" style="padding-top:24px;">
{!! Former::select('sort_field')
->addOption(trans('texts.date'), 'createdAt')
->addOption(trans('texts.duration'), 'duration')
->addOption(trans('texts.client'), 'client')
->addOption(trans('texts.project'), 'project')
->addOption(trans('texts.description'), 'description')
->data_bind('value: sortField, event: {change: onSortChange}') !!}
</div>
<div class="col-md-6" style="padding-top:24px;">
{!! Former::select('sort_direction')
->addOption(trans('texts.ascending'), 'ascending')
->addOption(trans('texts.descending'), 'descending')
->data_bind('value: sortDirection, event: {change: onSortChange}') !!}
</div>
2017-09-27 22:15:42 +02:00
</div>
</div>
2017-09-25 19:09:23 +02:00
</div>
2017-09-27 22:15:42 +02:00
</div>
<div data-bind="foreach: filteredTasks">
2017-09-28 11:34:02 +02:00
<a href="#" data-bind="click: $parent.selectTask, event: { mouseover: onMouseOver, mouseout: onMouseOut }, css: listItemState"
2017-09-27 22:15:42 +02:00
class="list-group-item">
<div class="pull-right" style="text-align:right;">
<div data-bind="visible: actionButtonVisible()"
data-bindx="style : { visibility : actionButtonVisible() ? '' : 'hidden' }">
&nbsp;&nbsp;
<button type="button" data-bind="css: startClass, click: onStartClick, clickBubble: false"
class="btn btn-sm" style="padding-left:0px; padding-right: 12px; padding-bottom: 6px; margin-top:5px;">
<span data-bind="css: startIcon"></span>
</button>
</div>
</div>
<div class="pull-right" style="text-align:right; padding-left: 16px;">
<div data-bind="text: totalDuration, style: { fontWeight: isRunning() ? 'bold' : '' }"></div>
<div data-bind="text: age, style: { fontWeight: isRunning() ? 'bold' : '' }" style="padding-top: 2px"></div>
</div>
<div style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
<h4 class="list-group-item-heading">
<span data-bind="text: description, style: { fontWeight: isRunning() ? 'bold' : '' }"></span>&nbsp;
</h4>
<p class="list-group-item-text">
2017-10-02 19:07:41 +02:00
<span class="link" data-bind="text: clientName, click: $parent.viewClient, clickBubble: false, css: clientClass"></span>
2017-09-27 22:15:42 +02:00
<span data-bind="visible: clientName &amp;&amp; projectName"> | </span>
2017-10-02 19:07:41 +02:00
<span class="link" data-bind="text: projectName, click: $parent.viewProject, clickBubble: false, css: projectClass"></span>
2017-09-27 22:15:42 +02:00
&nbsp;
</p>
</div>
</a>
</div>
2017-09-24 14:42:24 +02:00
</div>
</div>
</div>
2017-09-24 22:25:56 +02:00
<!--
2017-09-24 21:44:20 +02:00
<footer class="footer">
<div style="padding-left: 16px; padding-top: 16px;">
<div data-bind="text: statistics"></div>
</div>
</footer>
2017-09-24 22:25:56 +02:00
-->
2017-09-24 21:44:20 +02:00
2017-09-24 14:42:24 +02:00
@include('tasks.time_tracker_knockout')
<script type="text/javascript">
var tasks = {!! $tasks !!};
var clients = {!! $clients !!};
var projects = {!! $projects !!};
var timezone = '{{ $account->getTimezone() }}';
var clientMap = {};
var projectMap = {};
var projectsForClientMap = {};
2017-09-25 12:53:50 +02:00
function refreshClientList() {
var $clientSelect = $('select#client_id');
$clientSelect.combobox({highlighter: comboboxHighlighter}).find('option').remove().end().combobox('refresh');
2017-09-25 12:53:50 +02:00
$clientSelect.append(new Option('', ''));
2019-01-30 12:00:26 +01:00
@if (Auth::user()->can('createEntity', ENTITY_CLIENT))
2017-09-25 16:26:22 +02:00
//$clientSelect.append(new Option("{{ trans('texts.create_client')}}: $name", '-1'));
2017-09-25 12:53:50 +02:00
@endif
for (var i=0; i<clients.length; i++) {
var client = clients[i];
var clientName = getClientDisplayName(client);
if (!clientName) {
continue;
}
$clientSelect.append(new Option(clientName, client.public_id));
}
$('select#client_id').combobox('refresh');
}
2017-09-24 14:42:24 +02:00
function refreshProjectList(forceClear) {
var clientId = $('input[name=client_id]').val();
$projectCombobox = $('select#project_id');
$projectCombobox.find('option').remove().end().combobox('refresh');
$projectCombobox.append(new Option('', ''));
2017-09-25 12:53:50 +02:00
2019-01-30 12:00:26 +01:00
@if (Auth::user()->can('createEntity', ENTITY_PROJECT))
2017-09-24 14:42:24 +02:00
if (clientId) {
$projectCombobox.append(new Option("{{ trans('texts.create_project')}}: $name", '-1'));
}
@endif
2017-09-25 12:53:50 +02:00
if (clientId && ! forceClear) {
var list = projectsForClientMap.hasOwnProperty(clientId) ? projectsForClientMap[clientId] : [];
} else {
var list = projects;
}
2017-09-24 14:42:24 +02:00
for (var i=0; i<list.length; i++) {
var project = list[i];
$projectCombobox.append(new Option(project.name, project.public_id));
}
2017-09-25 12:53:50 +02:00
2017-09-24 14:42:24 +02:00
$('select#project_id').combobox('refresh');
}
2017-09-25 12:53:50 +02:00
function addClientToMaps(client) {
clientMap[client.public_id] = client;
}
2017-09-24 16:04:32 +02:00
function addProjectToMaps(project) {
var client = project.client;
projectMap[project.public_id] = project;
if (!projectsForClientMap.hasOwnProperty(client.public_id)) {
projectsForClientMap[client.public_id] = [];
}
projectsForClientMap[client.public_id].push(project);
}
2017-09-26 09:12:03 +02:00
function sendKeepAlive() {
setTimeout(function() {
$.get('{{ URL::to('/keep_alive') }}', function (response) {
if (response == '{{ RESULT_SUCCESS }}') {
sendKeepAlive()
} else {
location.reload();
}
}).fail(function() {
location.reload();
});
}, 1000 * 60 * 15);
}
2017-09-24 14:42:24 +02:00
$(function() {
// setup clients and project comboboxes
for (var i=0; i<projects.length; i++) {
2017-09-25 12:53:50 +02:00
addProjectToMaps(projects[i])
2017-09-24 14:42:24 +02:00
}
for (var i=0; i<clients.length; i++) {
2017-09-25 12:53:50 +02:00
addClientToMaps(clients[i]);
2017-09-24 14:42:24 +02:00
}
2017-09-25 12:53:50 +02:00
var $clientSelect = $('select#client_id');
2017-09-24 14:42:24 +02:00
$clientSelect.on('change', function(e) {
var clientId = $('input[name=client_id]').val();
var projectId = $('input[name=project_id]').val();
var client = clientMap[clientId];
var project = projectMap[projectId];
if (!clientId && (window.model && !model.selectedTask().client())) {
e.preventDefault();return;
}
if (window.model && model.selectedTask()) {
2017-09-25 16:26:22 +02:00
var clientModel = new ClientModel(client);
if (clientId == -1) {
clientModel.name($('#client_name').val());
}
model.selectedTask().client(clientModel);
2017-09-24 14:42:24 +02:00
model.selectedTask().client_id(clientId);
model.selectedTask().project_id(0);
model.selectedTask().project(false);
}
refreshProjectList();
});
var $projectSelect = $('select#project_id').on('change', function(e) {
$clientCombobox = $('select#client_id');
var projectId = $('input[name=project_id]').val();
if (projectId == '-1') {
$('input[name=project_name]').val(projectName);
//var project = new ProjectModel();
2017-09-27 22:15:42 +02:00
//project.name = projectName;
2017-09-24 14:42:24 +02:00
//model.selectedTask().project = project;
//model.selectedTask().project_id(projectId);
} else if (projectId) {
var project = projectMap[projectId];
model.selectedTask().project(new ProjectModel(project));
model.selectedTask().project_id(projectId);
// when selecting a project make sure the client is loaded
if (project && project.client) {
var client = clientMap[project.client.public_id];
if (client) {
project.client = client;
model.selectedTask().client(new ClientModel(client));
model.selectedTask().client_id(client.public_id);
}
}
} else {
$clientSelect.trigger('change');
}
});
2017-09-25 15:46:02 +02:00
$projectSelect.on('change', function(e) {
var projectId = $('input[name=project_id]').val();
if (window.model && model.selectedTask() && projectId == -1) {
var project = new ProjectModel();
project.name($('#project_name').val());
model.selectedTask().project_id(-1);
model.selectedTask().project(project);
}
refreshProjectList();
});
2017-09-24 16:04:32 +02:00
Mousetrap.bind('/', function(e) {
event.preventDefault();
$('#search').focus();
});
2017-09-24 14:42:24 +02:00
@include('partials/entity_combobox', ['entityType' => ENTITY_PROJECT])
2017-09-25 12:53:50 +02:00
refreshClientList();
2017-09-24 14:42:24 +02:00
$clientSelect.trigger('change');
window.model = new ViewModel();
2017-09-27 14:26:55 +02:00
var taskModels = [];
2017-09-24 14:42:24 +02:00
for (var i=0; i<tasks.length; i++) {
var task = tasks[i];
var taskModel = new TaskModel(task);
2017-09-27 14:26:55 +02:00
taskModels.push(taskModel);
2017-09-24 14:42:24 +02:00
}
2017-09-27 14:26:55 +02:00
ko.utils.arrayPushAll(model.tasks, taskModels);
2017-09-24 14:42:24 +02:00
ko.applyBindings(model);
2017-09-26 09:19:33 +02:00
model.refreshTitle();
2017-09-24 14:42:24 +02:00
model.tock();
2017-09-25 12:03:19 +02:00
if (isStorageSupported()) {
2017-09-28 11:01:27 +02:00
var taskId = localStorage.getItem('last:time_tracker:task_id');
2017-09-25 12:03:19 +02:00
var task = model.taskById(taskId);
if (task) {
setTimeout(function() {
model.selectTask(task);
}, 1);
}
}
2017-09-27 14:26:55 +02:00
$('#taskList, .navbar-right').show();
2017-09-24 14:42:24 +02:00
$('.archive-dropdown:not(.dropdown-toggle)').click(function() {
model.onArchiveClick();
});
2017-09-24 21:44:20 +02:00
2017-09-25 10:52:57 +02:00
toastr.options.timeOut = 3000;
toastr.options.positionClass = 'toast-bottom-right';
2017-10-01 21:16:38 +02:00
if (navigator.userAgent != '{{ TIME_TRACKER_USER_AGENT }}') {
var link = '{{ config('ninja.time_tracker_web_url') }}';
var message = "{{ trans('texts.download_desktop_app') }}";
2017-09-26 10:22:29 +02:00
if (isMobile) {
2017-09-26 10:44:05 +02:00
toastr.warning("{{ trans('texts.time_tracker_mobile_help')}}", false, {
2017-09-28 15:19:22 +02:00
timeOut: 5000,
2017-09-26 10:54:56 +02:00
closeButton: true,
2017-09-26 10:44:05 +02:00
});
2017-09-26 10:22:29 +02:00
if (isIPhone) {
link = '{{ NINJA_IOS_APP_URL }}';
message = "{{ trans('texts.download_iphone_app') }}";
} else if (isAndroid) {
link = '{{ NINJA_ANDROID_APP_URL }}';
message = "{{ trans('texts.download_android_app') }}";
}
}
2017-09-28 15:19:22 +02:00
if (link) {
var options = {
timeOut: 5000,
closeButton: true,
onclick: function() {
window.open(link, '_blank');
}
};
toastr.info(message, false, options);
}
2017-09-26 08:54:36 +02:00
}
2017-09-26 11:46:23 +02:00
if (model.isDesktop()) {
sendKeepAlive();
}
2017-09-26 09:12:03 +02:00
2017-09-26 10:15:03 +02:00
function setButtonSize() {
if ($(window).width() > 350) {
2017-09-26 09:58:34 +02:00
$('#buttons .btn').addClass('btn-lg');
2017-09-26 10:15:03 +02:00
} else {
2017-09-26 09:58:34 +02:00
$('#buttons .btn').removeClass('btn-lg');
}
2017-09-26 10:15:03 +02:00
}
2017-10-02 11:57:38 +02:00
function setPanelHeights() {
2017-10-02 20:37:39 +02:00
if (isMobile) {
return;
}
2017-10-02 11:57:38 +02:00
var height = $(window).height() - $('.navbar').height() - 2;
$('#taskList').height(height);
2017-10-02 20:03:12 +02:00
$('#taskForm').height(height);
2017-10-02 11:57:38 +02:00
}
2017-09-26 10:15:03 +02:00
$(window).on('resize', function() {
setButtonSize();
2017-10-02 11:57:38 +02:00
setPanelHeights();
2017-09-26 10:15:03 +02:00
});
setButtonSize();
2017-10-02 11:57:38 +02:00
setPanelHeights();
2017-09-26 09:58:34 +02:00
2017-09-24 22:48:32 +02:00
$(window).on('beforeunload', function () {
2017-09-26 11:46:23 +02:00
if (model.isDesktop()) {
2017-09-26 08:43:19 +02:00
return undefined;
}
2017-10-02 17:21:11 +02:00
if (model.selectedTask() && model.isChanged()) {
2017-09-26 08:43:19 +02:00
return "{{ trans('texts.save_or_discard') }}";
2017-09-24 22:48:32 +02:00
} else {
return undefined;
}
});
2017-09-25 08:53:20 +02:00
2017-09-24 14:42:24 +02:00
});
</script>
@stop