2016-09-21 19:39:56 +02:00
|
|
|
/**
|
2016-09-23 14:53:03 +02:00
|
|
|
* Open an item such as tasks/shots in the #item-details div
|
2016-09-21 19:39:56 +02:00
|
|
|
*/
|
2016-10-05 10:30:10 +02:00
|
|
|
function item_open(item_id, item_type, pushState, project_url)
|
2016-09-23 14:53:03 +02:00
|
|
|
{
|
|
|
|
if (item_id === undefined || item_type === undefined) {
|
|
|
|
throw new ReferenceError("item_open(" + item_id + ", " + item_type + ") called.");
|
2016-09-21 19:39:56 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 10:28:47 +02:00
|
|
|
if (typeof project_url === 'undefined') {
|
2016-10-05 10:30:10 +02:00
|
|
|
project_url = ProjectUtils.projectUrl();
|
|
|
|
if (typeof project_url === 'undefined') {
|
|
|
|
throw new ReferenceError("ProjectUtils.projectUrl() undefined");
|
|
|
|
}
|
2016-09-23 10:28:47 +02:00
|
|
|
}
|
|
|
|
|
2016-11-09 14:57:46 +01:00
|
|
|
// Special case to highlight the shot row when opening task in shot or asset context
|
|
|
|
var pu_ctx = ProjectUtils.context();
|
|
|
|
var pc_ctx_shot_asset = (pu_ctx == 'shot' || pu_ctx == 'asset');
|
2016-11-04 13:02:43 +01:00
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
var item_url = '/attract/' + project_url + '/' + item_type + 's/' + item_id;
|
|
|
|
var push_url = item_url;
|
2016-11-09 14:57:46 +01:00
|
|
|
if (pc_ctx_shot_asset && item_type == 'task'){
|
|
|
|
push_url = '/attract/' + project_url + '/' + pu_ctx + 's/with-task/' + item_id;
|
2016-09-23 14:53:03 +02:00
|
|
|
}
|
2016-11-09 14:57:46 +01:00
|
|
|
item_url += '?context=' + pu_ctx;
|
2016-09-21 19:39:56 +02:00
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
$.get(item_url, function(item_data) {
|
|
|
|
$('#item-details').html(item_data);
|
2017-02-14 15:33:44 +01:00
|
|
|
$('#col_right .col_header span.header_text').text(item_type + ' details');
|
|
|
|
|
2016-09-21 19:39:56 +02:00
|
|
|
}).fail(function(xhr) {
|
|
|
|
if (console) {
|
2016-09-23 14:53:03 +02:00
|
|
|
console.log('Error fetching task', item_id, 'from', item_url);
|
2016-09-21 19:39:56 +02:00
|
|
|
console.log('XHR:', xhr);
|
|
|
|
}
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2017-06-14 18:23:16 +02:00
|
|
|
toastr.error('Failed to open ' + item_type);
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2016-10-04 14:24:27 +02:00
|
|
|
if (xhr.status) {
|
|
|
|
$('#item-details').html(xhr.responseText);
|
|
|
|
} else {
|
|
|
|
$('#item-details').html('<p class="text-danger">Opening ' + item_type + ' failed. There possibly was ' +
|
|
|
|
'an error connecting to the server. Please check your network connection and ' +
|
|
|
|
'try again.</p>');
|
|
|
|
}
|
2016-09-21 19:39:56 +02:00
|
|
|
});
|
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
// Determine whether we should push the new state or not.
|
|
|
|
pushState = (typeof pushState !== 'undefined') ? pushState : true;
|
|
|
|
if (!pushState) return;
|
2016-09-22 15:29:18 +02:00
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
// Push the correct URL onto the history.
|
|
|
|
var push_state = {itemId: item_id, itemType: item_type};
|
2016-09-23 10:28:47 +02:00
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
window.history.pushState(
|
|
|
|
push_state,
|
|
|
|
item_type + ': ' + item_id,
|
|
|
|
push_url
|
|
|
|
);
|
|
|
|
}
|
2016-09-22 17:22:43 +02:00
|
|
|
|
2016-10-05 10:30:10 +02:00
|
|
|
// Fine if project_url is undefined, but that requires ProjectUtils.projectUrl().
|
|
|
|
function task_open(task_id, project_url)
|
2016-09-23 14:53:03 +02:00
|
|
|
{
|
2016-10-05 10:30:10 +02:00
|
|
|
item_open(task_id, 'task', true, project_url);
|
2016-09-23 14:53:03 +02:00
|
|
|
}
|
2016-09-22 15:29:18 +02:00
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
function shot_open(shot_id)
|
|
|
|
{
|
|
|
|
item_open(shot_id, 'shot');
|
|
|
|
}
|
2016-09-22 15:29:18 +02:00
|
|
|
|
2016-11-09 14:57:46 +01:00
|
|
|
function asset_open(asset_id)
|
|
|
|
{
|
|
|
|
item_open(asset_id, 'asset');
|
|
|
|
}
|
|
|
|
|
2016-09-23 14:53:03 +02:00
|
|
|
window.onpopstate = function(event)
|
|
|
|
{
|
|
|
|
var state = event.state;
|
2018-12-12 11:45:47 +01:00
|
|
|
if(!state) return;
|
2016-09-23 14:53:03 +02:00
|
|
|
item_open(state.itemId, state.itemType, false);
|
2016-09-22 15:29:18 +02:00
|
|
|
}
|
|
|
|
|
2016-09-23 19:38:57 +02:00
|
|
|
/**
|
2016-11-09 14:57:46 +01:00
|
|
|
* Create a asset and show it in the #item-details div.
|
2016-09-23 19:38:57 +02:00
|
|
|
*/
|
2016-11-09 14:57:46 +01:00
|
|
|
function asset_create(project_url)
|
2016-09-23 19:38:57 +02:00
|
|
|
{
|
|
|
|
if (project_url === undefined) {
|
2016-11-09 14:57:46 +01:00
|
|
|
throw new ReferenceError("asset_create(" + project_url+ ") called.");
|
2016-09-23 19:38:57 +02:00
|
|
|
}
|
2016-11-09 14:57:46 +01:00
|
|
|
var url = '/attract/' + project_url + '/assets/create';
|
2016-09-23 19:38:57 +02:00
|
|
|
|
|
|
|
data = {
|
|
|
|
project_url: project_url
|
|
|
|
};
|
|
|
|
|
2016-11-09 14:57:46 +01:00
|
|
|
$.post(url, data, function(asset_data) {
|
2019-02-12 09:08:37 +01:00
|
|
|
/* window.location.href = asset_data.asset_id; */
|
|
|
|
pillar.events.Nodes.triggerCreated(asset_data);
|
|
|
|
asset_open(asset_data._id);
|
2016-09-23 19:38:57 +02:00
|
|
|
})
|
|
|
|
.fail(function(xhr) {
|
|
|
|
if (console) {
|
2016-11-09 14:57:46 +01:00
|
|
|
console.log('Error creating asset');
|
2016-09-23 19:38:57 +02:00
|
|
|
console.log('XHR:', xhr);
|
|
|
|
}
|
|
|
|
$('#item-details').html(xhr.responseText);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-29 15:36:02 +02:00
|
|
|
|
2016-09-21 19:39:56 +02:00
|
|
|
/**
|
2016-09-23 14:53:03 +02:00
|
|
|
* Create a task and show it in the #item-details div.
|
2016-10-04 15:21:59 +02:00
|
|
|
*
|
|
|
|
* 'shot_id' may be undefined, in which case the task will not
|
|
|
|
* be attached to a shot.
|
2016-09-21 19:39:56 +02:00
|
|
|
*/
|
2016-10-04 14:37:39 +02:00
|
|
|
function task_create(shot_id, task_type)
|
2016-09-23 14:53:03 +02:00
|
|
|
{
|
2016-10-04 15:21:59 +02:00
|
|
|
if (task_type === undefined) {
|
2016-10-04 14:37:39 +02:00
|
|
|
throw new ReferenceError("task_create(" + shot_id + ", " + task_type + ") called.");
|
2016-09-22 09:27:28 +02:00
|
|
|
}
|
2016-09-29 15:36:02 +02:00
|
|
|
|
2016-10-04 14:37:39 +02:00
|
|
|
var project_url = ProjectUtils.projectUrl();
|
2016-09-22 10:34:51 +02:00
|
|
|
var url = '/attract/' + project_url + '/tasks/create';
|
2016-10-04 15:21:59 +02:00
|
|
|
var has_shot_id = typeof shot_id !== 'undefined';
|
2016-09-21 19:39:56 +02:00
|
|
|
|
2016-09-22 10:34:51 +02:00
|
|
|
data = {
|
|
|
|
task_type: task_type,
|
|
|
|
};
|
2016-10-04 15:21:59 +02:00
|
|
|
if (has_shot_id) data.parent = shot_id;
|
|
|
|
|
2016-09-22 10:34:51 +02:00
|
|
|
$.post(url, data, function(task_data) {
|
2016-10-04 15:35:42 +02:00
|
|
|
if (console) console.log('Task created:', task_data);
|
2019-02-12 09:08:37 +01:00
|
|
|
pillar.events.Nodes.triggerCreated(task_data);
|
|
|
|
task_open(task_data._id);
|
2016-09-21 19:39:56 +02:00
|
|
|
})
|
|
|
|
.fail(function(xhr) {
|
|
|
|
if (console) {
|
|
|
|
console.log('Error creating task');
|
|
|
|
console.log('XHR:', xhr);
|
|
|
|
}
|
2016-09-23 14:53:03 +02:00
|
|
|
$('#item-details').html(xhr.responseText);
|
2016-09-29 15:36:02 +02:00
|
|
|
})
|
|
|
|
.done(function(){
|
|
|
|
$('#item-details input[name="name"]').focus();
|
2016-09-21 19:39:56 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-29 16:52:41 +02:00
|
|
|
function attract_form_save(form_id, item_id, item_save_url, options)
|
2016-09-22 15:29:18 +02:00
|
|
|
{
|
2016-09-23 09:36:06 +02:00
|
|
|
// Mandatory option.
|
2016-09-29 16:52:41 +02:00
|
|
|
if (typeof options === 'undefined' || typeof options.type === 'undefined') {
|
2016-09-23 11:50:02 +02:00
|
|
|
throw new ReferenceError('attract_form_save(): options.type is mandatory.');
|
2016-09-23 09:36:06 +02:00
|
|
|
}
|
|
|
|
|
2016-09-22 15:29:18 +02:00
|
|
|
var $form = $('#' + form_id);
|
2016-09-08 11:24:58 +02:00
|
|
|
var $button = $form.find("button[type='submit']");
|
2016-09-22 15:29:18 +02:00
|
|
|
|
2016-09-08 11:24:58 +02:00
|
|
|
var payload = $form.serialize();
|
2016-09-22 15:29:18 +02:00
|
|
|
var $item = $('#' + item_id);
|
2016-09-08 11:24:58 +02:00
|
|
|
|
|
|
|
$button.attr('disabled', true);
|
|
|
|
|
|
|
|
if (console) console.log('Sending:', payload);
|
2016-09-21 14:02:05 +02:00
|
|
|
|
2016-09-22 15:29:18 +02:00
|
|
|
$.post(item_save_url, payload)
|
|
|
|
.done(function(saved_item) {
|
|
|
|
if (console) console.log('Done saving', saved_item);
|
2019-02-12 09:08:37 +01:00
|
|
|
toastr.success('Saved ' + options.type + '. ' + saved_item._updated);
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2019-02-12 09:08:37 +01:00
|
|
|
pillar.events.Nodes.triggerUpdated(saved_item);
|
2016-09-22 18:28:11 +02:00
|
|
|
$form.find("input[name='_etag']").val(saved_item._etag);
|
2016-09-21 14:02:05 +02:00
|
|
|
|
2016-09-22 15:29:18 +02:00
|
|
|
if (options.done) options.done($item, saved_item);
|
2016-09-08 11:24:58 +02:00
|
|
|
})
|
|
|
|
.fail(function(xhr_or_response_data) {
|
|
|
|
// jQuery sends the response data (if JSON), or an XHR object (if not JSON).
|
2016-09-23 09:36:06 +02:00
|
|
|
if (console) console.log('Failed saving', options.type, xhr_or_response_data);
|
2016-09-22 18:28:11 +02:00
|
|
|
|
2018-09-06 16:56:05 +02:00
|
|
|
$button.removeClass('btn-outline-success').addClass('btn-danger');
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2019-02-12 09:08:37 +01:00
|
|
|
toastr.error('Failed saving. ' + xhr_or_response_data.status);
|
2016-09-22 15:29:18 +02:00
|
|
|
|
|
|
|
if (options.fail) options.fail($item, xhr_or_response_data);
|
2016-09-08 11:24:58 +02:00
|
|
|
})
|
|
|
|
.always(function() {
|
|
|
|
$button.attr('disabled', false);
|
2016-09-22 15:29:18 +02:00
|
|
|
|
|
|
|
if (options.always) options.always($item);
|
2016-09-08 11:24:58 +02:00
|
|
|
})
|
2016-09-21 14:02:05 +02:00
|
|
|
;
|
2016-09-08 11:24:58 +02:00
|
|
|
|
|
|
|
return false; // prevent synchronous POST to current page.
|
|
|
|
}
|
2016-09-22 15:29:18 +02:00
|
|
|
|
|
|
|
function task_save(task_id, task_url) {
|
2016-11-09 17:04:13 +01:00
|
|
|
return attract_form_save('item_form', 'task-' + task_id, task_url, {
|
2016-09-22 15:29:18 +02:00
|
|
|
done: function($task, saved_task) {
|
2016-10-04 14:37:58 +02:00
|
|
|
task_open(task_id);
|
2016-09-22 15:29:18 +02:00
|
|
|
},
|
|
|
|
fail: function($item, xhr_or_response_data) {
|
2016-09-22 18:28:11 +02:00
|
|
|
if (xhr_or_response_data.status == 412) {
|
|
|
|
// TODO: implement something nice here. Just make sure we don't throw
|
|
|
|
// away the user's edits. It's up to the user to handle this.
|
|
|
|
} else {
|
2016-09-23 14:53:03 +02:00
|
|
|
$('#item-details').html(xhr_or_response_data.responseText);
|
2016-09-22 18:28:11 +02:00
|
|
|
}
|
2016-09-22 17:46:17 +02:00
|
|
|
},
|
|
|
|
type: 'task'
|
2016-09-22 15:29:18 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function shot_save(shot_id, shot_url) {
|
2016-11-09 17:04:13 +01:00
|
|
|
return attract_form_save('item_form', 'shot-' + shot_id, shot_url, {
|
2016-09-22 15:29:18 +02:00
|
|
|
done: function($shot, saved_shot) {
|
2016-10-04 14:37:58 +02:00
|
|
|
shot_open(shot_id);
|
2016-09-22 15:29:18 +02:00
|
|
|
},
|
|
|
|
fail: function($item, xhr_or_response_data) {
|
2016-09-22 18:28:11 +02:00
|
|
|
if (xhr_or_response_data.status == 412) {
|
|
|
|
// TODO: implement something nice here. Just make sure we don't throw
|
|
|
|
// away the user's edits. It's up to the user to handle this.
|
|
|
|
} else {
|
2016-09-23 14:53:03 +02:00
|
|
|
$('#item-details').html(xhr_or_response_data.responseText);
|
2016-09-22 18:28:11 +02:00
|
|
|
}
|
2016-09-22 17:46:17 +02:00
|
|
|
},
|
|
|
|
type: 'shot'
|
2016-09-22 15:29:18 +02:00
|
|
|
});
|
|
|
|
}
|
2016-09-23 10:28:47 +02:00
|
|
|
|
2016-11-09 14:57:46 +01:00
|
|
|
function asset_save(asset_id, asset_url) {
|
2016-11-09 17:04:13 +01:00
|
|
|
return attract_form_save('item_form', 'asset-' + asset_id, asset_url, {
|
2016-11-09 14:57:46 +01:00
|
|
|
done: function($asset, saved_asset) {
|
|
|
|
asset_open(asset_id);
|
|
|
|
},
|
|
|
|
fail: function($item, xhr_or_response_data) {
|
|
|
|
if (xhr_or_response_data.status == 412) {
|
|
|
|
// TODO: implement something nice here. Just make sure we don't throw
|
|
|
|
// away the user's edits. It's up to the user to handle this.
|
|
|
|
} else {
|
|
|
|
$('#item-details').html(xhr_or_response_data.responseText);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
type: 'asset'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-09-23 13:58:14 +02:00
|
|
|
function task_delete(task_id, task_etag, task_delete_url) {
|
|
|
|
if (task_id === undefined || task_etag === undefined || task_delete_url === undefined) {
|
|
|
|
throw new ReferenceError("task_delete(" + task_id + ", " + task_etag + ", " + task_delete_url + ") called.");
|
|
|
|
}
|
|
|
|
$.ajax({
|
|
|
|
type: 'DELETE',
|
|
|
|
url: task_delete_url,
|
|
|
|
data: {'etag': task_etag}
|
|
|
|
})
|
|
|
|
.done(function(e) {
|
|
|
|
if (console) console.log('Task', task_id, 'was deleted.');
|
2016-09-29 15:35:31 +02:00
|
|
|
$('#item-details').fadeOutAndClear();
|
2019-02-12 09:08:37 +01:00
|
|
|
pillar.events.Nodes.triggerDeleted(task_id);
|
2016-11-02 12:13:31 +01:00
|
|
|
|
2019-02-12 09:08:37 +01:00
|
|
|
toastr.success('Task deleted');
|
2016-09-23 13:58:14 +02:00
|
|
|
})
|
|
|
|
.fail(function(xhr) {
|
2019-02-12 09:08:37 +01:00
|
|
|
toastr.error('Unable to delete task, code ' + xhr.status);
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2016-09-23 13:58:14 +02:00
|
|
|
if (xhr.status == 412) {
|
|
|
|
alert('Someone else edited this task before you deleted it; refresh to try again.');
|
|
|
|
// TODO: implement something nice here. Just make sure we don't throw
|
|
|
|
// away the user's edits. It's up to the user to handle this.
|
|
|
|
// TODO: refresh activity feed and point user to it.
|
|
|
|
} else {
|
|
|
|
// TODO: find a better place to put this error message, without overwriting the
|
|
|
|
// task the user is looking at in-place.
|
|
|
|
$('#task-view-feed').html(xhr.responseText);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-11-02 11:08:33 +01:00
|
|
|
function loadActivities(url)
|
2016-10-18 14:50:35 +02:00
|
|
|
{
|
2016-11-02 16:12:14 +01:00
|
|
|
return $.get(url)
|
2016-10-18 14:50:35 +02:00
|
|
|
.done(function(data) {
|
|
|
|
if(console) console.log('Activities loaded OK');
|
|
|
|
$('#activities').html(data);
|
|
|
|
})
|
|
|
|
.fail(function(xhr) {
|
|
|
|
if (console) {
|
|
|
|
console.log('Error fetching activities');
|
|
|
|
console.log('XHR:', xhr);
|
|
|
|
}
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2019-02-12 09:08:37 +01:00
|
|
|
toastr.error('Opening activity log failed.');
|
2016-11-01 12:44:35 +01:00
|
|
|
|
2016-10-18 14:50:35 +02:00
|
|
|
if (xhr.status) {
|
|
|
|
$('#activities').html(xhr.responseText);
|
|
|
|
} else {
|
|
|
|
$('#activities').html('<p class="text-danger">Opening activity log failed. There possibly was ' +
|
|
|
|
'an error connecting to the server. Please check your network connection and ' +
|
|
|
|
'try again.</p>');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-11-09 15:26:11 +01:00
|
|
|
var save_on_ctrl_enter = ['shot', 'asset', 'task'];
|
2016-10-20 15:33:44 +02:00
|
|
|
$(document).on('keyup', function(e){
|
2017-02-14 15:57:08 +01:00
|
|
|
if ($.inArray(save_on_ctrl_enter, ProjectUtils.context())) {
|
|
|
|
var active = document.activeElement;
|
|
|
|
|
|
|
|
// Save on Ctrl + Enter anytime except when comment field is on focus
|
|
|
|
if (active.id != 'comment_field'){
|
2016-11-03 15:07:49 +01:00
|
|
|
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey){
|
|
|
|
$("#item-save").trigger( "click" );
|
|
|
|
}
|
|
|
|
}
|
2016-10-20 15:33:44 +02:00
|
|
|
}
|
|
|
|
});
|