374 lines
23 KiB
Plaintext
374 lines
23 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");
|
|
|
|
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") @(canRemoveAnyAttachments ? "canRemoveAnyAttachments" : "cannotRemoveAnyAttachments") @(canRemoveOwnAttachments ? "canRemoveOwnAttachments" : "cannotRemoveOwnAttachments")" data-id="@Model.Device.SerialNumber" data-userid="@CurrentUser.UserId" data-uploadurl="@(Url.Action(MVC.API.Device.AttachmentUpload(Model.Device.SerialNumber, null)))" data-onlineuploadurl="@(Url.Action(MVC.API.Device.AttachmentOnlineUploadSession(Model.Device.SerialNumber)))" data-qrcodeurl="@Url.Content("~/ClientSource/Scripts/Modules/qrcode.min.js")" data-removeurl="@Url.Action(MVC.API.Device.AttachmentRemove())" data-downloadallurl="@Url.Action(MVC.API.Device.AttachmentDownloadAll(Model.Device.SerialNumber))">
|
|
<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.OrderByDescending(a => a.Id))
|
|
{
|
|
<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 ?? da.Filename)">
|
|
@{if (!string.IsNullOrEmpty(da.DocumentTemplateId))
|
|
{ @da.DocumentTemplate.Description}
|
|
else
|
|
{ @(da.Comments ?? da.Filename) }}
|
|
</span><span class="author">@da.TechUser.ToString()</span>@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase)))
|
|
{<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>
|
|
<div class="Disco-AttachmentUpload-Progress"></div>
|
|
<div class="attachmentInput clearfix">
|
|
@if (canAddAttachments)
|
|
{
|
|
<span class="action enabled upload fa fa-upload disabled" title="Attach File"></span><span class="action enabled photo fa fa-camera disabled" title="Capture Image"></span><span class="action enabled online-upload fa fa-qrcode disabled" title="Upload with Online Services"></span>
|
|
}
|
|
@if (Model.Device.DeviceAttachments != null && Model.Device.DeviceAttachments.Count > 0)
|
|
{
|
|
<span class="action enabled download-all fa fa-download" title="Download All"></span>
|
|
}
|
|
</div>
|
|
<script type="text/javascript">
|
|
Shadowbox.init({
|
|
skipSetup: true,
|
|
modal: true,
|
|
onOpen: function (obj) {
|
|
if (obj.player === 'iframe' && obj.content.indexOf('inline=True') === -1) {
|
|
obj.content += (obj.content.indexOf('?') === -1 ? '?' : '&') + 'inline=True';
|
|
}
|
|
return true;
|
|
},
|
|
onChange: function (obj) {
|
|
if (obj.player === 'iframe' && obj.content.indexOf('inline=True') === -1) {
|
|
obj.content += (obj.content.indexOf('?') === -1 ? '?' : '&') + 'inline=True';
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
$(function () {
|
|
const $Attachments = $('#Attachments');
|
|
const $attachmentOutput = $Attachments.find('.attachmentOutput');
|
|
let $attachmentDownloadHost = null;
|
|
let $dialogRemoveAttachment = null;
|
|
let attachmentUploader = null;
|
|
|
|
function onAttachmentAdded(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 ($Attachments.hasClass('canRemoveAnyAttachments'))
|
|
buildAttachment(a, true, quick);
|
|
else if ($Attachments.hasClass('canRemoveOwnAttachments'))
|
|
buildAttachment(a, (a.AuthorId === $Attachments.attr('data-userid')), quick);
|
|
else
|
|
buildAttachment(a, false, quick);
|
|
|
|
if (attachmentUploader && attachmentUploader.onlineUploadCloseDialog) {
|
|
attachmentUploader.onlineUploadCloseDialog();
|
|
}
|
|
} 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.prepend(e);
|
|
onUpdate();
|
|
if (!quick)
|
|
e.show('slow');
|
|
if (a.MimeType.toLowerCase().indexOf('image/') == 0)
|
|
e.shadowbox({ gallery: 'attachments', player: 'img', title: a.Description });
|
|
else if (a.MimeType.toLowerCase().indexOf('application/pdf') == 0 && navigator.pdfViewerEnabled)
|
|
e.shadowbox({ gallery: 'attachments', player: 'iframe', 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 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({ 'id': 'AttachmentsDownloadHost', 'name': 'AttachmentsDownloadHost', 'src': url, 'title': 'Attachment Download Host' })
|
|
.addClass('hidden')
|
|
.appendTo('body')
|
|
.contents();
|
|
} else {
|
|
$attachmentDownloadHost[0].location.href = url;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function onAttachmentRemoved(id) {
|
|
var a = $attachmentOutput.find('a[data-attachmentid=' + id + ']');
|
|
|
|
a.hide(300).delay(300).queue(function () {
|
|
var $this = $(this);
|
|
if (this['shadowboxCacheKey'])
|
|
Shadowbox.removeCache(this);
|
|
$this.find('.timestamp').livestamp('destroy');
|
|
$this.remove();
|
|
onUpdate();
|
|
});
|
|
}
|
|
|
|
function onUpdate() {
|
|
var attachmentCount = $attachmentOutput.children('a').length;
|
|
var tabHeading = 'Attachments [' + attachmentCount + ']';
|
|
$('#DeviceDetailTab-ResourcesLink').text(tabHeading);
|
|
}
|
|
|
|
$Attachments
|
|
.find('.attachmentInput span.download-all')
|
|
.on('click', function (event) {
|
|
const downloadAllUrl = $Attachments.attr('data-downloadallurl');
|
|
const id = $Attachments.attr('data-id');
|
|
const $this = $(this);
|
|
|
|
if ($this.hasClass('fa-spinner'))
|
|
return;
|
|
|
|
$this
|
|
.removeClass('fa-download')
|
|
.addClass('fa-spinner fa-spin');
|
|
|
|
if (!$attachmentDownloadHost) {
|
|
$attachmentDownloadHost = $('<iframe>')
|
|
.attr({ 'id': 'AttachmentsDownloadHost', 'name': 'AttachmentsDownloadHost', 'title': 'Attachment Download Host' })
|
|
.addClass('hidden')
|
|
.appendTo('body')
|
|
.contents();
|
|
}
|
|
const $form = $('<form>')
|
|
.attr({
|
|
method: 'POST',
|
|
action: downloadAllUrl,
|
|
target: 'AttachmentsDownloadHost'
|
|
})
|
|
.append($('<input>')
|
|
.attr({ type: 'hidden', name: '__RequestVerificationToken' })
|
|
.val(document.body.dataset.antiforgery))
|
|
.append($('<input>')
|
|
.attr({ type: 'hidden', name: 'id' })
|
|
.val(id))
|
|
.appendTo(document.body)
|
|
.trigger('submit');
|
|
|
|
window.setTimeout(function () {
|
|
$this
|
|
.removeClass('fa-spinner fa-spin')
|
|
.addClass('fa-download');
|
|
$form.remove();
|
|
}, 2000);
|
|
});
|
|
|
|
document.DiscoFunctions.onAttachmentAdded = onAttachmentAdded;
|
|
document.DiscoFunctions.onAttachmentRemoved = onAttachmentRemoved;
|
|
|
|
@if (canAddAttachments)
|
|
{<text>
|
|
//#region Add Attachments
|
|
attachmentUploader = new document.Disco.AttachmentUploader($Attachments);
|
|
|
|
var $attachmentInput = $Attachments.find('.attachmentInput');
|
|
$attachmentInput.find('.online-upload').on('click', function () {
|
|
if ($(this).hasClass('disabled'))
|
|
alert('Disconnected from the Disco ICT Server, please refresh this page and try again');
|
|
else
|
|
attachmentUploader.onlineUpload();
|
|
});
|
|
if (window.location.protocol != 'https:') {
|
|
$attachmentInput.find('.photo')
|
|
.removeClass('enabled')
|
|
.addClass('disabled')
|
|
.attr('title', 'Capture Image: this functionality is only available over a HTTPS connection');
|
|
}
|
|
$attachmentInput.find('.photo').click(function () {
|
|
if (!$(this).hasClass('enabled'))
|
|
alert('This functionality is only available over a HTTPS connection');
|
|
else 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');
|
|
|
|
if (!$dialogRemoveAttachment) {
|
|
$dialogRemoveAttachment = $('#dialogRemoveAttachment').dialog({
|
|
resizable: false,
|
|
height: 140,
|
|
modal: true,
|
|
autoOpen: false
|
|
});
|
|
}
|
|
|
|
async function removeAttachmentAsync(id) {
|
|
const body = new FormData();
|
|
body.append('__RequestVerificationToken', document.body.dataset.antiforgery);
|
|
body.append('id', id);
|
|
|
|
try {
|
|
const response = await fetch($Attachments.attr('data-removeurl'), {
|
|
body: body,
|
|
method: 'POST'
|
|
});
|
|
if (!response.ok) {
|
|
alert('Unable to remove attachment: ' + response.statusText);
|
|
}
|
|
$dialogRemoveAttachment.dialog("close");
|
|
} catch (e) {
|
|
alert('Unable to remove attachment: ' + e);
|
|
$dialogRemoveAttachment.dialog("close");
|
|
}
|
|
}
|
|
|
|
const attachmentId = $this.attr('data-attachmentid');
|
|
$dialogRemoveAttachment.dialog('option', 'buttons', {
|
|
"Remove": function () {
|
|
$dialogRemoveAttachment.dialog("option", "buttons", null);
|
|
removeAttachmentAsync(attachmentId);
|
|
},
|
|
Cancel: function () {
|
|
$dialogRemoveAttachment.dialog("close");
|
|
}
|
|
}).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 if ($this.attr('data-mimetype').toLowerCase().indexOf('application/pdf') == 0 && navigator.pdfViewerEnabled)
|
|
$this.shadowbox({ gallery: 'attachments', player: 'iframe', 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>
|