Merge pull request #2910 from aignatov-bio/ai-sci-5103-update-file-preview

Update file preview [SCI-5103][SCI-5104]
This commit is contained in:
aignatov-bio 2020-10-29 15:35:12 +01:00 committed by GitHub
commit 7a6e2386f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 827 additions and 820 deletions

View file

@ -186,7 +186,6 @@ var MyModuleRepositories = (function() {
drawCallback: function() {
FULL_VIEW_TABLE.columns.adjust();
FilePreviewModal.init();
renderFullViewRepositoryName(
tableContainer.attr('data-repository-name'),
tableContainer.attr('data-repository-snapshot-created'),

View file

@ -118,7 +118,6 @@
ResultAssets.applyEditResultAssetCallback();
applyCreateWopiFileCallback();
toggleResultEditButtons(true);
FilePreviewModal.init();
Comments.init();
ResultAssets.initNewResultAsset();
expandResult($(this));

View file

@ -220,7 +220,6 @@ function initProtocolPreviewModal() {
modal.modal("show");
ProtocolRepositoryHeader.init();
initHandsOnTable(modalBody);
FilePreviewModal.init({ readOnly: true });
},
error: function (error) {
// TODO

View file

@ -79,7 +79,6 @@
setTimeout(function() {
initStepsComments();
FilePreviewModal.init();
SmartAnnotation.preventPropagation('.atwho-user-popover');
TinyMCE.destroyAll();
DragNDropSteps.clearFiles();
@ -107,7 +106,6 @@
toggleButtons(false);
initializeCheckboxSorting();
animateSpinner(null, false);
FilePreviewModal.init();
DragNDropSteps.clearFiles();
if (tinyMCE.editors.step_description_textarea) tinyMCE.editors.step_description_textarea.remove();
TinyMCE.init('#step_description_textarea');
@ -183,8 +181,6 @@
initCallBacks();
initHandsOnTable($new_step);
toggleButtons(true);
FilePreviewModal.init();
TinyMCE.destroyAll();
SmartAnnotation.preventPropagation('.atwho-user-popover');
// Show the edited step
@ -345,6 +341,7 @@
$(`.asset[data-asset-id=${assetId}]`).replaceWith(data.html);
FilePreviewModal.init();
$(`.asset[data-asset-id=${assetId}]`).closest('.attachments').trigger('reorder');
},
error: function (data) {
console.log(data);
@ -592,7 +589,6 @@
});
animateSpinner(null, false);
DragNDropSteps.clearFiles();
FilePreviewModal.init();
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
},
error: function(xhr) {
@ -697,7 +693,6 @@
initCallBacks();
initHandsOnTable($(document));
expandAllSteps();
FilePreviewModal.init();
TinyMCE.highlight();
SmartAnnotation.preventPropagation('.atwho-user-popover');
newStepHandler();

View file

@ -118,7 +118,6 @@ var RepositoryDatatable = (function(global) {
currentMode = 'viewMode';
// Table specific stuff
TABLE.button(0).enable(true);
FilePreviewModal.init();
$(TABLE_WRAPPER_ID).find('tr').removeClass('blocked');
updateButtons();
disableCheckboxToggleOnCheckboxPreview();
@ -362,12 +361,6 @@ var RepositoryDatatable = (function(global) {
});
}
function disableCheckboxToggleOnAssetDownload() {
$('.file-preview-link').on('click', function(ev) {
ev.stopPropagation();
});
}
// Adjust columns width in table header
function adjustTableHeader() {
TABLE.columns.adjust();
@ -502,7 +495,6 @@ var RepositoryDatatable = (function(global) {
animateSpinner(this, false);
changeToViewMode();
updateDataTableSelectAllCtrl();
FilePreviewModal.init();
// Prevent row toggling when selecting user smart annotation link
SmartAnnotation.preventPropagation('.atwho-user-popover');
@ -548,8 +540,6 @@ var RepositoryDatatable = (function(global) {
});
},
fnInitComplete: function() {
disableCheckboxToggleOnAssetDownload();
FilePreviewModal.init();
initHeaderTooltip();
disableCheckboxToggleOnCheckboxPreview();

View file

@ -50,7 +50,6 @@
$form.remove();
applyEditResultAssetCallback();
Results.toggleResultEditButtons(true);
FilePreviewModal.init();
});
Results.toggleResultEditButtons(false);
@ -71,7 +70,6 @@
Results.toggleResultEditButtons(true);
Results.expandResult($newResult);
FilePreviewModal.init();
Comments.init();
initNewResultAsset();
}).on('ajax:error', function(e, xhr) {
@ -97,5 +95,4 @@
ResultAssets.initNewResultAsset();
ResultAssets.applyEditResultAssetCallback();
FilePreviewModal.init();
}(window));

View file

@ -435,7 +435,6 @@
initFormSubmitLinks($(this));
ResultAssets.applyEditResultAssetCallback();
Results.toggleResultEditButtons(true);
FilePreviewModal.init();
Comments.init();
ResultAssets.initNewResultAsset();
Results.expandResult($(this));

View file

@ -1,551 +1,36 @@
/* eslint no-underscore-dangle: ["error", { "allowAfterThis": true }]*/
/* eslint no-use-before-define: ["error", { "functions": false }]*/
/* eslint-disable no-underscore-dangle */
/* global Uint8Array fabric tui animateSpinner Assets ActiveStoragePreviews
PerfectScrollbar MarvinJsEditor refreshProtocolStatusBar */
var FilePreviewModal = (function() {
'use strict';
var readOnly = false;
function initPreviewModal(options = {}) {
var name;
var url;
var downloadUrl;
readOnly = options.readOnly;
$('.file-preview-link').off('click');
$('.file-preview-link').click(function(e) {
if ($(e.target.offsetParent).hasClass('change-preview-type')) return;
e.preventDefault();
name = $(this).find('.attachment-label').text();
url = $(this).data('preview-url');
downloadUrl = $(this).attr('href');
openPreviewModal(name, url, downloadUrl);
return true;
});
$('#filePreviewModal').find('.preview-close').click(function() {
$('#filePreviewModal').find('.file-preview-container').html('');
$('#filePreviewModal').modal('hide');
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
});
}
// Adding rotation icon
function updateFabricControls() {
fabric.Object.prototype.drawBorders = function(ctx, styleOverride = {}) {
var wh = this._calculateCurrentDimensions();
var strokeWidth = 1 / this.borderScaleFactor;
var width = wh.x + strokeWidth;
var height = wh.y + strokeWidth;
var drawRotatingPoint = typeof styleOverride.hasRotatingPoint !== 'undefined'
? styleOverride.hasRotatingPoint : this.hasRotatingPoint;
var hasControls = typeof styleOverride.hasControls !== 'undefined'
? styleOverride.hasControls : this.hasControls;
var rotatingPointOffset = typeof styleOverride.rotatingPointOffset !== 'undefined'
? styleOverride.rotatingPointOffset : this.rotatingPointOffset;
var rotateHeight = -height / 2;
ctx.save();
ctx.strokeStyle = styleOverride.borderColor || this.borderColor;
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray, null);
ctx.strokeRect(
-width / 2,
-height / 2,
width,
height
);
if (drawRotatingPoint && this.isControlVisible('mtr') && hasControls) {
ctx.beginPath();
ctx.moveTo(0, rotateHeight);
ctx.lineTo(0, rotateHeight - rotatingPointOffset + 10);
ctx.stroke();
}
ctx.restore();
return this;
};
fabric.Object.prototype.drawControls = function(ctx) {
var rotationImage = 'data:image/png;base64,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';
var rotate = new Image();
var rotateLeft;
var rotateTop;
var wh = this._calculateCurrentDimensions();
var width = wh.x;
var height = wh.y;
var scaleOffset = this.cornerSize;
var left = -(width + scaleOffset) / 2;
var top = -(height + scaleOffset) / 2;
var methodName = this.transparentCorners ? 'stroke' : 'fill';
if (!this.hasControls) {
return this;
}
ctx.save();
ctx.strokeStyle = this.cornerColor;
ctx.fillStyle = this.cornerColor;
if (!this.transparentCorners) {
ctx.strokeStyle = this.cornerStrokeColor;
}
this._setLineDash(ctx, this.cornerDashArray, null);
// top-left
this._drawControl(
'tl',
ctx,
methodName,
left,
top
);
// top-right
this._drawControl(
'tr',
ctx,
methodName,
left + width,
top
);
// bottom-left
this._drawControl(
'bl',
ctx,
methodName,
left,
top + height
);
// bottom-right
this._drawControl(
'br',
ctx,
methodName,
left + width,
top + height
);
if (!this.get('lockUniScaling')) {
// middle-top
this._drawControl(
'mt',
ctx,
methodName,
left + width / 2,
top
);
// middle-bottom
this._drawControl(
'mb',
ctx,
methodName,
left + width / 2,
top + height
);
// middle-right
this._drawControl(
'mr',
ctx,
methodName,
left + width,
top + height / 2
);
// middle-left
this._drawControl(
'ml',
ctx,
methodName,
left,
top + height / 2
);
}
// middle-top-rotate
if (this.hasRotatingPoint) {
rotate.src = rotationImage;
rotateLeft = left + width / 2 - 6;
rotateTop = top - this.rotatingPointOffset - 6;
ctx.drawImage(rotate, rotateLeft, rotateTop, 32, 32);
}
ctx.restore();
return this;
};
}
function preInitImageEditor(data) {
$.ajax({
url: data['download-url'],
type: 'get',
success: function(responseData) {
var fileUrl = responseData;
initImageEditor(data, fileUrl);
}
});
}
function initImageEditor(data, fileUrl) {
var imageEditor;
var ps;
var blackTheme = {
'common.bi.image': '',
'common.bisize.width': '0',
'common.bisize.height': '0',
'common.backgroundImage': 'none',
'common.backgroundColor': '#1e1e1e',
'common.border': '0px',
// header
'header.backgroundImage': 'none',
'header.backgroundColor': 'transparent',
'header.border': '0px',
// load button
'loadButton.backgroundColor': '#fff',
'loadButton.border': '1px solid #ddd',
'loadButton.color': '#222',
'loadButton.fontFamily': '\'Noto Sans\', sans-serif',
'loadButton.fontSize': '12px',
// download button
'downloadButton.backgroundColor': '#fdba3b',
'downloadButton.border': '1px solid #fdba3b',
'downloadButton.color': '#fff',
'downloadButton.fontFamily': '\'Noto Sans\', sans-serif',
'downloadButton.fontSize': '12px',
// main icons
'menu.normalIcon.path': '/images/icon-d.svg',
'menu.normalIcon.name': 'icon-d',
'menu.activeIcon.path': '/images/icon-b.svg',
'menu.activeIcon.name': 'icon-b',
'menu.disabledIcon.path': '/images/icon-a.svg',
'menu.disabledIcon.name': 'icon-a',
'menu.hoverIcon.path': '/images/icon-c.svg',
'menu.hoverIcon.name': 'icon-c',
'menu.iconSize.width': '24px',
'menu.iconSize.height': '24px',
// submenu primary color
'submenu.backgroundColor': '#1e1e1e',
'submenu.partition.color': '#3c3c3c',
// submenu icons
'submenu.normalIcon.path': '/images/icon-d.svg',
'submenu.normalIcon.name': 'icon-d',
'submenu.activeIcon.path': '/images/icon-c.svg',
'submenu.activeIcon.name': 'icon-c',
'submenu.iconSize.width': '32px',
'submenu.iconSize.height': '32px',
// submenu labels
'submenu.normalLabel.color': '#8a8a8a',
'submenu.normalLabel.fontWeight': 'lighter',
'submenu.activeLabel.color': '#fff',
'submenu.activeLabel.fontWeight': 'lighter',
// checkbox style
'checkbox.border': '0px',
'checkbox.backgroundColor': '#fff',
// range style
'range.pointer.color': '#fff',
'range.bar.color': '#666',
'range.subbar.color': '#d1d1d1',
'range.disabledPointer.color': '#414141',
'range.disabledBar.color': '#282828',
'range.disabledSubbar.color': '#414141',
'range.value.color': '#fff',
'range.value.fontWeight': 'lighter',
'range.value.fontSize': '11px',
'range.value.border': '1px solid #353535',
'range.value.backgroundColor': '#151515',
'range.title.color': '#fff',
'range.title.fontWeight': 'lighter',
// colorpicker style
'colorpicker.button.border': '1px solid #1e1e1e',
'colorpicker.title.color': '#fff'
};
animateSpinner(null, true);
imageEditor = new tui.ImageEditor('#tui-image-editor', {
includeUI: {
loadImage: {
path: fileUrl,
name: data.filename
},
theme: blackTheme,
initMenu: 'draw',
menuBarPosition: 'bottom'
},
cssMaxWidth: 700,
cssMaxHeight: 500,
selectionStyle: {
cornerSize: 20,
rotatingPointOffset: 70,
borderColor: '#333',
cornerColor: '#333',
cornerStyle: 'circle',
borderScaleFactor: 3
},
usageStatistics: false
});
imageEditor.on('image_loaded', () => {
$('.file-save-link').css('display', '');
animateSpinner(null, false);
});
ps = new PerfectScrollbar($('.tui-image-editor-wrap')[0], { wheelSpeed: 0.5 });
$('#tui-image-editor .tui-image-editor').on('mousewheel', (e) => {
var imageOriginalSize = {
width: imageEditor._graphics.canvasImage.width,
height: imageEditor._graphics.canvasImage.height
};
var wDelta = e.originalEvent.wheelDelta || e.originalEvent.deltaY;
var imageEditorWindow = e.currentTarget;
var scrollContainer = $('.tui-image-editor-wrap');
var initWidth = imageEditorWindow.style.width;
var initHeight = imageEditorWindow.style.height;
var scrollContainerInitial = {
top: scrollContainer.scrollTop(),
left: scrollContainer.scrollLeft(),
height: scrollContainer[0].scrollHeight,
width: scrollContainer[0].scrollWidth
};
var mousePosition = {
top: e.clientY - (imageEditorWindow.offsetTop - scrollContainerInitial.top),
left: e.clientX - $(imageEditorWindow).offset().left
};
var newWidth;
var newHeight;
var offsetY;
var offsetX;
if (wDelta > 0) {
newWidth = parseInt(initWidth, 10) * 1.1;
newHeight = parseInt(initHeight, 10) * 1.1;
if (newWidth > imageOriginalSize.width || newHeight > imageOriginalSize.height) {
newWidth = imageOriginalSize.width;
newHeight = imageOriginalSize.height;
}
} else {
newWidth = parseInt(initWidth, 10) * 0.9;
newHeight = parseInt(initHeight, 10) * 0.9;
if (parseInt(imageEditorWindow.dataset.minWidth, 10) * 0.5 > parseInt(newWidth, 10)) {
newWidth = parseInt(imageEditorWindow.dataset.minWidth, 10) * 0.5;
newHeight = parseInt(imageEditorWindow.dataset.minHeight, 10) * 0.5;
}
}
imageEditorWindow.style.width = newWidth + 'px';
imageEditorWindow.style.height = newHeight + 'px';
$(imageEditorWindow).find('canvas, .tui-image-editor-canvas-container')
.css('max-width', imageEditorWindow.style.width)
.css('max-height', imageEditorWindow.style.height);
if (imageEditorWindow.dataset.minHeight === undefined) {
imageEditorWindow.dataset.minHeight = initHeight;
imageEditorWindow.dataset.minWidth = initWidth;
}
offsetY = (scrollContainer[0].scrollHeight - scrollContainerInitial.height)
* (mousePosition.top / scrollContainerInitial.height);
offsetX = (scrollContainer[0].scrollWidth - scrollContainerInitial.width)
* (mousePosition.left / scrollContainerInitial.width);
scrollContainer.scrollTop(scrollContainerInitial.top + offsetY);
scrollContainer.scrollLeft(scrollContainerInitial.left + offsetX);
ps.update();
function initPreviewModal() {
$(document).on('click', '.file-preview-link', function(e) {
var params = {};
var galleryViewId = $(this).data('gallery-view-id');
e.preventDefault();
e.stopPropagation();
});
$('.tui-image-editor-wrap')[0].onwheel = function() { return false; };
$('.tui-image-editor-wrap').css('height', 'calc(100% - 150px)');
$('#fileEditModal').find('.file-name').text('Editing: ' + data.filename);
$('#fileEditModal').modal('show');
$('.tui-image-editor-header').hide();
$('.file-save-link').css('display', 'none');
$('.file-save-link').off().click(function(ev) {
var imageBlob;
var imageDataURL;
var imageParams;
var dataUpload = new FormData();
var blobArray;
var bytePosition;
ev.preventDefault();
ev.stopPropagation();
if (data['mime-type'] === 'image/png') {
imageParams = { format: 'png' };
} else {
imageParams = { format: 'jpeg', quality: (data.quality / 100) };
}
imageDataURL = imageEditor.toDataURL(imageParams);
imageDataURL = atob(imageDataURL.split(',')[1]);
blobArray = new Uint8Array(imageDataURL.length);
for (bytePosition = 0; bytePosition < imageDataURL.length; bytePosition += 1) {
blobArray[bytePosition] = imageDataURL.charCodeAt(bytePosition);
}
imageBlob = new Blob([blobArray]);
function closeEditor() {
animateSpinner(null, false);
imageEditor.destroy();
imageEditor = {};
$('#tui-image-editor').html('');
$('#fileEditModal').modal('hide');
}
dataUpload.append('image', imageBlob);
animateSpinner(null, true);
$.ajax({
type: 'POST',
url: '/files/' + data.id + '/update_image',
data: dataUpload,
contentType: false,
processData: false,
success: function(res) {
$('#modal_link' + data.id).parent().html(res.html);
initPreviewModal();
}
}).done(function() {
closeEditor();
params.gallery = $(`.file-preview-link[data-gallery-view-id=${galleryViewId}]`)
.toArray().sort((a, b) => $(a).closest('.asset').css('order') - $(b).closest('.asset').css('order'))
.map(i => i.dataset.id);
$.get($(this).data('preview-url'), params, function(result) {
$('#filePreviewModal .modal-content').html(result.html);
$('#filePreviewModal').modal('show');
});
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
});
window.onresize = function() {
imageEditor.ui.resizeEditor();
};
}
function openPreviewModal(name, url, downloadUrl) {
var modal = $('#filePreviewModal');
updateFabricControls();
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(data) {
var link = modal.find('.file-download-link');
clearPrevieModal();
if (Object.prototype.hasOwnProperty.call(data, 'wopi-controls')) {
modal.find('.file-wopi-controls').html(data['wopi-controls']);
}
link.attr('href', downloadUrl);
link.attr('data-no-turbolink', true);
link.attr('data-status', 'asset-present');
if (data.type === 'previewable') {
animateSpinner('.file-preview-container', false);
if (data['wopi-preview-url']) {
modal.find('.file-preview-container')
.html(`<iframe class="wopi-file-preview" src="${data['wopi-preview-url']}"></iframe>`);
} else {
modal.find('.file-preview-container')
.append($('<img>')
.css('opacity', 0)
.attr('src', data['large-preview-url'])
.attr('alt', name)
.on('error', ActiveStoragePreviews.reCheckPreview)
.on('load', ActiveStoragePreviews.showPreview)
.click(function(ev) {
ev.stopPropagation();
}));
}
if (!readOnly && data.editable) {
modal.find('.file-edit-link').css('display', '');
modal.find('.file-edit-link').off().click(function(ev) {
$.post('/files/' + data.id + '/start_edit_image');
ev.preventDefault();
ev.stopPropagation();
modal.modal('hide');
preInitImageEditor(data);
});
} else {
modal.find('.file-edit-link').css('display', 'none');
}
} else if (data.type === 'marvinjs') {
openMarvinEditModal(data, modal);
} else {
modal.find('.file-edit-link').css('display', 'none');
modal.find('.file-preview-container').html(data['preview-icon']);
}
if (readOnly) {
modal.find('#wopi_file_edit_button').remove();
}
modal.find('.file-name').text(name);
modal.modal();
modal.find('a[disabled=disabled]').click(function(ev) {
ev.preventDefault();
});
$('.modal-backdrop').last().css('z-index', modal.css('z-index') - 1);
},
error: function() {
// TODO
}
});
}
function clearPrevieModal() {
var modal = $('#filePreviewModal');
modal.find('.file-preview-container').empty();
modal.find('.file-wopi-controls').empty();
modal.find('.file-edit-link').css('display', 'none');
}
function openMarvinEditModal(data, modal) {
modal.find('.file-preview-container')
.append($('<img>')
.css('opacity', 0)
.attr('src', data['large-preview-url'])
.attr('alt', data.name)
.on('error', ActiveStoragePreviews.reCheckPreview)
.on('load', ActiveStoragePreviews.showPreview)
.click(function(ev) {
ev.stopPropagation();
}));
if (!readOnly && data.editable) {
modal.find('.file-edit-link').css('display', '');
modal.find('.file-edit-link').off().click(function(ev) {
ev.preventDefault();
ev.stopPropagation();
modal.modal('hide');
$.post(data['update-url'] + '/start_editing');
MarvinJsEditor.open({
mode: 'edit',
data: data.description,
name: data.name,
marvinUrl: data['update-url']
});
$(document).on('click', '#filePreviewModal .gallery-switcher', function(e) {
e.preventDefault();
e.stopPropagation();
$.get($(this).attr('href'), { gallery: $(this).data('gallery-elements') }, function(result) {
$('#filePreviewModal .modal-content').html(result.html);
});
} else {
modal.find('.file-edit-link').css('display', 'none');
}
});
}
return Object.freeze({
init: initPreviewModal,
imageEditor: initImageEditor
init: initPreviewModal
});
}(window));
}());
FilePreviewModal.init();

View file

@ -0,0 +1,420 @@
/* global animateSpinner fabric PerfectScrollbar refreshProtocolStatusBar tui Uint8Array*/
/* eslint-disable no-underscore-dangle */
var ImageEditorModal = (function() {
function updateFabricControls() {
fabric.Object.prototype.drawBorders = function(ctx, styleOverride = {}) {
var wh = this._calculateCurrentDimensions();
var strokeWidth = 1 / this.borderScaleFactor;
var width = wh.x + strokeWidth;
var height = wh.y + strokeWidth;
var drawRotatingPoint = typeof styleOverride.hasRotatingPoint !== 'undefined'
? styleOverride.hasRotatingPoint : this.hasRotatingPoint;
var hasControls = typeof styleOverride.hasControls !== 'undefined'
? styleOverride.hasControls : this.hasControls;
var rotatingPointOffset = typeof styleOverride.rotatingPointOffset !== 'undefined'
? styleOverride.rotatingPointOffset : this.rotatingPointOffset;
var rotateHeight = -height / 2;
ctx.save();
ctx.strokeStyle = styleOverride.borderColor || this.borderColor;
this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray, null);
ctx.strokeRect(
-width / 2,
-height / 2,
width,
height
);
if (drawRotatingPoint && this.isControlVisible('mtr') && hasControls) {
ctx.beginPath();
ctx.moveTo(0, rotateHeight);
ctx.lineTo(0, rotateHeight - rotatingPointOffset + 10);
ctx.stroke();
}
ctx.restore();
return this;
};
fabric.Object.prototype.drawControls = function(ctx) {
var rotationImage = 'data:image/png;base64,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';
var rotate = new Image();
var rotateLeft;
var rotateTop;
var wh = this._calculateCurrentDimensions();
var width = wh.x;
var height = wh.y;
var scaleOffset = this.cornerSize;
var left = -(width + scaleOffset) / 2;
var top = -(height + scaleOffset) / 2;
var methodName = this.transparentCorners ? 'stroke' : 'fill';
if (!this.hasControls) {
return this;
}
ctx.save();
ctx.strokeStyle = this.cornerColor;
ctx.fillStyle = this.cornerColor;
if (!this.transparentCorners) {
ctx.strokeStyle = this.cornerStrokeColor;
}
this._setLineDash(ctx, this.cornerDashArray, null);
// top-left
this._drawControl(
'tl',
ctx,
methodName,
left,
top
);
// top-right
this._drawControl(
'tr',
ctx,
methodName,
left + width,
top
);
// bottom-left
this._drawControl(
'bl',
ctx,
methodName,
left,
top + height
);
// bottom-right
this._drawControl(
'br',
ctx,
methodName,
left + width,
top + height
);
if (!this.get('lockUniScaling')) {
// middle-top
this._drawControl(
'mt',
ctx,
methodName,
left + width / 2,
top
);
// middle-bottom
this._drawControl(
'mb',
ctx,
methodName,
left + width / 2,
top + height
);
// middle-right
this._drawControl(
'mr',
ctx,
methodName,
left + width,
top + height / 2
);
// middle-left
this._drawControl(
'ml',
ctx,
methodName,
left,
top + height / 2
);
}
// middle-top-rotate
if (this.hasRotatingPoint) {
rotate.src = rotationImage;
rotateLeft = left + width / 2 - 6;
rotateTop = top - this.rotatingPointOffset - 6;
ctx.drawImage(rotate, rotateLeft, rotateTop, 32, 32);
}
ctx.restore();
return this;
};
}
function initImageEditor(data, fileUrl) {
var imageEditor;
var ps;
var blackTheme = {
'common.bi.image': '',
'common.bisize.width': '0',
'common.bisize.height': '0',
'common.backgroundImage': 'none',
'common.backgroundColor': '#1e1e1e',
'common.border': '0px',
// header
'header.backgroundImage': 'none',
'header.backgroundColor': 'transparent',
'header.border': '0px',
// load button
'loadButton.backgroundColor': '#fff',
'loadButton.border': '1px solid #ddd',
'loadButton.color': '#222',
'loadButton.fontFamily': '\'Noto Sans\', sans-serif',
'loadButton.fontSize': '12px',
// download button
'downloadButton.backgroundColor': '#fdba3b',
'downloadButton.border': '1px solid #fdba3b',
'downloadButton.color': '#fff',
'downloadButton.fontFamily': '\'Noto Sans\', sans-serif',
'downloadButton.fontSize': '12px',
// main icons
'menu.normalIcon.path': '/images/icon-d.svg',
'menu.normalIcon.name': 'icon-d',
'menu.activeIcon.path': '/images/icon-b.svg',
'menu.activeIcon.name': 'icon-b',
'menu.disabledIcon.path': '/images/icon-a.svg',
'menu.disabledIcon.name': 'icon-a',
'menu.hoverIcon.path': '/images/icon-c.svg',
'menu.hoverIcon.name': 'icon-c',
'menu.iconSize.width': '24px',
'menu.iconSize.height': '24px',
// submenu primary color
'submenu.backgroundColor': '#1e1e1e',
'submenu.partition.color': '#3c3c3c',
// submenu icons
'submenu.normalIcon.path': '/images/icon-d.svg',
'submenu.normalIcon.name': 'icon-d',
'submenu.activeIcon.path': '/images/icon-c.svg',
'submenu.activeIcon.name': 'icon-c',
'submenu.iconSize.width': '32px',
'submenu.iconSize.height': '32px',
// submenu labels
'submenu.normalLabel.color': '#8a8a8a',
'submenu.normalLabel.fontWeight': 'lighter',
'submenu.activeLabel.color': '#fff',
'submenu.activeLabel.fontWeight': 'lighter',
// checkbox style
'checkbox.border': '0px',
'checkbox.backgroundColor': '#fff',
// range style
'range.pointer.color': '#fff',
'range.bar.color': '#666',
'range.subbar.color': '#d1d1d1',
'range.disabledPointer.color': '#414141',
'range.disabledBar.color': '#282828',
'range.disabledSubbar.color': '#414141',
'range.value.color': '#fff',
'range.value.fontWeight': 'lighter',
'range.value.fontSize': '11px',
'range.value.border': '1px solid #353535',
'range.value.backgroundColor': '#151515',
'range.title.color': '#fff',
'range.title.fontWeight': 'lighter',
// colorpicker style
'colorpicker.button.border': '1px solid #1e1e1e',
'colorpicker.title.color': '#fff'
};
animateSpinner(null, true);
imageEditor = new tui.ImageEditor('#tui-image-editor', {
includeUI: {
loadImage: {
path: fileUrl,
name: data.filename
},
theme: blackTheme,
initMenu: 'draw',
menuBarPosition: 'bottom'
},
cssMaxWidth: 700,
cssMaxHeight: 500,
selectionStyle: {
cornerSize: 20,
rotatingPointOffset: 70,
borderColor: '#333',
cornerColor: '#333',
cornerStyle: 'circle',
borderScaleFactor: 3
},
usageStatistics: false
});
imageEditor.on('image_loaded', () => {
$('.file-save-link').css('display', '');
animateSpinner(null, false);
});
ps = new PerfectScrollbar($('.tui-image-editor-wrap')[0], { wheelSpeed: 0.5 });
$('#tui-image-editor .tui-image-editor').on('mousewheel', (e) => {
var imageOriginalSize = {
width: imageEditor._graphics.canvasImage.width,
height: imageEditor._graphics.canvasImage.height
};
var wDelta = e.originalEvent.wheelDelta || e.originalEvent.deltaY;
var imageEditorWindow = e.currentTarget;
var scrollContainer = $('.tui-image-editor-wrap');
var initWidth = imageEditorWindow.style.width;
var initHeight = imageEditorWindow.style.height;
var scrollContainerInitial = {
top: scrollContainer.scrollTop(),
left: scrollContainer.scrollLeft(),
height: scrollContainer[0].scrollHeight,
width: scrollContainer[0].scrollWidth
};
var mousePosition = {
top: e.clientY - (imageEditorWindow.offsetTop - scrollContainerInitial.top),
left: e.clientX - $(imageEditorWindow).offset().left
};
var newWidth;
var newHeight;
var offsetY;
var offsetX;
if (wDelta > 0) {
newWidth = parseInt(initWidth, 10) * 1.1;
newHeight = parseInt(initHeight, 10) * 1.1;
if (newWidth > imageOriginalSize.width || newHeight > imageOriginalSize.height) {
newWidth = imageOriginalSize.width;
newHeight = imageOriginalSize.height;
}
} else {
newWidth = parseInt(initWidth, 10) * 0.9;
newHeight = parseInt(initHeight, 10) * 0.9;
if (parseInt(imageEditorWindow.dataset.minWidth, 10) * 0.5 > parseInt(newWidth, 10)) {
newWidth = parseInt(imageEditorWindow.dataset.minWidth, 10) * 0.5;
newHeight = parseInt(imageEditorWindow.dataset.minHeight, 10) * 0.5;
}
}
imageEditorWindow.style.width = newWidth + 'px';
imageEditorWindow.style.height = newHeight + 'px';
$(imageEditorWindow).find('canvas, .tui-image-editor-canvas-container')
.css('max-width', imageEditorWindow.style.width)
.css('max-height', imageEditorWindow.style.height);
if (imageEditorWindow.dataset.minHeight === undefined) {
imageEditorWindow.dataset.minHeight = initHeight;
imageEditorWindow.dataset.minWidth = initWidth;
}
offsetY = (scrollContainer[0].scrollHeight - scrollContainerInitial.height)
* (mousePosition.top / scrollContainerInitial.height);
offsetX = (scrollContainer[0].scrollWidth - scrollContainerInitial.width)
* (mousePosition.left / scrollContainerInitial.width);
scrollContainer.scrollTop(scrollContainerInitial.top + offsetY);
scrollContainer.scrollLeft(scrollContainerInitial.left + offsetX);
ps.update();
e.preventDefault();
e.stopPropagation();
});
$('.tui-image-editor-wrap')[0].onwheel = function() { return false; };
$('.tui-image-editor-wrap').css('height', 'calc(100% - 150px)');
$('#fileEditModal').find('.file-name').text('Editing: ' + data.filename);
$('#fileEditModal').modal('show');
$('.tui-image-editor-header').hide();
$('.file-save-link').css('display', 'none');
$('.file-save-link').off().click(function(ev) {
var imageBlob;
var imageDataURL;
var imageParams;
var dataUpload = new FormData();
var blobArray;
var bytePosition;
ev.preventDefault();
ev.stopPropagation();
if (data['mime-type'] === 'image/png') {
imageParams = { format: 'png' };
} else {
imageParams = { format: 'jpeg', quality: (data.quality / 100) };
}
imageDataURL = imageEditor.toDataURL(imageParams);
imageDataURL = atob(imageDataURL.split(',')[1]);
blobArray = new Uint8Array(imageDataURL.length);
for (bytePosition = 0; bytePosition < imageDataURL.length; bytePosition += 1) {
blobArray[bytePosition] = imageDataURL.charCodeAt(bytePosition);
}
imageBlob = new Blob([blobArray]);
function closeEditor() {
animateSpinner(null, false);
imageEditor.destroy();
imageEditor = {};
$('#tui-image-editor').html('');
$('#fileEditModal').modal('hide');
}
dataUpload.append('image', imageBlob);
animateSpinner(null, true);
$.ajax({
type: 'POST',
url: '/files/' + data.id + '/update_image',
data: dataUpload,
contentType: false,
processData: false,
success: function(res) {
$(`.asset[data-asset-id=${data.id}]`).replaceWith(res.html);
$(`.asset[data-asset-id=${data.id}]`).closest('.attachments').trigger('reorder');
closeEditor();
}
});
if (typeof refreshProtocolStatusBar === 'function') refreshProtocolStatusBar();
});
window.onresize = function() {
imageEditor.ui.resizeEditor();
};
}
function preInitImageEditor() {
$(document).on('click', '.image-edit-button', function() {
var editButton = $(this);
updateFabricControls();
$.get(editButton.data('image-url'), function(responseData) {
var fileUrl = responseData;
var data = {
id: editButton.data('image-id'),
quality: editButton.data('image-quality'),
filename: editButton.data('image-name'),
'mime-type': editButton.data('image-mime-type')
};
$('#filePreviewModal').modal('hide');
$.post(editButton.data('image-start-edit-url'));
initImageEditor(data, fileUrl);
});
});
}
return Object.freeze({
init: preInitImageEditor
});
}());
ImageEditorModal.init();

View file

@ -1,5 +1,4 @@
/* global TinyMCE, ChemicalizeMarvinJs, MarvinJSUtil, I18n, FilePreviewModal, tinymce */
/* global Results, Comments */
/* global TinyMCE, ChemicalizeMarvinJs, MarvinJSUtil, I18n, tinymce, HelperModule */
/* eslint-disable no-param-reassign */
/* eslint-disable wrap-iife */
/* eslint-disable no-use-before-define */
@ -166,7 +165,6 @@ var MarvinJsEditorApi = (function() {
TinyMCE.updateImages(config.editor);
}
$(marvinJsModal).modal('hide');
FilePreviewModal.init();
config.button.dataset.inProgress = false;
}).error((response) => {
if (response.status === 403) {
@ -319,7 +317,17 @@ var MarvinJsEditorApi = (function() {
})();
// Initialization
$(document).on('click', '.marvinjs-edit-button', function() {
var editButton = $(this);
$.post(editButton.data('sketch-start-edit-url'));
$('#filePreviewModal').modal('hide');
MarvinJsEditor.open({
mode: 'edit',
data: editButton.data('sketch-description'),
name: editButton.data('sketch-name'),
marvinUrl: editButton.data('update-url')
});
});
$(document).on('turbolinks:load', function() {
MarvinJsEditor = MarvinJsEditorApi();

View file

@ -16,7 +16,6 @@
$(this).find('.modal-body #repository_row-info-table').DataTable().destroy();
$(this).remove();
});
FilePreviewModal.init();
$('#repository_row-info-table').DataTable({
dom: 'RBltpi',
stateSave: false,

View file

@ -0,0 +1,141 @@
// scss-lint:disable ImportantRule PropertyUnits NestingDepth SelectorDepth
// Image preview modal
.modal-file-preview {
background: transparent;
font-size: $font-size-base;
padding: 0 !important;
.modal-dialog {
background: inherit;
height: 100%;
margin: 0;
padding: 0;
width: 100%;
}
.modal-content {
background: inherit;
border: 0;
border-radius: 0;
height: auto;
min-height: 100%;
}
.file-preview-container {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
text-align: center;
width: 100%;
&.processing {
background-image: url("/images/medium/processing.gif");
background-position: center;
background-repeat: no-repeat;
}
.wopi-file-preview {
height: 100%;
width: 100%;
}
}
img {
background: url(asset-path("custom/checkerboard-pattern.png"));
height: auto;
max-width: 100%;
@media (max-height: 520px) {
height: 80%;
max-width: 100%;
}
}
.modal-header {
align-items: center;
background: $color-white;
display: flex;
height: 4em;
padding: 0 1em;
.file-name {
font-weight: bold;
margin-right: auto;
}
}
.modal-body {
align-items: center;
background: transparent;
display: flex;
height: calc(100vh - 8em);
justify-content: center;
overflow: hidden;
padding: 0;
width: 100%;
}
.modal-footer {
background: $color-white;
height: 4em;
padding: 0 1em;
.gallery {
align-items: center;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
height: 100%;
padding: 0 1em;
width: 100%;
img {
max-height: 2em;
max-width: 2em;
}
.file-counter {
font-weight: bold;
grid-column-start: 2;
margin: 0 auto;
}
.gallery-switcher {
align-items: center;
color: $color-black;
display: flex;
&:hover {
text-decoration: none;
}
.file-name {
display: inline-block;
max-width: 16em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fa-angle-right,
.fa-angle-left {
margin: 0 .5em;
}
&.previous-asset {
grid-column-start: 1;
margin-right: auto;
}
&.next-asset {
grid-column-start: 3;
margin-left: auto;
}
}
}
}
}

View file

@ -16,7 +16,8 @@
transition: .3s;
user-select: none;
.fas {
.fas,
img {
color: inherit;
margin-right: 5px;
}

View file

@ -183,6 +183,12 @@
text-align: center;
width: 100%;
&.processing {
background-image: url("/images/medium/processing.gif");
background-position: center;
background-repeat: no-repeat;
}
img {
max-height: 100%;
max-width: 100%;

View file

@ -1458,139 +1458,6 @@ ul.content-activities {
}
}
// Image preview modal
.modal-file-preview {
background: transparent;
font-size: $font-size-large;
padding-right: 0 !important;
z-index: 1060;
.preview-close {
background: transparent;
border: 0;
color: $color-white;
display: inline-block;
float: right;
}
.file-wopi-controls {
display: inline-block;
.btn {
margin: 0 15px;
}
}
.modal-dialog {
height: 100%;
margin: 0;
padding: 0;
width: auto;
}
.modal-content {
background: transparent;
border: 0;
-webkit-box-shadow: none;
box-shadow: none;
color: $color-white;
height: 100%;
width: auto;
.modal-body {
width: 100%;
}
}
.file-preview-container {
align-items: center;
color: $gray-dark;
display: -moz-flex;
display: -webkit-flex;
display: flex;
height: 100%;
justify-content: center;
text-align: center;
width: 100%;
&.processing {
background-image: url("/images/medium/processing.gif");
background-position: center;
background-repeat: no-repeat;
}
.file-name {
color: $color-black;
margin: 30px 0;
}
.wopi-file-preview {
border: 0;
height: 100%;
width: 100%;
}
}
img {
background: url(asset-path("custom/checkerboard-pattern.png"));
height: auto;
max-width: 100%;
@media (max-height: 520px) {
height: 80%;
max-width: 100%;
}
}
.modal-header {
background: $color-black;
border: 0;
height: 60px;
line-height: 40px;
text-align: center;
.file-name {
float: left;
}
}
.modal-body {
align-items: center;
display: -moz-flex;
display: -webkit-flex;
display: flex;
height: calc(100% - 120px);
justify-content: center;
overflow: hidden;
padding: 0;
}
.modal-footer {
background: $color-black;
border: 0;
bottom: 0;
height: 60px;
position: absolute;
text-align: center;
width: 100%;
}
.file-download-link {
color: $color-white;
display: inline-block;
float: right;
margin-right: 20px;
}
.file-edit-link {
color: $color-white;
display: inline-block;
float: right;
margin-right: 20px;
}
}
// Disable textarea resizing throughout application
// (will be done via autosize JS plugin)
textarea {

View file

@ -14,93 +14,32 @@ class AssetsController < ApplicationController
include FileIconsHelper
include MyModulesHelper
helper_method :wopi_file_edit_button_status
before_action :load_vars, except: :create_wopi_file
before_action :check_read_permission, except: :edit
before_action :check_edit_permission, only: %i(edit toggle_view_mode)
def file_preview
file_type = @asset.file.metadata[:asset_type] || (@asset.previewable? ? 'previewable' : false)
response_json = {
'id' => @asset.id,
'type' => file_type,
'filename' => truncate(escape_input(@asset.file_name),
length: Constants::FILENAME_TRUNCATION_LENGTH),
'download-url' => asset_file_url_path(@asset)
}
can_edit = if @assoc.class == Step
can_manage_protocol_in_module?(@protocol) || can_manage_protocol_in_repository?(@protocol)
elsif @assoc.class == Result
can_manage_module?(@my_module)
elsif @assoc.class == RepositoryCell && !@repository.is_a?(RepositorySnapshot)
can_manage_repository_rows?(@repository)
end
if response_json['type'] == 'previewable'
if ['image/jpeg', 'image/pjpeg'].include? @asset.file.content_type
response_json['quality'] = @asset.file_image_quality || 80
end
response_json.merge!(
'editable' => @asset.editable_image? && can_edit,
'mime-type' => @asset.file.content_type,
'large-preview-url' => rails_representation_url(@asset.large_preview)
)
elsif response_json['type'] == 'marvinjs'
response_json.merge!(
'editable' => can_edit,
'large-preview-url' => rails_representation_url(@asset.large_preview),
'update-url' => marvin_js_asset_path(@asset.id),
'description' => @asset.file.metadata[:description],
'name' => @asset.file.metadata[:name]
)
else
response_json['preview-icon'] = render_to_string(partial: 'shared/file_preview_icon.html.erb',
locals: { asset: @asset })
end
if wopi_enabled? && wopi_file?(@asset)
edit_supported, title = wopi_file_edit_button_status
response_json['wopi-preview-url'] = @asset.get_action_url(current_user, 'embedview')
response_json['wopi-controls'] = render_to_string(
partial: 'assets/wopi/file_wopi_controls.html.erb',
locals: {
asset: @asset,
can_edit: can_edit,
edit_supported: edit_supported,
title: title
}
)
end
respond_to do |format|
format.json do
render json: response_json
end
end
end
# Check whether the wopi file can be edited and return appropriate response
def wopi_file_edit_button_status
file_ext = @asset.file_name.split('.').last
if Constants::WOPI_EDITABLE_FORMATS.include?(file_ext)
edit_supported = true
title = ''
else
edit_supported = false
title = if Constants::FILE_TEXT_FORMATS.include?(file_ext)
I18n.t('assets.wopi_supported_text_formats_title')
elsif Constants::FILE_TABLE_FORMATS.include?(file_ext)
I18n.t('assets.wopi_supported_table_formats_title')
else
I18n.t('assets.wopi_supported_presentation_formats_title')
end
end
return edit_supported, title
render json: { html: render_to_string(
partial: 'shared/file_preview/content.html.erb',
locals: {
asset: @asset,
can_edit: can_manage_asset?(@asset),
gallery: params[:gallery]
}
) }
end
def toggle_view_mode
@asset.view_mode = toggle_view_mode_params[:view_mode]
if @asset.save(touch: false)
html = render_to_string(partial: 'assets/asset.html.erb', locals: { asset: @asset })
gallery_view_id = @assoc.id if @assoc.class == Step
html = render_to_string(partial: 'assets/asset.html.erb', locals: {
asset: @asset,
gallery_view_id: gallery_view_id
})
respond_to do |format|
format.json do
render json: { html: html }, status: :ok
@ -126,7 +65,7 @@ class AssetsController < ApplicationController
tkn = current_user.get_wopi_token
@token = tkn.token
@ttl = (tkn.ttl * 1000).to_s
@asset.step&.protocol&.update(updated_at: Time.now)
@asset.step&.protocol&.update(updated_at: Time.zone.now)
create_wopi_file_activity(current_user, true)
@ -160,7 +99,7 @@ class AssetsController < ApplicationController
@asset.team.release_space(orig_file_size)
# Post process file here
@asset.post_process_file(@asset.team)
@asset.step&.protocol&.update(updated_at: Time.now)
@asset.step&.protocol&.update(updated_at: Time.zone.now)
render_html = if @asset.step || @asset.result
render_to_string(
@ -170,7 +109,7 @@ class AssetsController < ApplicationController
)
else
render_to_string(
partial: 'shared/asset_link',
partial: 'assets/asset_link.html.erb',
locals: { asset: @asset, display_image_tag: true },
formats: :html
)
@ -209,7 +148,7 @@ class AssetsController < ApplicationController
render_403 && return unless can_manage_protocol_in_module?(step.protocol) ||
can_manage_protocol_in_repository?(step.protocol)
step_asset = StepAsset.create!(step: step, asset: asset)
step.protocol&.update(updated_at: Time.now)
step.protocol&.update(updated_at: Time.zone.now)
edit_url = edit_asset_url(step_asset.asset_id)
elsif params[:element_type] == 'Result'
@ -257,25 +196,30 @@ class AssetsController < ApplicationController
end
def check_read_permission
if @assoc.class == Step
render_403 && return unless can_read_protocol_in_module?(@protocol) ||
can_read_protocol_in_repository?(@protocol)
elsif @assoc.class == Result
render_403 and return unless can_read_experiment?(@my_module.experiment)
elsif @assoc.class == RepositoryCell
render_403 and return unless can_read_repository?(@repository)
end
render_403 unless can_read_asset?(@asset)
end
def check_edit_permission
if @assoc.class == Step
render_403 && return unless can_manage_protocol_in_module?(@protocol) ||
can_manage_protocol_in_repository?(@protocol)
elsif @assoc.class == Result
render_403 and return unless can_manage_module?(@my_module)
elsif @assoc.class == RepositoryCell
render_403 and return unless can_manage_repository_rows?(@repository)
render_403 unless can_manage_asset?(@asset)
end
# Check whether the wopi file can be edited and return appropriate response
def wopi_file_edit_button_status(asset)
file_ext = asset.file_name.split('.').last
if Constants::WOPI_EDITABLE_FORMATS.include?(file_ext)
edit_supported = true
title = ''
else
edit_supported = false
title = if Constants::FILE_TEXT_FORMATS.include?(file_ext)
I18n.t('assets.wopi_supported_text_formats_title')
elsif Constants::FILE_TABLE_FORMATS.include?(file_ext)
I18n.t('assets.wopi_supported_table_formats_title')
else
I18n.t('assets.wopi_supported_presentation_formats_title')
end
end
return edit_supported, title
end
def append_wd_params(url)

33
app/permissions/asset.rb Normal file
View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
Canaid::Permissions.register_for(Asset) do
can :read_asset do |user, asset|
object = asset.step || asset.result || asset.repository_cell
case object
when Step
protocol = object.protocol
can_read_protocol_in_module?(user, protocol) || can_read_protocol_in_repository?(user, protocol)
when Result
can_read_experiment?(user, object.my_module.experiment)
when RepositoryCell
can_read_repository?(user, object.repository_column.repository)
end
end
can :manage_asset do |user, asset|
object = asset.step || asset.result || asset.repository_cell
case object
when Step
protocol = object.protocol
can_manage_protocol_in_module?(user, protocol) || can_manage_protocol_in_repository?(user, protocol)
when Result
can_manage_experiment?(user, object.my_module.experiment)
when RepositoryCell
return false if object.repository_column.repository.is_a?(RepositorySnapshot)
can_manage_repository?(user, object.repository_column.repository)
end
end
end

View file

@ -1,7 +1,8 @@
<% gallery_view_id = nil unless defined? gallery_view_id %>
<% if asset.inline? %>
<%= render partial: 'assets/asset_inline.html.erb', locals: { asset: asset } %>
<%= render partial: 'assets/asset_inline.html.erb', locals: { asset: asset, gallery_view_id: gallery_view_id } %>
<% elsif asset.list? %>
<%= render partial: 'assets/asset_list.html.erb', locals: { asset: asset } %>
<%= render partial: 'assets/asset_list.html.erb', locals: { asset: asset, gallery_view_id: gallery_view_id } %>
<% else %>
<%= render partial: 'assets/asset_thumbnail.html.erb', locals: { edit_page: false, asset: asset } %>
<%= render partial: 'assets/asset_thumbnail.html.erb', locals: { asset: asset, gallery_view_id: gallery_view_id } %>
<% end %>

View file

@ -9,7 +9,12 @@
<%= link_to rails_blob_path(asset.file, disposition: 'attachment'),
class: "file-preview-link file-name",
id: "modal_link#{asset.id}",
data: { no_turbolink: true, id: true, 'preview-url': asset_file_preview_path(asset)} do %>
data: {
no_turbolink: true,
id: asset.id,
gallery_view_id: gallery_view_id,
preview_url: asset_file_preview_path(asset)
} do %>
<%= asset.file_name %>
<% end %>
<div class="file-metadata">

View file

@ -10,7 +10,12 @@
<%= link_to rails_blob_path(asset.file, disposition: 'attachment'),
class: "file-preview-link file-name",
id: "modal_link#{asset.id}",
data: { no_turbolink: true, id: true, 'preview-url': asset_file_preview_path(asset)} do %>
data: {
no_turbolink: true,
id: asset.id,
gallery_view_id: gallery_view_id,
preview_url: asset_file_preview_path(asset)
} do %>
<%= asset.file_name %>
<% end %>
<div class="file-metadata">

View file

@ -7,7 +7,12 @@
<%= link_to rails_blob_path(asset.file, disposition: 'attachment'),
class: "file-preview-link",
id: "modal_link#{asset.id}",
data: { no_turbolink: true, id: true, 'preview-url': asset_file_preview_path(asset)} do %>
data: {
no_turbolink: true,
id: asset.id,
gallery_view_id: gallery_view_id,
preview_url: asset_file_preview_path(asset)
} do %>
<div class="change-preview-type"
data-preview-type="inline"
data-toggle-view-url="<%= toggle_view_mode_path(asset) %>">

View file

@ -1,28 +1,18 @@
<%= link_to view_asset_url(id: asset),
id: 'wopi_file_view_button',
class: 'btn btn-default btn-sm',
target: '_blank',
style: 'display: inline-block' do %>
<%= file_application_icon(asset) %>
<%= wopi_button_text(asset, 'view') %>
<% end %>
<% if can_edit && edit_supported %>
<% if edit_supported %>
<%= link_to edit_asset_url(id: asset),
id: 'wopi_file_edit_button',
class: 'btn btn-default btn-sm',
target: '_blank',
style: 'display: inline-block' do %>
class: 'btn btn-light',
target: '_blank' do %>
<%= file_application_icon(asset) %>
<%= wopi_button_text(asset, 'edit') %>
<% end %>
<% elsif can_edit %>
<% else %>
<%= link_to edit_asset_url(id: asset),
id: 'wopi_file_edit_button',
class: 'btn btn-default btn-sm',
class: 'btn btn-light',
target: '_blank',
title: title,
disabled: true,
style: 'display: inline-block' do %>
disabled: true do %>
<%= file_application_icon(asset) %>
<%= wopi_button_text(asset, 'edit') %>
<% end %>

View file

@ -46,7 +46,7 @@
<!-- About us modal -->
<%= render "shared/about_modal" %>
<%= render "shared/file_preview_modal.html.erb" %>
<%= render "shared/file_preview/modal.html.erb" %>
<%= render "shared/file_edit_modal.html.erb" %>
<%= render "shared/marvinjs_modal.html.erb" %>
<%= render "shared/navigation" %>

View file

@ -17,5 +17,3 @@
<% end %>
</div>
</div>
<script>FilePreviewModal.init()</script>

View file

@ -93,7 +93,6 @@
<% end %>
<% end %>
</div>
<script>FilePreviewModal.init()</script>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t('general.close')%></button>
</div>

View file

@ -0,0 +1,102 @@
<div class="modal-header">
<span class="file-name"><%= asset.file_name %></span>
<div class="sci-btn-group">
<% if can_edit %>
<% if wopi_enabled? && wopi_file?(asset) %>
<% edit_supported, title = wopi_file_edit_button_status(asset) %>
<%= render partial: 'assets/wopi/file_wopi_controls.html.erb',
locals: {
asset: asset,
edit_supported: edit_supported,
title: title
} %>
<% elsif asset.file.metadata[:asset_type] == 'marvinjs' %>
<button class="btn btn-light marvinjs-edit-button"
data-sketch-id="<%= asset.id %>"
data-update-url="<%= marvin_js_asset_path(asset) %>"
data-sketch-start-edit-url="<%= start_editing_marvin_js_asset_path(asset) %>"
data-sketch-name="<%= asset.file.metadata[:name] %>"
data-sketch-description="<%= asset.file.metadata[:description] %>"
>
<span class="fas fa-pencil-alt"></span>
<%= t('assets.file_preview.edit_in_marvinjs') %>
</button>
<% elsif asset.editable_image? %>
<button class="btn btn-light image-edit-button"
data-image-id="<%= asset.id %>"
data-image-name="<%= asset.file_name %>"
data-image-url="<%= asset_file_url_path(asset) %>"
data-image-quality="<%= asset.file_image_quality || 80 %>"
data-image-mime-type="<%= asset.file.content_type %>"
data-image-start-edit-url="<%= start_edit_image_path(asset) %>"
>
<span class="fas fa-pencil-alt"></span>
<%= t('assets.file_preview.edit_in_scinote') %>
</button>
<% end %>
<% end %>
<a class="btn btn-light file-download-link" href="<%= rails_blob_path(asset.file, disposition: 'attachment') %>" data-turbolinks="false">
<span class="fas fa-download"></span> <%= t('Download')%>
</a>
<button type="button" class="btn icon-btn btn-light" data-dismiss="modal"><span class="fas fa-times"></span></button>
</div>
</div>
<div class="modal-body">
<div class="file-preview-container">
<% if asset.previewable? %>
<% if wopi_enabled? && wopi_file?(asset) %>
<iframe class="wopi-file-preview" src="<%= asset.get_action_url(current_user, 'embedview') %>"></iframe>
<% else %>
<%= image_tag asset.large_preview,
onerror: 'ActiveStoragePreviews.reCheckPreview(event)',
onload: 'ActiveStoragePreviews.showPreview(event)',
style: 'opacity: 0' %>
<% end %>
<% else %>
<%= render partial: 'shared/file_preview/file_icon.html.erb', locals: { asset: asset } %>
<% end %>
</div>
</div>
<div class="modal-footer">
<% if gallery %>
<div class="gallery">
<% previous_asset = Asset.find_by(id: gallery.split(asset.id.to_s)[0]&.last) %>
<% next_asset = Asset.find_by(id: gallery.split(asset.id.to_s)[1]&.first) %>
<% if previous_asset && can_read_asset?(previous_asset) %>
<%= link_to asset_file_preview_path(previous_asset),
class: "previous-asset gallery-switcher",
data: {id: previous_asset.id, gallery_elements: gallery} do %>
<% if previous_asset.previewable? %>
<%= image_tag previous_asset.medium_preview,
onerror: 'ActiveStoragePreviews.reCheckPreview(event)',
onload: 'ActiveStoragePreviews.showPreview(event)',
style: 'opacity: 0' %>
<% else %>
<i class="fas <%= file_fa_icon_class(previous_asset) if previous_asset.file_name %>"></i>
<% end %>
<i class="fas fa-angle-left"></i>
<span class="file-name"><%= previous_asset.file_name %></span>
<% end %>
<% end %>
<span class="file-counter">
<%= gallery.split(asset.id.to_s)[0].length + 1 %> of <%= gallery.length %> attachments
</span>
<% if next_asset && can_read_asset?(next_asset) %>
<%= link_to asset_file_preview_path(next_asset),
class: "next-asset gallery-switcher",
data: {id: next_asset.id, gallery_elements: gallery} do %>
<span class="file-name"><%= next_asset.file_name %></span>
<i class="fas fa-angle-right"></i>
<% if next_asset.previewable? %>
<%= image_tag next_asset.medium_preview,
onerror: 'ActiveStoragePreviews.reCheckPreview(event)',
onload: 'ActiveStoragePreviews.showPreview(event)',
style: 'opacity: 0' %>
<% else %>
<i class="fas <%= file_fa_icon_class(next_asset) if next_asset.file_name %>"></i>
<% end %>
<% end %>
<% end %>
</div>
<% end %>
</div>

View file

@ -0,0 +1,4 @@
<div>
<i class="fas fa-10x <%= file_fa_icon_class(asset) %>"></i>
<h3 class="file-name"></h3>
</div>

View file

@ -0,0 +1,13 @@
<div id="filePreviewModal"
class="modal modal-file-preview"
role="dialog"
tabindex="-1"
aria-labelledby="filePreviewModal"
aria-hidden="true"
data-backdrop="static"
data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
</div>

View file

@ -41,7 +41,7 @@
<div class="col-xs-12 attachments" data-step-id="<%= step.id %>" data-order="<%= current_order %>">
<% assets.each_with_index do |asset, i| %>
<%= render partial: 'assets/asset.html.erb', locals: { asset: asset } %>
<%= render partial: 'assets/asset.html.erb', locals: { asset: asset, gallery_view_id: step.id } %>
<% end %>
</div>
<hr>

View file

@ -2283,6 +2283,9 @@ en:
errors:
forbidden: 'You do not have permission to add files.'
not_found: 'Element not found.'
file_preview:
edit_in_scinote: "Edit in SciNote"
edit_in_marvinjs: "Edit in Marvin JS"
atwho:
no_results:
projects: "Projects with this name were not found"