b1575fa321
Dialogs (with a refresh option) appear whenever the SignalR client disconnects or encounters an error. Nonsensical error messages replaced. Page refresh technique changed to allow for urls containing fragment hashes.
348 lines
20 KiB
Plaintext
348 lines
20 KiB
Plaintext
@model Disco.Web.Models.Device.ShowModel
|
|
@{
|
|
Authorization.Require(Claims.Device.ShowAttachments);
|
|
|
|
var canAddAttachments = Authorization.Has(Claims.Device.Actions.AddAttachments);
|
|
var canRemoveAnyAttachments = Authorization.Has(Claims.Device.Actions.RemoveAnyAttachments);
|
|
var canRemoveOwnAttachments = Authorization.Has(Claims.Device.Actions.RemoveOwnAttachments);
|
|
|
|
Html.BundleDeferred("~/Style/Shadowbox");
|
|
Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox");
|
|
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
|
|
|
if (canAddAttachments)
|
|
{
|
|
Html.BundleDeferred("~/ClientScripts/Modules/Disco-AttachmentUploader");
|
|
}
|
|
}
|
|
<div id="DeviceDetailTab-Resources" class="DevicePart">
|
|
<table id="deviceShowResources">
|
|
<tr>
|
|
<td id="AttachmentsContainer">
|
|
<div id="Attachments" class="@(canAddAttachments ? "canAddAttachments" : "cannotAddAttachments")">
|
|
<div class="Disco-AttachmentUpload-DropTarget">
|
|
<h2>Drop Attachments Here</h2>
|
|
</div>
|
|
<div class="attachmentOutput">
|
|
@if (Model.Device.DeviceAttachments != null)
|
|
{
|
|
foreach (var da in Model.Device.DeviceAttachments)
|
|
{
|
|
<a href="@Url.Action(MVC.API.Device.AttachmentDownload(da.Id))" data-attachmentid="@da.Id" data-mimetype="@da.MimeType">
|
|
<span class="icon" title="@da.Filename">
|
|
<img alt="Attachment Thumbnail" src="@(Url.Action(MVC.API.Device.AttachmentThumbnail(da.Id)))" /></span>
|
|
<span class="comments" title="@da.Comments">
|
|
@{if (!string.IsNullOrEmpty(da.DocumentTemplateId))
|
|
{ @da.DocumentTemplate.Description}
|
|
else
|
|
{ @da.Comments }}
|
|
</span><span class="author">@da.TechUser.ToString()</span>@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId == CurrentUser.UserId))
|
|
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" title="@da.Timestamp.ToFullDateTime()" data-livestamp="@da.Timestamp.ToUnixEpoc()">@da.Timestamp.ToFullDateTime()</span>
|
|
</a>
|
|
}
|
|
}
|
|
</div>
|
|
@if (canAddAttachments)
|
|
{
|
|
<div class="Disco-AttachmentUpload-Progress"></div>
|
|
<div class="attachmentInput clearfix">
|
|
<span class="action upload fa fa-upload disabled" title="Attach File"></span><span class="action photo fa fa-camera disabled" title="Capture Image"></span>
|
|
</div>
|
|
}
|
|
<script type="text/javascript">
|
|
Shadowbox.init({
|
|
skipSetup: true,
|
|
modal: true
|
|
});
|
|
$(function () {
|
|
var $Attachments = $('#Attachments');
|
|
var $attachmentOutput = $Attachments.find('.attachmentOutput');
|
|
var $attachmentDownloadHost;
|
|
|
|
var $dialogRemoveAttachment = null;
|
|
|
|
// Connect to Hub
|
|
var hub = $.connection.deviceUpdates;
|
|
|
|
// Map Functions
|
|
hub.client.addAttachment = onAddAttachment;
|
|
hub.client.removeAttachment = onRemoveAttachment;
|
|
|
|
$.connection.hub.qs = { DeviceSerialNumber: '@(Model.Device.SerialNumber)' };
|
|
$.connection.hub.error(onHubFailed);
|
|
$.connection.hub.disconnected(onHubFailed);
|
|
|
|
$.connection.hub.reconnecting(function () {
|
|
$('#AttachmentsContainer').find('span.action').addClass('disabled');
|
|
});
|
|
$.connection.hub.reconnected(function () {
|
|
$('#AttachmentsContainer').find('span.action').removeClass('disabled');
|
|
});
|
|
|
|
// Start Connection
|
|
$.connection.hub.start(function () {
|
|
$('#AttachmentsContainer').find('span.action').removeClass('disabled');
|
|
}).fail(onHubFailed);
|
|
|
|
function onHubFailed(error) {
|
|
// Disable UI
|
|
$('#AttachmentsContainer').find('span.action').addClass('disabled');
|
|
|
|
// Show Dialog Message
|
|
if ($('.disconnected-dialog').length == 0) {
|
|
$('<div>')
|
|
.addClass('dialog disconnected-dialog')
|
|
.html('<h3><span class="fa-stack fa-lg"><i class="fa fa-wifi fa-stack-1x"></i><i class="fa fa-ban fa-stack-2x error"></i></span>Disconnected from the Disco ICT Server</h3><div>This page is not receiving live updates. Please ensure you are connected to the server, then refresh this page to enable features.</div>')
|
|
.dialog({
|
|
resizable: false,
|
|
title: 'Disconnected',
|
|
width: 400,
|
|
modal: true,
|
|
buttons: {
|
|
'Refresh Now': function () {
|
|
$(this).dialog('option', 'buttons', null);
|
|
window.location.reload(true);
|
|
},
|
|
'Close': function () {
|
|
$(this).dialog('destroy');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function onAddAttachment(id, quick) {
|
|
var data = { id: id };
|
|
$.ajax({
|
|
url: '@Url.Action(MVC.API.Device.Attachment())',
|
|
dataType: 'json',
|
|
data: data,
|
|
success: function (d) {
|
|
if (d.Result == 'OK') {
|
|
var a = d.Attachment;
|
|
@if (canRemoveAnyAttachments)
|
|
{
|
|
<text>buildAttachment(a, true, quick);</text>
|
|
}
|
|
else if (canRemoveOwnAttachments)
|
|
{
|
|
<text>buildAttachment(a, (a.AuthorId === '@(CurrentUser.UserId)'), quick);</text>
|
|
}
|
|
else
|
|
{
|
|
<text>buildAttachment(a, false, quick);</text>
|
|
}
|
|
} else {
|
|
alert('Unable to add attachment: ' + d.Result);
|
|
}
|
|
},
|
|
error: function (jqXHR, textStatus, errorThrown) {
|
|
alert('Unable to add attachment: ' + textStatus);
|
|
}
|
|
});
|
|
}
|
|
|
|
function buildAttachment(a, canRemove, quick) {
|
|
var t = '<a><span class="icon"><img alt="Attachment Thumbnail" /></span><span class="comments"></span><span class="author"></span>';
|
|
if (canRemove)
|
|
t += '<span class="remove fa fa-times-circle"></span>';
|
|
t += '<span class="timestamp"></span></a>';
|
|
|
|
var e = $(t);
|
|
|
|
e.attr('data-attachmentid', a.Id).attr('data-mimetype', a.MimeType).attr('href', '@(Url.Action(MVC.API.Device.AttachmentDownload()))/' + a.Id);
|
|
e.find('.comments').text(a.Description);
|
|
e.find('.author').text(a.Author);
|
|
e.find('.timestamp').text(a.TimestampFull).attr('title', a.TimestampFull).livestamp(a.TimestampUnixEpoc);
|
|
if (canRemove)
|
|
e.find('.remove').click(removeAttachment);
|
|
if (!quick)
|
|
e.hide();
|
|
$attachmentOutput.append(e);
|
|
onUpdate();
|
|
if (!quick)
|
|
e.show('slow');
|
|
if (a.MimeType.toLowerCase().indexOf('image/') == 0)
|
|
e.shadowbox({ gallery: 'attachments', player: 'img', title: a.Description });
|
|
else
|
|
e.click(onDownload);
|
|
|
|
// Add Thumbnail
|
|
var buildThumbnail = function () {
|
|
var retryCount = 0;
|
|
var img = e.find('.icon img');
|
|
|
|
var setThumbnailUrl = function () {
|
|
img.attr('src', '@(Url.Action(MVC.API.Device.AttachmentThumbnail()))/' + a.Id + '?v=' + retryCount);
|
|
};
|
|
img.on('error', function () {
|
|
img.addClass('loading');
|
|
retryCount++;
|
|
if (retryCount < 6)
|
|
window.setTimeout(setThumbnailUrl, retryCount * 250);
|
|
});
|
|
img.on('load', function () {
|
|
img.removeClass('loading');
|
|
});
|
|
window.setTimeout(setThumbnailUrl, 100);
|
|
};
|
|
buildThumbnail();
|
|
}
|
|
|
|
function onRemoveAttachment(id) {
|
|
var a = $attachmentOutput.find('a[data-attachmentid=' + id + ']');
|
|
|
|
a.hide(300).delay(300).queue(function () {
|
|
var $this = $(this);
|
|
if ($this.attr('data-mimetype').toLowerCase().indexOf('image/') == 0)
|
|
Shadowbox.removeCache(this);
|
|
$this.find('.timestamp').livestamp('destroy');
|
|
$this.remove();
|
|
onUpdate();
|
|
});
|
|
}
|
|
|
|
function onDownload() {
|
|
var $this = $(this);
|
|
var url = $this.attr('href');
|
|
|
|
if ($.connection && $.connection.hub && $.connection.hub.transport &&
|
|
$.connection.hub.transport.name == 'foreverFrame') {
|
|
// SignalR active with foreverFrame transport - use popup window
|
|
window.open(url, '_blank', 'height=150,width=250,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no');
|
|
} else {
|
|
// use iFrame
|
|
if (!$attachmentDownloadHost) {
|
|
$attachmentDownloadHost = $('<iframe>')
|
|
.attr({ 'src': url, 'title': 'Attachment Download Host' })
|
|
.addClass('hidden')
|
|
.appendTo('body')
|
|
.contents();
|
|
} else {
|
|
$attachmentDownloadHost[0].location.href = url;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function onUpdate() {
|
|
var attachmentCount = $attachmentOutput.children('a').length;
|
|
var tabHeading = 'Attachments [' + attachmentCount + ']';
|
|
$('#DeviceDetailTab-ResourcesLink').text(tabHeading);
|
|
}
|
|
|
|
@if (canAddAttachments)
|
|
{<text>
|
|
//#region Add Attachments
|
|
var attachmentUploader = new document.Disco.AttachmentUploader(
|
|
'@(Url.Action(MVC.API.Device.AttachmentUpload(Model.Device.SerialNumber, null)))',
|
|
$Attachments.find('.Disco-AttachmentUpload-DropTarget'),
|
|
$Attachments.find('.Disco-AttachmentUpload-Progress'));
|
|
|
|
var $attachmentInput = $Attachments.find('.attachmentInput');
|
|
$attachmentInput.find('.photo').click(function () {
|
|
if ($(this).hasClass('disabled'))
|
|
alert('Disconnected from the Disco ICT Server, please refresh this page and try again');
|
|
else
|
|
attachmentUploader.uploadImage();
|
|
});
|
|
$attachmentInput.find('.upload').click(function () {
|
|
if ($(this).hasClass('disabled'))
|
|
alert('Disconnected from the Disco ICT Server, please refresh this page and try again');
|
|
else
|
|
attachmentUploader.uploadFiles();
|
|
});
|
|
|
|
var resourcesTab;
|
|
$(document).on('dragover', function () {
|
|
if (!resourcesTab) {
|
|
var tabs = $Attachments.closest('.ui-tabs');
|
|
resourcesTab = {
|
|
tabs: tabs,
|
|
resourcesIndex: tabs.children('ul.ui-tabs-nav').find('a[href="#DeviceDetailTab-Resources"]').closest('li').index()
|
|
};
|
|
}
|
|
var selectedIndex = resourcesTab.tabs.tabs('option', 'active');
|
|
if (resourcesTab.resourcesIndex !== selectedIndex)
|
|
resourcesTab.tabs.tabs('option', 'active', resourcesTab.resourcesIndex);
|
|
});
|
|
//#endregion
|
|
</text>}
|
|
@if (canRemoveAnyAttachments || canRemoveOwnAttachments)
|
|
{<text>
|
|
//#region Remove Attachments
|
|
$attachmentOutput.find('span.remove').click(removeAttachment);
|
|
|
|
function removeAttachment() {
|
|
$this = $(this).closest('a');
|
|
|
|
var data = { id: $this.attr('data-attachmentid') };
|
|
|
|
if (!$dialogRemoveAttachment) {
|
|
$dialogRemoveAttachment = $('#dialogRemoveAttachment').dialog({
|
|
resizable: false,
|
|
height: 140,
|
|
modal: true,
|
|
autoOpen: false
|
|
});
|
|
}
|
|
|
|
$dialogRemoveAttachment.dialog("enable");
|
|
$dialogRemoveAttachment.dialog('option', 'buttons', {
|
|
"Remove": function () {
|
|
$dialogRemoveAttachment.dialog("disable");
|
|
$dialogRemoveAttachment.dialog("option", "buttons", null);
|
|
$.ajax({
|
|
url: '@Url.Action(MVC.API.Device.AttachmentRemove())',
|
|
dataType: 'json',
|
|
data: data,
|
|
success: function (d) {
|
|
if (d == 'OK') {
|
|
// Do nothing, await SignalR notification
|
|
} else {
|
|
alert('Unable to remove attachment: ' + d);
|
|
}
|
|
$dialogRemoveAttachment.dialog("close");
|
|
},
|
|
error: function (jqXHR, textStatus, errorThrown) {
|
|
alert('Unable to remove attachment: ' + textStatus);
|
|
$dialogRemoveAttachment.dialog("close");
|
|
}
|
|
});
|
|
},
|
|
Cancel: function () {
|
|
$dialogRemoveAttachment.dialog("close");
|
|
}
|
|
});
|
|
|
|
$dialogRemoveAttachment.dialog('open');
|
|
|
|
return false;
|
|
}
|
|
//#endregion
|
|
</text>}
|
|
|
|
$attachmentOutput.children('a').each(function () {
|
|
$this = $(this);
|
|
if ($this.attr('data-mimetype').toLowerCase().indexOf('image/') == 0)
|
|
$this.shadowbox({ gallery: 'attachments', player: 'img', title: $this.find('.comments').text() });
|
|
else
|
|
$this.click(onDownload);
|
|
});
|
|
});
|
|
</script>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<div id="dialogRemoveAttachment" class="dialog" title="Remove this Attachment?">
|
|
<p>
|
|
<i class="fa fa-exclamation-triangle fa-lg"></i> Are you sure?
|
|
</p>
|
|
</div>
|
|
<script>
|
|
$('#DeviceDetailTabItems').append('<li><a href="#DeviceDetailTab-Resources" id="DeviceDetailTab-ResourcesLink">Attachments [@(Model.Device.DeviceAttachments == null ? 0 : Model.Device.DeviceAttachments.Count)]</a></li>');
|
|
</script>
|
|
</div>
|