dragndrop + bulk upload + bulk delete + shit/cmd/ctrl multi file selection + player default view if no fallback playlist
This commit is contained in:
parent
fab5f8f49e
commit
5065c9fe54
File diff suppressed because one or more lines are too long
90
data/www/js/dragdrop.js
vendored
Normal file
90
data/www/js/dragdrop.js
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
jQuery(function ($) {
|
||||||
|
|
||||||
|
const main = function () {
|
||||||
|
fileUpload();
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileUpload = function () {
|
||||||
|
$('.btn-super-upload').each(function () {
|
||||||
|
const $button = $(this);
|
||||||
|
const $input = $(this).find('input[type=file]');
|
||||||
|
$input.fileupload({
|
||||||
|
url: $(this).attr('data-route'),
|
||||||
|
dropZone: $('body'),
|
||||||
|
formData: {},
|
||||||
|
dataType: 'json',
|
||||||
|
add: function (e, data) {
|
||||||
|
const $alert = $('.alert-danger');
|
||||||
|
const $bar = $button.find('.progress-bar');
|
||||||
|
$bar.css('width', '0%');
|
||||||
|
$button.addClass('uploading').removeClass('btn-info btn-super-upload').addClass('btn-naked btn-super-upload-busy');
|
||||||
|
$alert.addClass('hidden').text('');
|
||||||
|
data.submit();
|
||||||
|
},
|
||||||
|
progressall: function (e, data) {
|
||||||
|
const progress = parseInt(data.loaded / data.total * 100, 10);
|
||||||
|
const $bar = $button.find('.progress-bar');
|
||||||
|
const $percent = $button.find('.percent');
|
||||||
|
$bar.css('width', progress + '%');
|
||||||
|
$percent.text(progress + '%');
|
||||||
|
},
|
||||||
|
always: function (e, data) {
|
||||||
|
const response = data._response.jqXHR;
|
||||||
|
$button.removeClass('uploading').removeClass('btn-naked btn-super-upload-busy').addClass('btn-info btn-super-upload');
|
||||||
|
if (response.status != 200) {
|
||||||
|
const $alert = $('.alert-danger').removeClass('hidden');
|
||||||
|
if (response.status == 413) {
|
||||||
|
$alert.text(l.js_common_http_error_413);
|
||||||
|
} else {
|
||||||
|
$alert.text(l.js_common_http_error_occured.replace('%code%', response.status));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
|
$(document).on('click', '.btn-super-upload', function (e) {
|
||||||
|
$(this).find('input[type=file]')[0].click();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('dragenter', 'body', function () {
|
||||||
|
$(this).addClass('dragenter');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('dragover', 'body', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
$(this).addClass('dragover');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('dragleave', 'body', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
$(this).removeClass('dragenter dragover');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('drop', 'body', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
$(this).removeClass('dragenter dragover');
|
||||||
|
|
||||||
|
const $dz = $('.dropzone:visible');
|
||||||
|
|
||||||
|
if (isset($dz.attr('data-handle-drop') && $dz.attr('data-handle-drop') === '1')) {
|
||||||
|
const $inputTarget = $("#" + $dz.attr('data-related-input'));
|
||||||
|
const droppedFiles = e.originalEvent.dataTransfer.files;
|
||||||
|
$inputTarget.prop("files", droppedFiles).trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@ -2,6 +2,7 @@ let onPickedElement = function (element) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
jQuery(function ($) {
|
jQuery(function ($) {
|
||||||
|
let lastClicked = null;
|
||||||
|
|
||||||
const explrSidebarOpenFromFolder = function (folderId) {
|
const explrSidebarOpenFromFolder = function (folderId) {
|
||||||
const $leaf = $('.li-explr-folder-' + folderId);
|
const $leaf = $('.li-explr-folder-' + folderId);
|
||||||
@ -70,29 +71,59 @@ jQuery(function ($) {
|
|||||||
initExplr();
|
initExplr();
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectEpxlrLink = function ($link) {
|
const updateBodyClasses = function () {
|
||||||
$('a.explr-link').removeClass('highlight-clicked');
|
const $selectedLinks = $('a.explr-link.highlight-clicked');
|
||||||
$('a.explr-link').parent().removeClass('highlight-clicked');
|
const isMultiSelect = $selectedLinks.length > 1;
|
||||||
$('body').removeClass('explr-selection explr-selection-actionable explr-selection-entity explr-selection-folder');
|
const isSingleSelect = $selectedLinks.length === 1;
|
||||||
|
const $link = $selectedLinks.last();
|
||||||
|
|
||||||
if ($link.hasClass('explr-item-selectable')) {
|
$('body')
|
||||||
$link.addClass('highlight-clicked');
|
.toggleClass('explr-selection', isSingleSelect)
|
||||||
$link.parent().addClass('highlight-clicked');
|
.toggleClass('explr-selection-actionable', isSingleSelect && $link.hasClass('explr-item-actionable'))
|
||||||
$('body').addClass('explr-selection');
|
.toggleClass('explr-selection-entity', isSingleSelect && $link.hasClass('explr-item-entity'))
|
||||||
if ($link.hasClass('explr-item-actionable')) {
|
.toggleClass('explr-selection-folder', isSingleSelect && $link.hasClass('explr-item-folder'))
|
||||||
$('body').addClass('explr-selection-actionable');
|
.toggleClass('explr-multiselection', isMultiSelect)
|
||||||
}
|
.toggleClass('explr-multiselection-actionable', isMultiSelect && $selectedLinks.hasClass('explr-item-actionable'))
|
||||||
if ($link.hasClass('explr-item-entity')) {
|
.toggleClass('explr-multiselection-entity', isMultiSelect && $selectedLinks.hasClass('explr-item-entity'))
|
||||||
$('body').addClass('explr-selection-entity');
|
.toggleClass('explr-multiselection-folder', isMultiSelect && $selectedLinks.hasClass('explr-item-folder'));
|
||||||
}
|
|
||||||
if ($link.hasClass('explr-item-folder')) {
|
|
||||||
$('body').addClass('explr-selection-folder');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectEpxlrLink = function ($link) {
|
||||||
|
$link.addClass('highlight-clicked');
|
||||||
|
$link.parent().addClass('highlight-clicked');
|
||||||
|
updateBodyClasses();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSelection = function () {
|
||||||
|
$('a.explr-link').removeClass('highlight-clicked');
|
||||||
|
$('a.explr-link').parent().removeClass('highlight-clicked');
|
||||||
|
$('body').removeClass('explr-selection explr-selection-actionable explr-selection-entity explr-selection-folder explr-multiselection explr-multiselection-actionable explr-multiselection-entity explr-multiselection-folder');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShiftClick = function ($link) {
|
||||||
|
const $links = $('li > a.explr-link');
|
||||||
|
const start = $links.index(lastClicked);
|
||||||
|
const end = $links.index($link);
|
||||||
|
const [from, to] = start < end ? [start, end] : [end, start];
|
||||||
|
$links.slice(from, to + 1).each(function () {
|
||||||
|
selectEpxlrLink($(this));
|
||||||
|
});
|
||||||
|
updateBodyClasses();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCmdCtrlClick = function ($link) {
|
||||||
|
if ($link.hasClass('highlight-clicked')) {
|
||||||
|
$link.removeClass('highlight-clicked');
|
||||||
|
$link.parent().removeClass('highlight-clicked');
|
||||||
|
} else {
|
||||||
|
selectEpxlrLink($link);
|
||||||
|
}
|
||||||
|
updateBodyClasses();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const getExplrSelection = function () {
|
const getExplrSelection = function () {
|
||||||
return $('.explr-dirview .highlight-clicked');
|
return $('.explr-dirview li.highlight-clicked');
|
||||||
};
|
};
|
||||||
|
|
||||||
const renameExplrItem = function ($item) {
|
const renameExplrItem = function ($item) {
|
||||||
@ -116,9 +147,9 @@ jQuery(function ($) {
|
|||||||
let route;
|
let route;
|
||||||
|
|
||||||
if (is_folder) {
|
if (is_folder) {
|
||||||
route = $(this).attr('data-folder-route') + '?id=' + $item.attr('data-id');
|
route = $(this).attr('data-folder-route') + '&id=' + $item.attr('data-id');
|
||||||
} else {
|
} else {
|
||||||
route = $(this).attr('data-entity-route') + '?id=' + $item.attr('data-id');
|
route = $(this).attr('data-entity-route') + '&id=' + $item.attr('data-id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confirm(l.js_common_are_you_sure)) {
|
if (confirm(l.js_common_are_you_sure)) {
|
||||||
@ -126,18 +157,44 @@ jQuery(function ($) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.explr-items-delete', function () {
|
||||||
|
const $items = getExplrSelection();
|
||||||
|
const folder_ids = [], entity_ids = [];
|
||||||
|
|
||||||
|
$items.each(function() {
|
||||||
|
const is_folder = $(this).attr('data-folder') === '1';
|
||||||
|
const id = $(this).attr('data-id');
|
||||||
|
|
||||||
|
if (is_folder) {
|
||||||
|
folder_ids.push(id);
|
||||||
|
} else {
|
||||||
|
entity_ids.push(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirm(l.js_common_are_you_sure)) {
|
||||||
|
document.location.href = $(this).attr('data-route')
|
||||||
|
+ '&folder_ids=' + folder_ids.join(',')
|
||||||
|
+ '&entity_ids=' + entity_ids.join(',')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$(document).keyup(function (e) {
|
$(document).keyup(function (e) {
|
||||||
const $selectedLink = $('.explr-item-selectable.highlight-clicked');
|
const $selectedLink = $('.explr-item-selectable.highlight-clicked');
|
||||||
const $selectedLi = $selectedLink.parents('li:eq(0)');
|
const $selectedLi = $selectedLink.parents('li:eq(0)');
|
||||||
|
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
$('.dirview .new-folder').addClass('hidden');
|
||||||
|
$('.dirview .renaming').removeClass('renaming');
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
if ($('.renaming input:focus').length > 0) {
|
if ($('.renaming input:focus').length > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === "Escape") {
|
if (e.code === "Space") {
|
||||||
$('.dirview .new-folder').addClass('hidden');
|
|
||||||
$('.dirview .renaming').removeClass('renaming');
|
|
||||||
} else if (e.code === "Space") {
|
|
||||||
renameExplrItem($selectedLi);
|
renameExplrItem($selectedLi);
|
||||||
} else if ($selectedLink.length) {
|
} else if ($selectedLink.length) {
|
||||||
const $prevLi = $selectedLi.prev('li:visible');
|
const $prevLi = $selectedLi.prev('li:visible');
|
||||||
@ -158,6 +215,9 @@ jQuery(function ($) {
|
|||||||
if ($('.explr-item-delete:visible').length) {
|
if ($('.explr-item-delete:visible').length) {
|
||||||
$('.explr-item-delete:visible').click();
|
$('.explr-item-delete:visible').click();
|
||||||
}
|
}
|
||||||
|
if ($('.explr-items-delete:visible').length) {
|
||||||
|
$('.explr-items-delete:visible').click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (e.key.indexOf('Arrow') === 0) {
|
} else if (e.key.indexOf('Arrow') === 0) {
|
||||||
selectEpxlrLink($('.explr-dirview li:visible:eq(0)').find('.explr-link'));
|
selectEpxlrLink($('.explr-dirview li:visible:eq(0)').find('.explr-link'));
|
||||||
@ -167,7 +227,17 @@ jQuery(function ($) {
|
|||||||
// Explorer item selection
|
// Explorer item selection
|
||||||
$(document).on('click', 'a.explr-link', function (event) {
|
$(document).on('click', 'a.explr-link', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
selectEpxlrLink($(this));
|
const $link = $(this);
|
||||||
|
|
||||||
|
if (event.shiftKey && lastClicked) {
|
||||||
|
handleShiftClick($link);
|
||||||
|
} else if (event.metaKey || event.ctrlKey) {
|
||||||
|
handleCmdCtrlClick($link);
|
||||||
|
} else {
|
||||||
|
clearSelection();
|
||||||
|
selectEpxlrLink($link);
|
||||||
|
}
|
||||||
|
lastClicked = $link;
|
||||||
});
|
});
|
||||||
$(document).on('click', 'a.explr-pick-element', function (event) {
|
$(document).on('click', 'a.explr-pick-element', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
const $modalsRoot = $('.modals');
|
const $modalsRoot = $('.modals');
|
||||||
const $pickersRoot = $('.pickers');
|
const $pickersRoot = $('.pickers');
|
||||||
|
|
||||||
|
const isset = function (obj){
|
||||||
|
return obj !== undefined && obj !== null;
|
||||||
|
};
|
||||||
|
|
||||||
const showModal = function (modalClass) {
|
const showModal = function (modalClass) {
|
||||||
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
$modalsRoot.removeClass('hidden').find('form').trigger('reset');
|
||||||
$modalsRoot.find('.modal').addClass('hidden');
|
$modalsRoot.find('.modal').addClass('hidden');
|
||||||
|
|||||||
1477
data/www/js/lib/jquery-fileupload.js
vendored
Normal file
1477
data/www/js/lib/jquery-fileupload.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,7 +22,7 @@ jQuery(document).ready(function ($) {
|
|||||||
$('.modal-variable-edit input:visible:eq(0)').focus().select();
|
$('.modal-variable-edit input:visible:eq(0)').focus().select();
|
||||||
$('#variable-edit-name').val(variable.name);
|
$('#variable-edit-name').val(variable.name);
|
||||||
$('#variable-edit-description').html(variable.description);
|
$('#variable-edit-description').html(variable.description);
|
||||||
$('#variable-edit-description-edition').html(variable.description_edition).toggleClass('hidden', variable.description_edition == '');
|
$('#variable-edit-description-edition').html(variable.description_edition).toggleClass('hidden', variable.description_edition === '');
|
||||||
$('#variable-edit-value').val(variable.value);
|
$('#variable-edit-value').val(variable.value);
|
||||||
$('#variable-edit-id').val(variable.id);
|
$('#variable-edit-id').val(variable.id);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -77,7 +77,6 @@ main {
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.explr-selection-actions + .btn,
|
|
||||||
.btn:first-child {
|
.btn:first-child {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ button,
|
|||||||
letter-spacing: -0.5px;
|
letter-spacing: -0.5px;
|
||||||
margin-top: -$shadowOffset;
|
margin-top: -$shadowOffset;
|
||||||
min-width: 38px;
|
min-width: 38px;
|
||||||
|
min-height: 34px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
|||||||
64
data/www/scss/components/_dragdrop.scss
Normal file
64
data/www/scss/components/_dragdrop.scss
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
body.dragover {
|
||||||
|
.shakeondrag {
|
||||||
|
animation: shakednd .1s linear alternate infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-super-upload-busy,
|
||||||
|
.btn-super-upload {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.btn-super-upload-busy {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unprogress {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
display: none;
|
||||||
|
width: 200px;
|
||||||
|
height: 10px;
|
||||||
|
background: #666;
|
||||||
|
border-radius: $baseRadius;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
border-radius: $baseRadius;
|
||||||
|
background-color: $seaBlue;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percent {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
top: 2px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 0 0 2px black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uploading {
|
||||||
|
.progress {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unprogress {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -73,6 +73,7 @@ ul.explr-tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.explr-multiselection-actions,
|
||||||
.explr-selection-actions {
|
.explr-selection-actions {
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -107,6 +108,28 @@ body.explr-selection-actionable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.explr-multiselection-actionable {
|
||||||
|
.explr-multiselection-actions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.explr-multiselection-folder {
|
||||||
|
.explr-multiselection-actions {
|
||||||
|
button.explr-multiselection-folder {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.explr-multiselection-entity {
|
||||||
|
.explr-multiselection-actions {
|
||||||
|
button.explr-multiselection-entity {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ul.explr-dirview {
|
ul.explr-dirview {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -119,9 +142,9 @@ ul.explr-dirview {
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 18px;
|
margin: 10px 10px;
|
||||||
min-width: 90px;
|
min-width: 100px;
|
||||||
min-height: 104px;
|
min-height: 130px;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: $baseRadius;
|
border-radius: $baseRadius;
|
||||||
@ -162,6 +185,35 @@ ul.explr-dirview {
|
|||||||
min-width: 84px;
|
min-width: 84px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
&.with-thumbnail {
|
||||||
|
|
||||||
|
.img-holder {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
background: #070707;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 24px;
|
||||||
|
position: absolute;
|
||||||
|
top: -4px;
|
||||||
|
left: 0;
|
||||||
|
text-shadow: 0 .5px .5px #777;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: 64px;
|
font-size: 64px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
|||||||
@ -10,3 +10,12 @@
|
|||||||
left: 27px;
|
left: 27px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes shakednd {
|
||||||
|
0% {
|
||||||
|
transform: rotate(-2deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(2deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
@import 'components/breadcrumb';
|
@import 'components/breadcrumb';
|
||||||
@import 'components/modals';
|
@import 'components/modals';
|
||||||
@import 'components/toast';
|
@import 'components/toast';
|
||||||
|
@import 'components/dragdrop';
|
||||||
|
|
||||||
// Legacy
|
// Legacy
|
||||||
@import 'components/panes';
|
@import 'components/panes';
|
||||||
|
|||||||
@ -1,9 +1,29 @@
|
|||||||
|
|
||||||
.view-content-list main .main-container {
|
.view-content-list {
|
||||||
|
main .main-container {
|
||||||
|
.page-content {
|
||||||
|
.inner {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
.dropzone {
|
||||||
|
flex: 1;
|
||||||
|
align-self: stretch;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.content-object-input {
|
.content-object-input {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dragover {
|
||||||
|
main .main-container .inner .dropzone {
|
||||||
|
border-radius: $baseRadius;
|
||||||
|
background: rgba($white, .1);
|
||||||
|
border: 1px dashed rgba($white, .5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -244,6 +244,8 @@
|
|||||||
"common_copied": "Element copied in clipboard!",
|
"common_copied": "Element copied in clipboard!",
|
||||||
"common_host_placeholder": "raspberrypi.local or 192.168.1.85",
|
"common_host_placeholder": "raspberrypi.local or 192.168.1.85",
|
||||||
"common_reachable_at": "Host",
|
"common_reachable_at": "Host",
|
||||||
|
"common_http_error_occured": "Error %code% occured",
|
||||||
|
"common_http_error_413": "Files are too large",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"login_error_not_found": "Bad credentials",
|
"login_error_not_found": "Bad credentials",
|
||||||
"login_error_bad_credentials": "Bad credentials",
|
"login_error_bad_credentials": "Bad credentials",
|
||||||
@ -300,5 +302,6 @@
|
|||||||
"sysinfo_network_interface": "Network Interface",
|
"sysinfo_network_interface": "Network Interface",
|
||||||
"sysinfo_mac_address": "MAC Address",
|
"sysinfo_mac_address": "MAC Address",
|
||||||
"sysinfo_ip_address": "IP Address",
|
"sysinfo_ip_address": "IP Address",
|
||||||
"player_default_welcome_message": "To manage this player, go to a browser at"
|
"player_default_welcome_message": "To manage this player, go to a browser at",
|
||||||
|
"player_noplaylist_welcome_message": "No playlist is configured by default, go to a browser at"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -245,6 +245,8 @@
|
|||||||
"common_copied": "¡Elemento copiado!",
|
"common_copied": "¡Elemento copiado!",
|
||||||
"common_host_placeholder": "raspberrypi.local o 192.168.1.85",
|
"common_host_placeholder": "raspberrypi.local o 192.168.1.85",
|
||||||
"common_reachable_at": "Host",
|
"common_reachable_at": "Host",
|
||||||
|
"common_http_error_occured": "Se ha producido un error %code%",
|
||||||
|
"common_http_error_413": "Los archivos son demasiado grandes",
|
||||||
"logout": "Cerrar sesión",
|
"logout": "Cerrar sesión",
|
||||||
"login_error_not_found": "Credenciales incorrectas",
|
"login_error_not_found": "Credenciales incorrectas",
|
||||||
"login_error_bad_credentials": "Credenciales incorrectas",
|
"login_error_bad_credentials": "Credenciales incorrectas",
|
||||||
@ -301,5 +303,6 @@
|
|||||||
"sysinfo_network_interface": "Interfaz de red",
|
"sysinfo_network_interface": "Interfaz de red",
|
||||||
"sysinfo_mac_address": "Dirección MAC",
|
"sysinfo_mac_address": "Dirección MAC",
|
||||||
"sysinfo_ip_address": "Dirección IP",
|
"sysinfo_ip_address": "Dirección IP",
|
||||||
"player_default_welcome_message": "Para gestionar este reproductor, ve a un navegador en"
|
"player_default_welcome_message": "Para gestionar este reproductor, ve a un navegador en",
|
||||||
|
"player_noplaylist_welcome_message": "No hay ninguna playlist configurada de forma predeterminada, vaya a un navegador en"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -246,6 +246,8 @@
|
|||||||
"common_copied": "Element copié !",
|
"common_copied": "Element copié !",
|
||||||
"common_host_placeholder": "raspberrypi.local ou 192.168.1.85",
|
"common_host_placeholder": "raspberrypi.local ou 192.168.1.85",
|
||||||
"common_reachable_at": "Hôte",
|
"common_reachable_at": "Hôte",
|
||||||
|
"common_http_error_occured": "Une erreur %code% est apparue",
|
||||||
|
"common_http_error_413": "Les fichiers sont trop volumineux",
|
||||||
"logout": "Déconnexion",
|
"logout": "Déconnexion",
|
||||||
"login_error_not_found": "Identifiants invalides",
|
"login_error_not_found": "Identifiants invalides",
|
||||||
"login_error_bad_credentials": "Identifiants invalides",
|
"login_error_bad_credentials": "Identifiants invalides",
|
||||||
@ -302,5 +304,6 @@
|
|||||||
"sysinfo_network_interface": "Interface Réseau",
|
"sysinfo_network_interface": "Interface Réseau",
|
||||||
"sysinfo_mac_address": "Addresse MAC",
|
"sysinfo_mac_address": "Addresse MAC",
|
||||||
"sysinfo_ip_address": "Addresse IP",
|
"sysinfo_ip_address": "Addresse IP",
|
||||||
"player_default_welcome_message": "Pour gérer ce lecteur, allez sur un navigateur à l'adresse"
|
"player_default_welcome_message": "Pour gérer ce lecteur, allez sur un navigateur à l'adresse",
|
||||||
|
"player_noplaylist_welcome_message": "Aucune playlist n'est configurée par défaut, allez sur un navigateur à l'adresse"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -245,6 +245,8 @@
|
|||||||
"common_copied": "Elemento copiato!",
|
"common_copied": "Elemento copiato!",
|
||||||
"common_host_placeholder": "raspberrypi.local o 192.168.1.85",
|
"common_host_placeholder": "raspberrypi.local o 192.168.1.85",
|
||||||
"common_reachable_at": "Host",
|
"common_reachable_at": "Host",
|
||||||
|
"common_http_error_occured": "Si è verificato un errore %code%",
|
||||||
|
"common_http_error_413": "I file sono troppo grandi",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"login_error_not_found": "Credenziali errate",
|
"login_error_not_found": "Credenziali errate",
|
||||||
"login_error_bad_credentials": "Credenziali errate",
|
"login_error_bad_credentials": "Credenziali errate",
|
||||||
@ -301,5 +303,6 @@
|
|||||||
"sysinfo_network_interface": "interfaccia di rete",
|
"sysinfo_network_interface": "interfaccia di rete",
|
||||||
"sysinfo_mac_address": "Indirizzo MAC",
|
"sysinfo_mac_address": "Indirizzo MAC",
|
||||||
"sysinfo_ip_address": "indirizzo IP",
|
"sysinfo_ip_address": "indirizzo IP",
|
||||||
"player_default_welcome_message": "Per gestire questo lettore, vai al browser all'indirizzo"
|
"player_default_welcome_message": "Per gestire questo lettore, vai al browser all'indirizzo",
|
||||||
|
"player_noplaylist_welcome_message": "Nessuna playlist è configurata per impostazione predefinita, vai su un browser all'indirizzo"
|
||||||
}
|
}
|
||||||
@ -28,11 +28,25 @@ class ContentController(ObController):
|
|||||||
self._app.add_url_rule('/slideshow/content/rename-folder', 'slideshow_content_folder_rename', self._auth(self.slideshow_content_folder_rename), methods=['POST'])
|
self._app.add_url_rule('/slideshow/content/rename-folder', 'slideshow_content_folder_rename', self._auth(self.slideshow_content_folder_rename), methods=['POST'])
|
||||||
self._app.add_url_rule('/slideshow/content/delete-folder', 'slideshow_content_folder_delete', self._auth(self.slideshow_content_folder_delete), methods=['GET'])
|
self._app.add_url_rule('/slideshow/content/delete-folder', 'slideshow_content_folder_delete', self._auth(self.slideshow_content_folder_delete), methods=['GET'])
|
||||||
self._app.add_url_rule('/slideshow/content/show/<content_id>', 'slideshow_content_show', self._auth(self.slideshow_content_show), methods=['GET'])
|
self._app.add_url_rule('/slideshow/content/show/<content_id>', 'slideshow_content_show', self._auth(self.slideshow_content_show), methods=['GET'])
|
||||||
|
self._app.add_url_rule('/slideshow/content/upload-bulk', 'slideshow_content_upload_bulk', self._auth(self.slideshow_content_upload_bulk), methods=['POST'])
|
||||||
|
self._app.add_url_rule('/slideshow/content/delete-bulk-explr', 'slideshow_content_delete_bulk_explr', self._auth(self.slideshow_content_delete_bulk_explr), methods=['GET'])
|
||||||
|
|
||||||
|
def get_working_folder(self):
|
||||||
|
working_folder_path = request.args.get('path', None)
|
||||||
|
working_folder = None
|
||||||
|
|
||||||
|
if working_folder_path:
|
||||||
|
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.CONTENT)
|
||||||
|
|
||||||
|
if not working_folder:
|
||||||
|
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_content').as_string()
|
||||||
|
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.CONTENT)
|
||||||
|
|
||||||
|
return working_folder_path, working_folder
|
||||||
|
|
||||||
def slideshow_content_list(self):
|
def slideshow_content_list(self):
|
||||||
self._model_store.variable().update_by_name('last_pillmenu_slideshow', 'slideshow_content_list')
|
self._model_store.variable().update_by_name('last_pillmenu_slideshow', 'slideshow_content_list')
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_content').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.CONTENT)
|
|
||||||
slides_with_content = self._model_store.slide().get_all_indexed(attribute='content_id', multiple=True)
|
slides_with_content = self._model_store.slide().get_all_indexed(attribute='content_id', multiple=True)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
@ -48,8 +62,7 @@ class ContentController(ObController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def slideshow_content_add(self):
|
def slideshow_content_add(self):
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_content').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.CONTENT)
|
|
||||||
|
|
||||||
self._model_store.content().add_form_raw(
|
self._model_store.content().add_form_raw(
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
@ -60,7 +73,24 @@ class ContentController(ObController):
|
|||||||
folder_id=working_folder.id if working_folder else None
|
folder_id=working_folder.id if working_folder else None
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
|
def slideshow_content_upload_bulk(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
|
file = request.files['object']
|
||||||
|
type = ContentType.guess_content_type_file(file)
|
||||||
|
name = file.filename.rsplit('.', 1)[0]
|
||||||
|
|
||||||
|
self._model_store.content().add_form_raw(
|
||||||
|
name=name,
|
||||||
|
type=type,
|
||||||
|
request_files=request.files,
|
||||||
|
upload_dir=self._app.config['UPLOAD_FOLDER'],
|
||||||
|
folder_id=working_folder.id if working_folder else None
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
def slideshow_content_edit(self, content_id: int = 0):
|
def slideshow_content_edit(self, content_id: int = 0):
|
||||||
content = self._model_store.content().get(content_id)
|
content = self._model_store.content().get(content_id)
|
||||||
@ -68,8 +98,7 @@ class ContentController(ObController):
|
|||||||
if not content:
|
if not content:
|
||||||
return abort(404)
|
return abort(404)
|
||||||
|
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_content').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.CONTENT)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'slideshow/contents/edit.jinja.html',
|
'slideshow/contents/edit.jinja.html',
|
||||||
@ -80,10 +109,11 @@ class ContentController(ObController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def slideshow_content_save(self, content_id: int = 0):
|
def slideshow_content_save(self, content_id: int = 0):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
content = self._model_store.content().get(content_id)
|
content = self._model_store.content().get(content_id)
|
||||||
|
|
||||||
if not content:
|
if not content:
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
self._model_store.content().update_form(
|
self._model_store.content().update_form(
|
||||||
id=content.id,
|
id=content.id,
|
||||||
@ -95,27 +125,25 @@ class ContentController(ObController):
|
|||||||
return redirect(url_for('slideshow_content_edit', content_id=content_id, saved=1))
|
return redirect(url_for('slideshow_content_edit', content_id=content_id, saved=1))
|
||||||
|
|
||||||
def slideshow_content_delete(self):
|
def slideshow_content_delete(self):
|
||||||
content = self._model_store.content().get(request.args.get('id'))
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
error_tuple = self.delete_content_by_id(request.args.get('id'))
|
||||||
|
route_args = {
|
||||||
|
"path": working_folder_path,
|
||||||
|
}
|
||||||
|
|
||||||
if not content:
|
if error_tuple:
|
||||||
return redirect(url_for('slideshow_content_list'))
|
route_args[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
slide_counter = self._model_store.slide().count_slides_for_content(content.id)
|
return redirect(url_for('slideshow_content_list', **route_args))
|
||||||
|
|
||||||
if slide_counter > 0:
|
|
||||||
return redirect(url_for('slideshow_content_list', referenced_in_slide_error=True))
|
|
||||||
|
|
||||||
self._model_store.content().delete(content.id)
|
|
||||||
self._post_update()
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
|
||||||
|
|
||||||
def slideshow_content_rename(self):
|
def slideshow_content_rename(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
self._model_store.content().update_form(
|
self._model_store.content().update_form(
|
||||||
id=request.form['id'],
|
id=request.form['id'],
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
def slideshow_content_cd(self):
|
def slideshow_content_cd(self):
|
||||||
path = request.args.get('path')
|
path = request.args.get('path')
|
||||||
@ -140,46 +168,46 @@ class ContentController(ObController):
|
|||||||
return redirect(url_for('slideshow_content_list', path=path))
|
return redirect(url_for('slideshow_content_list', path=path))
|
||||||
|
|
||||||
def slideshow_content_folder_add(self):
|
def slideshow_content_folder_add(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
self._model_store.folder().add_folder(
|
self._model_store.folder().add_folder(
|
||||||
entity=FolderEntity.CONTENT,
|
entity=FolderEntity.CONTENT,
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
working_folder_path=request.form['working_folder_path'],
|
working_folder_path=working_folder_path
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
def slideshow_content_folder_rename(self):
|
def slideshow_content_folder_rename(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
self._model_store.folder().rename_folder(
|
self._model_store.folder().rename_folder(
|
||||||
folder_id=request.form['id'],
|
folder_id=request.form['id'],
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
def slideshow_content_folder_move(self):
|
def slideshow_content_folder_move(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
self._model_store.folder().move_to_folder(
|
self._model_store.folder().move_to_folder(
|
||||||
entity_id=request.form['entity_id'],
|
entity_id=request.form['entity_id'],
|
||||||
folder_id=request.form['new_folder_id'],
|
folder_id=request.form['new_folder_id'],
|
||||||
entity_is_folder=True if 'is_folder' in request.form and request.form['is_folder'] == '1' else False,
|
entity_is_folder=True if 'is_folder' in request.form and request.form['is_folder'] == '1' else False,
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
return redirect(url_for('slideshow_content_list', path=working_folder_path))
|
||||||
|
|
||||||
def slideshow_content_folder_delete(self):
|
def slideshow_content_folder_delete(self):
|
||||||
folder = self._model_store.folder().get(request.args.get('id'))
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
error_tuple = self.delete_folder_by_id(request.args.get('id'))
|
||||||
|
route_args = {
|
||||||
|
"path": working_folder_path,
|
||||||
|
}
|
||||||
|
|
||||||
if not folder:
|
if error_tuple:
|
||||||
return redirect(url_for('slideshow_content_list'))
|
route_args[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
content_counter = self._model_store.content().count_contents_for_folder(folder.id)
|
return redirect(url_for('slideshow_content_list', **route_args))
|
||||||
folder_counter = self._model_store.folder().count_subfolders_for_folder(folder.id)
|
|
||||||
|
|
||||||
if content_counter > 0 or folder_counter:
|
|
||||||
return redirect(url_for('slideshow_content_list', folder_not_empty_error=True))
|
|
||||||
|
|
||||||
self._model_store.folder().delete(id=folder.id)
|
|
||||||
|
|
||||||
return redirect(url_for('slideshow_content_list'))
|
|
||||||
|
|
||||||
def slideshow_content_show(self, content_id: int = 0):
|
def slideshow_content_show(self, content_id: int = 0):
|
||||||
content = self._model_store.content().get(content_id)
|
content = self._model_store.content().get(content_id)
|
||||||
@ -201,6 +229,57 @@ class ContentController(ObController):
|
|||||||
|
|
||||||
return redirect(location)
|
return redirect(location)
|
||||||
|
|
||||||
|
def slideshow_content_delete_bulk_explr(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
entity_ids = request.args.get('entity_ids', '').split(',')
|
||||||
|
folder_ids = request.args.get('folder_ids', '').split(',')
|
||||||
|
route_args_dict = {"path": working_folder_path}
|
||||||
|
|
||||||
|
for id in entity_ids:
|
||||||
|
if id:
|
||||||
|
error_tuple = self.delete_content_by_id(id)
|
||||||
|
|
||||||
|
if error_tuple:
|
||||||
|
route_args_dict[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
|
for id in folder_ids:
|
||||||
|
if id:
|
||||||
|
error_tuple = self.delete_folder_by_id(id)
|
||||||
|
|
||||||
|
if error_tuple:
|
||||||
|
route_args_dict[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
|
return redirect(url_for('slideshow_content_list', **route_args_dict))
|
||||||
|
|
||||||
|
def delete_content_by_id(self, id):
|
||||||
|
content = self._model_store.content().get(id)
|
||||||
|
|
||||||
|
if not content:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self._model_store.slide().count_slides_for_content(content.id) > 0:
|
||||||
|
return 'referenced_in_slide_error', content.name
|
||||||
|
|
||||||
|
self._model_store.content().delete(content.id)
|
||||||
|
self._post_update()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete_folder_by_id(self, id):
|
||||||
|
folder = self._model_store.folder().get(id)
|
||||||
|
|
||||||
|
if not folder:
|
||||||
|
return None
|
||||||
|
|
||||||
|
content_counter = self._model_store.content().count_contents_for_folder(folder.id)
|
||||||
|
folder_counter = self._model_store.folder().count_subfolders_for_folder(folder.id)
|
||||||
|
|
||||||
|
if content_counter > 0 or folder_counter:
|
||||||
|
return 'folder_not_empty_error', folder.name
|
||||||
|
|
||||||
|
self._model_store.folder().delete(id=folder.id)
|
||||||
|
self._post_update()
|
||||||
|
return None
|
||||||
|
|
||||||
def _post_update(self):
|
def _post_update(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@ -31,11 +31,24 @@ class FleetNodePlayerController(ObController):
|
|||||||
self._app.add_url_rule('/fleet/node-player/move-folder', 'fleet_node_player_folder_move', self._auth(self.fleet_node_player_folder_move), methods=['POST'])
|
self._app.add_url_rule('/fleet/node-player/move-folder', 'fleet_node_player_folder_move', self._auth(self.fleet_node_player_folder_move), methods=['POST'])
|
||||||
self._app.add_url_rule('/fleet/node-player/rename-folder', 'fleet_node_player_folder_rename', self._auth(self.fleet_node_player_folder_rename), methods=['POST'])
|
self._app.add_url_rule('/fleet/node-player/rename-folder', 'fleet_node_player_folder_rename', self._auth(self.fleet_node_player_folder_rename), methods=['POST'])
|
||||||
self._app.add_url_rule('/fleet/node-player/delete-folder', 'fleet_node_player_folder_delete', self._auth(self.fleet_node_player_folder_delete), methods=['GET'])
|
self._app.add_url_rule('/fleet/node-player/delete-folder', 'fleet_node_player_folder_delete', self._auth(self.fleet_node_player_folder_delete), methods=['GET'])
|
||||||
|
self._app.add_url_rule('/fleet/node-player/delete-bulk-explr', 'fleet_node_player_delete_bulk_explr', self._auth(self.fleet_node_player_delete_bulk_explr), methods=['GET'])
|
||||||
|
|
||||||
|
def get_working_folder(self):
|
||||||
|
working_folder_path = request.args.get('path', None)
|
||||||
|
working_folder = None
|
||||||
|
|
||||||
|
if working_folder_path:
|
||||||
|
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.NODE_PLAYER)
|
||||||
|
|
||||||
|
if not working_folder:
|
||||||
|
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_node_player').as_string()
|
||||||
|
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.NODE_PLAYER)
|
||||||
|
|
||||||
|
return working_folder_path, working_folder
|
||||||
|
|
||||||
def fleet_node_player_list(self):
|
def fleet_node_player_list(self):
|
||||||
self._model_store.variable().update_by_name('last_pillmenu_fleet', 'fleet_node_player_list')
|
self._model_store.variable().update_by_name('last_pillmenu_fleet', 'fleet_node_player_list')
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_node_player').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.NODE_PLAYER)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'fleet/node-players/list.jinja.html',
|
'fleet/node-players/list.jinja.html',
|
||||||
@ -50,8 +63,7 @@ class FleetNodePlayerController(ObController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def fleet_node_player_add(self):
|
def fleet_node_player_add(self):
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_node_player').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.NODE_PLAYER)
|
|
||||||
|
|
||||||
self._model_store.node_player().add_form(
|
self._model_store.node_player().add_form(
|
||||||
NodePlayer(
|
NodePlayer(
|
||||||
@ -62,7 +74,7 @@ class FleetNodePlayerController(ObController):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_edit(self, node_player_id: int = 0):
|
def fleet_node_player_edit(self, node_player_id: int = 0):
|
||||||
node_player = self._model_store.node_player().get(node_player_id)
|
node_player = self._model_store.node_player().get(node_player_id)
|
||||||
@ -70,8 +82,7 @@ class FleetNodePlayerController(ObController):
|
|||||||
if not node_player:
|
if not node_player:
|
||||||
return abort(404)
|
return abort(404)
|
||||||
|
|
||||||
working_folder_path = self._model_store.variable().get_one_by_name('last_folder_node_player').as_string()
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
working_folder = self._model_store.folder().get_one_by_path(path=working_folder_path, entity=FolderEntity.NODE_PLAYER)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'fleet/node-players/edit.jinja.html',
|
'fleet/node-players/edit.jinja.html',
|
||||||
@ -84,9 +95,10 @@ class FleetNodePlayerController(ObController):
|
|||||||
def fleet_node_player_save(self, node_player_id: int = 0):
|
def fleet_node_player_save(self, node_player_id: int = 0):
|
||||||
node_player_id = request.form['id'] if 'id' in request.form else node_player_id
|
node_player_id = request.form['id'] if 'id' in request.form else node_player_id
|
||||||
node_player = self._model_store.node_player().get(node_player_id)
|
node_player = self._model_store.node_player().get(node_player_id)
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
if not node_player:
|
if not node_player:
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
self._model_store.node_player().update_form(
|
self._model_store.node_player().update_form(
|
||||||
id=node_player.id,
|
id=node_player.id,
|
||||||
@ -97,25 +109,28 @@ class FleetNodePlayerController(ObController):
|
|||||||
self._post_update()
|
self._post_update()
|
||||||
|
|
||||||
# return redirect(url_for('fleet_node_player_edit', node_player_id=node_player_id, saved=1))
|
# return redirect(url_for('fleet_node_player_edit', node_player_id=node_player_id, saved=1))
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_delete(self):
|
def fleet_node_player_delete(self):
|
||||||
node_player = self._model_store.node_player().get(request.args.get('id'))
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
error_tuple = self.delete_node_player_by_id(request.args.get('id'))
|
||||||
|
route_args = {
|
||||||
|
"path": working_folder_path,
|
||||||
|
}
|
||||||
|
|
||||||
if not node_player:
|
if error_tuple:
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
route_args[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
self._model_store.node_player().delete(node_player.id)
|
return redirect(url_for('fleet_node_player_list', **route_args))
|
||||||
self._post_update()
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
|
||||||
|
|
||||||
def fleet_node_player_rename(self):
|
def fleet_node_player_rename(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
self._model_store.node_player().update_form(
|
self._model_store.node_player().update_form(
|
||||||
id=request.form['id'],
|
id=request.form['id'],
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_cd(self):
|
def fleet_node_player_cd(self):
|
||||||
path = request.args.get('path')
|
path = request.args.get('path')
|
||||||
@ -140,46 +155,96 @@ class FleetNodePlayerController(ObController):
|
|||||||
return redirect(url_for('fleet_node_player_list', path=path))
|
return redirect(url_for('fleet_node_player_list', path=path))
|
||||||
|
|
||||||
def fleet_node_player_folder_add(self):
|
def fleet_node_player_folder_add(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
self._model_store.folder().add_folder(
|
self._model_store.folder().add_folder(
|
||||||
entity=FolderEntity.NODE_PLAYER,
|
entity=FolderEntity.NODE_PLAYER,
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
working_folder_path=request.form['working_folder_path'],
|
working_folder_path=working_folder_path
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_folder_rename(self):
|
def fleet_node_player_folder_rename(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
self._model_store.folder().rename_folder(
|
self._model_store.folder().rename_folder(
|
||||||
folder_id=request.form['id'],
|
folder_id=request.form['id'],
|
||||||
name=request.form['name'],
|
name=request.form['name'],
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_folder_move(self):
|
def fleet_node_player_folder_move(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
|
||||||
self._model_store.folder().move_to_folder(
|
self._model_store.folder().move_to_folder(
|
||||||
entity_id=request.form['entity_id'],
|
entity_id=request.form['entity_id'],
|
||||||
folder_id=request.form['new_folder_id'],
|
folder_id=request.form['new_folder_id'],
|
||||||
entity_is_folder=True if 'is_folder' in request.form and request.form['is_folder'] == '1' else False,
|
entity_is_folder=True if 'is_folder' in request.form and request.form['is_folder'] == '1' else False,
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return redirect(url_for('fleet_node_player_list', path=working_folder_path))
|
||||||
|
|
||||||
def fleet_node_player_folder_delete(self):
|
def fleet_node_player_folder_delete(self):
|
||||||
folder = self._model_store.folder().get(request.args.get('id'))
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
error_tuple = self.delete_folder_by_id(request.args.get('id'))
|
||||||
|
route_args = {
|
||||||
|
"path": working_folder_path,
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_tuple:
|
||||||
|
route_args[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
|
return redirect(url_for('fleet_node_player_list', **route_args))
|
||||||
|
|
||||||
|
def fleet_node_player_delete_bulk_explr(self):
|
||||||
|
working_folder_path, working_folder = self.get_working_folder()
|
||||||
|
entity_ids = request.args.get('entity_ids', '').split(',')
|
||||||
|
folder_ids = request.args.get('folder_ids', '').split(',')
|
||||||
|
route_args_dict = {"path": working_folder_path}
|
||||||
|
|
||||||
|
for id in entity_ids:
|
||||||
|
if id:
|
||||||
|
error_tuple = self.delete_node_player_by_id(id)
|
||||||
|
|
||||||
|
if error_tuple:
|
||||||
|
route_args_dict[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
|
for id in folder_ids:
|
||||||
|
if id:
|
||||||
|
error_tuple = self.delete_folder_by_id(id)
|
||||||
|
|
||||||
|
if error_tuple:
|
||||||
|
route_args_dict[error_tuple[0]] = error_tuple[1]
|
||||||
|
|
||||||
|
return redirect(url_for('fleet_node_player_list', **route_args_dict))
|
||||||
|
|
||||||
|
def delete_node_player_by_id(self, id):
|
||||||
|
node_player = self._model_store.node_player().get(id)
|
||||||
|
|
||||||
|
if not node_player:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self._model_store.node_player().delete(node_player.id)
|
||||||
|
self._post_update()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def delete_folder_by_id(self, id):
|
||||||
|
folder = self._model_store.folder().get(id)
|
||||||
|
|
||||||
if not folder:
|
if not folder:
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return None
|
||||||
|
|
||||||
node_player_counter = self._model_store.node_player().count_node_players_for_folder(folder.id)
|
node_player_counter = self._model_store.node_player().count_node_players_for_folder(folder.id)
|
||||||
folder_counter = self._model_store.folder().count_subfolders_for_folder(folder.id)
|
folder_counter = self._model_store.folder().count_subfolders_for_folder(folder.id)
|
||||||
|
|
||||||
if node_player_counter > 0 or folder_counter:
|
if node_player_counter > 0 or folder_counter:
|
||||||
return redirect(url_for('fleet_node_player_list', folder_not_empty_error=True))
|
return 'folder_not_empty_error', folder.name
|
||||||
|
|
||||||
self._model_store.folder().delete(id=folder.id)
|
self._model_store.folder().delete(id=folder.id)
|
||||||
|
|
||||||
return redirect(url_for('fleet_node_player_list'))
|
return None
|
||||||
|
|
||||||
def _post_update(self):
|
def _post_update(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class PlayerController(ObController):
|
|||||||
try:
|
try:
|
||||||
items = self._get_playlist(playlist_id=playlist_id, preview_content_id=preview_content_id)
|
items = self._get_playlist(playlist_id=playlist_id, preview_content_id=preview_content_id)
|
||||||
except NoFallbackPlaylistException:
|
except NoFallbackPlaylistException:
|
||||||
abort(404)
|
return redirect(url_for('player_default', noplaylist=1))
|
||||||
|
|
||||||
intro_slide_duration = 0 if items['preview_mode'] else int(request.args.get('intro', self._model_store.variable().get_one_by_name('intro_slide_duration').eval()))
|
intro_slide_duration = 0 if items['preview_mode'] else int(request.args.get('intro', self._model_store.variable().get_one_by_name('intro_slide_duration').eval()))
|
||||||
animation_enabled = bool(request.args.get('animation', int(self._model_store.variable().get_one_by_name('slide_animation_enabled').eval())))
|
animation_enabled = bool(request.args.get('animation', int(self._model_store.variable().get_one_by_name('slide_animation_enabled').eval())))
|
||||||
@ -64,7 +64,8 @@ class PlayerController(ObController):
|
|||||||
return render_template(
|
return render_template(
|
||||||
'player/default.jinja.html',
|
'player/default.jinja.html',
|
||||||
interfaces=[iface['ip_address'] for iface in get_network_interfaces()],
|
interfaces=[iface['ip_address'] for iface in get_network_interfaces()],
|
||||||
time_with_seconds=self._model_store.variable().get_one_by_name('default_slide_time_with_seconds')
|
time_with_seconds=self._model_store.variable().get_one_by_name('default_slide_time_with_seconds'),
|
||||||
|
noplaylist=request.args.get('noplaylist', '0') == '1'
|
||||||
)
|
)
|
||||||
|
|
||||||
def player_playlist(self, playlist_slug_or_id: str = ''):
|
def player_playlist(self, playlist_slug_or_id: str = ''):
|
||||||
|
|||||||
@ -73,9 +73,10 @@ class DatabaseManager:
|
|||||||
sanitized_params.append(param)
|
sanitized_params.append(param)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._conn:
|
self._conn.execute('BEGIN')
|
||||||
cur = self._conn.cursor()
|
cur = self._conn.cursor()
|
||||||
cur.execute(query, tuple(sanitized_params))
|
cur.execute(query, tuple(sanitized_params))
|
||||||
|
self._conn.commit()
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
if not silent_errors:
|
if not silent_errors:
|
||||||
logging.error("SQL query execution error while writing '{}': {}".format(query, e))
|
logging.error("SQL query execution error while writing '{}': {}".format(query, e))
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
import mimetypes
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Union
|
from typing import Union, List, Optional
|
||||||
|
|
||||||
from src.util.utils import str_to_enum
|
from src.util.utils import str_to_enum
|
||||||
|
|
||||||
|
|
||||||
class ContentInputType(Enum):
|
class ContentInputType(Enum):
|
||||||
|
|
||||||
UPLOAD = 'upload'
|
UPLOAD = 'upload'
|
||||||
@ -23,6 +26,25 @@ class ContentType(Enum):
|
|||||||
YOUTUBE = 'youtube'
|
YOUTUBE = 'youtube'
|
||||||
VIDEO = 'video'
|
VIDEO = 'video'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def guess_content_type_file(file):
|
||||||
|
mime_type, _ = mimetypes.guess_type(file.filename)
|
||||||
|
|
||||||
|
if mime_type in [
|
||||||
|
'image/gif',
|
||||||
|
'image/png',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/webp',
|
||||||
|
'image/jpg'
|
||||||
|
]:
|
||||||
|
return ContentType.PICTURE
|
||||||
|
elif mime_type in [
|
||||||
|
'video/mp4'
|
||||||
|
]:
|
||||||
|
return ContentType.VIDEO
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_input(value: Enum) -> ContentInputType:
|
def get_input(value: Enum) -> ContentInputType:
|
||||||
if value == ContentType.PICTURE:
|
if value == ContentType.PICTURE:
|
||||||
|
|||||||
@ -44,8 +44,16 @@
|
|||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn explr-item-delete explr-selection-entity explr-selection-folder btn-danger-alt"
|
class="btn explr-item-delete explr-selection-entity explr-selection-folder btn-danger-alt"
|
||||||
data-folder-route="{{ url_for('fleet_node_player_folder_delete') }}"
|
data-folder-route="{{ url_for('fleet_node_player_folder_delete') }}?path={{ working_folder_path }}"
|
||||||
data-entity-route="{{ url_for('fleet_node_player_delete') }}">
|
data-entity-route="{{ url_for('fleet_node_player_delete') }}?path={{ working_folder_path }}">
|
||||||
|
<i class="fa fa-trash-alt"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="explr-multiselection-actions">
|
||||||
|
<button type="button"
|
||||||
|
class="btn explr-items-delete explr-multiselection-entity explr-multiselection-folder btn-danger-alt"
|
||||||
|
data-route="{{ url_for('fleet_node_player_delete_bulk_explr') }}?path={{ working_folder_path }}">
|
||||||
<i class="fa fa-trash-alt"></i>
|
<i class="fa fa-trash-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -114,8 +122,7 @@
|
|||||||
<li class="new-folder hidden">
|
<li class="new-folder hidden">
|
||||||
<a href="javascript:void(0);">
|
<a href="javascript:void(0);">
|
||||||
<i class="fa fa-folder"></i>
|
<i class="fa fa-folder"></i>
|
||||||
<form action="{{ url_for('fleet_node_player_folder_add') }}" method="POST">
|
<form action="{{ url_for('fleet_node_player_folder_add') }}?path={{ working_folder_path }}" method="POST">
|
||||||
<input type="hidden" name="working_folder_path" value="{{ working_folder_path }}" />
|
|
||||||
<input type="text" name="name" autocomplete="off"/>
|
<input type="text" name="name" autocomplete="off"/>
|
||||||
</form>
|
</form>
|
||||||
</a>
|
</a>
|
||||||
@ -141,7 +148,7 @@
|
|||||||
class="explr-link explr-item-selectable explr-item-actionable explr-item-folder">
|
class="explr-link explr-item-selectable explr-item-actionable explr-item-folder">
|
||||||
<i class="fa fa-folder"></i>
|
<i class="fa fa-folder"></i>
|
||||||
<span>{{ truncate(folder.name, explr_limit_chars, '...') }}</span>
|
<span>{{ truncate(folder.name, explr_limit_chars, '...') }}</span>
|
||||||
<form action="{{ url_for('fleet_node_player_folder_rename') }}" method="POST">
|
<form action="{{ url_for('fleet_node_player_folder_rename') }}?path={{ working_folder_path }}" method="POST">
|
||||||
<input type="text" name="name" value="{{ folder.name }}" autocomplete="off"/>
|
<input type="text" name="name" value="{{ folder.name }}" autocomplete="off"/>
|
||||||
<input type="hidden" name="id" value="{{ folder.id }}"/>
|
<input type="hidden" name="id" value="{{ folder.id }}"/>
|
||||||
</form>
|
</form>
|
||||||
@ -166,7 +173,7 @@
|
|||||||
</sub>
|
</sub>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span>{{ truncate(node_player.name, explr_limit_chars, '...') }}</span>
|
<span>{{ truncate(node_player.name, explr_limit_chars, '...') }}</span>
|
||||||
<form action="{{ url_for('fleet_node_player_rename') }}" method="POST">
|
<form action="{{ url_for('fleet_node_player_rename') }}?path={{ working_folder_path }}" method="POST">
|
||||||
<input type="text" name="name" value="{{ node_player.name }}" autocomplete="off"/>
|
<input type="text" name="name" value="{{ node_player.name }}" autocomplete="off"/>
|
||||||
<input type="hidden" name="id" value="{{ node_player.id }}"/>
|
<input type="hidden" name="id" value="{{ node_player.id }}"/>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -63,7 +63,7 @@
|
|||||||
<script>
|
<script>
|
||||||
const interfaces = {{ json_dumps(interfaces) | safe }};
|
const interfaces = {{ json_dumps(interfaces) | safe }};
|
||||||
const translation_common_unknown_ipaddr = '{{ l.common_unknown_ipaddr }}';
|
const translation_common_unknown_ipaddr = '{{ l.common_unknown_ipaddr }}';
|
||||||
const translation_player_default_welcome_message = '{{ l.player_default_welcome_message }}';
|
const translation_player_default_welcome_message = '{% if noplaylist %}{{ l.player_noplaylist_welcome_message }}{% else %}{{ l.player_default_welcome_message }}{% endif %}';
|
||||||
const manage_url_template = '{{ 'http://%ipaddr%:' ~ PORT ~ url_for('manage') }}';
|
const manage_url_template = '{{ 'http://%ipaddr%:' ~ PORT ~ url_for('manage') }}';
|
||||||
|
|
||||||
const setIps = function(ips) {
|
const setIps = function(ips) {
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
<div class="horizontal">
|
<div class="horizontal">
|
||||||
<div class="form-holder">
|
<div class="form-holder">
|
||||||
<form class="form" action="{{ url_for('slideshow_content_save', content_id=content.id) }}" method="POST">
|
<form class="form" action="{{ url_for('slideshow_content_save', content_id=content.id) }}?path={{ working_folder_path }}" method="POST">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="content-edit-name">{{ l.slideshow_content_form_label_name }}</label>
|
<label for="content-edit-name">{{ l.slideshow_content_form_label_name }}</label>
|
||||||
|
|||||||
@ -10,10 +10,18 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block add_js %}
|
{% block add_js %}
|
||||||
|
<script>
|
||||||
|
var l = $.extend(l, {
|
||||||
|
'js_common_http_error_occured': '{{ l.common_http_error_occured }}',
|
||||||
|
'js_common_http_error_413': '{{ l.common_http_error_413 }}'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script src="{{ STATIC_PREFIX }}js/lib/jquery-explr-1.4.js"></script>
|
<script src="{{ STATIC_PREFIX }}js/lib/jquery-explr-1.4.js"></script>
|
||||||
<script src="{{ STATIC_PREFIX }}js/explorer.js"></script>
|
<script src="{{ STATIC_PREFIX }}js/explorer.js"></script>
|
||||||
<script src="{{ STATIC_PREFIX }}js/slideshow/contents.js"></script>
|
<script src="{{ STATIC_PREFIX }}js/slideshow/contents.js"></script>
|
||||||
<script src="{{ STATIC_PREFIX }}js/lib/jquery-ui.min.js"></script>
|
<script src="{{ STATIC_PREFIX }}js/lib/jquery-ui.min.js"></script>
|
||||||
|
<script src="{{ STATIC_PREFIX }}js/lib/jquery-fileupload.js"></script>
|
||||||
|
<script src="{{ STATIC_PREFIX }}js/dragdrop.js"></script>
|
||||||
|
|
||||||
{{ HOOK(H_SLIDESHOW_CONTENT_JAVASCRIPT) }}
|
{{ HOOK(H_SLIDESHOW_CONTENT_JAVASCRIPT) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -27,27 +35,47 @@
|
|||||||
<div class="top-actions">
|
<div class="top-actions">
|
||||||
{{ HOOK(H_SLIDESHOW_CONTENT_TOOLBAR_ACTIONS_START) }}
|
{{ HOOK(H_SLIDESHOW_CONTENT_TOOLBAR_ACTIONS_START) }}
|
||||||
|
|
||||||
<button type="button" class="btn btn-info content-add item-add">
|
|
||||||
<i class="fa fa-file-circle-plus icon-left"></i>
|
|
||||||
{{ l.slideshow_content_button_add }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="folder-add btn-neutral">
|
<button type="button" class="folder-add btn-neutral">
|
||||||
<i class="fa fa-folder-plus icon-left"></i>
|
<i class="fa fa-folder-plus icon-left"></i>
|
||||||
{{ l.common_new_folder }}
|
{{ l.common_new_folder }}
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-info content-add item-add">
|
||||||
|
<i class="fa fa-file-circle-plus icon-left"></i>
|
||||||
|
{{ l.slideshow_content_button_add }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<a href="javascript:void(0);" class="btn btn-info btn-super-upload" data-route="{{ url_for('slideshow_content_upload_bulk') }}?path={{ working_folder_path }}">
|
||||||
|
<input type="file" id="content_files" name="object" class="hidden" multiple />
|
||||||
|
<div class="unprogress">
|
||||||
|
<i class="fa fa-bolt"></i>
|
||||||
|
</div>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:50%"></div>
|
||||||
|
<div class="percent">0%</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="explr-selection-actions">
|
<div class="explr-selection-actions">
|
||||||
<button type="button" class="btn explr-item-edit explr-selection-entity btn-info"
|
<button type="button" class="btn explr-item-edit explr-selection-entity btn-info"
|
||||||
data-entity-route="{{ url_for('slideshow_content_edit', content_id='!c!') }}">
|
data-entity-route="{{ url_for('slideshow_content_edit', content_id='!c!') }}">
|
||||||
<i class="fa fa-eye"></i>
|
<i class="fa fa-eye"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn explr-item-rename explr-selection-entity explr-selection-folder btn-info">
|
<button type="button"
|
||||||
|
class="btn explr-item-rename explr-selection-entity explr-selection-folder btn-info">
|
||||||
<i class="fa fa-pencil"></i>
|
<i class="fa fa-pencil"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="btn explr-item-delete explr-selection-entity explr-selection-folder btn-danger-alt"
|
class="btn explr-item-delete explr-selection-entity explr-selection-folder btn-danger-alt"
|
||||||
data-folder-route="{{ url_for('slideshow_content_folder_delete') }}"
|
data-folder-route="{{ url_for('slideshow_content_folder_delete') }}?path={{ working_folder_path }}"
|
||||||
data-entity-route="{{ url_for('slideshow_content_delete') }}">
|
data-entity-route="{{ url_for('slideshow_content_delete') }}?path={{ working_folder_path }}">
|
||||||
|
<i class="fa fa-trash-alt"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="explr-multiselection-actions">
|
||||||
|
<button type="button"
|
||||||
|
class="btn explr-items-delete explr-multiselection-entity explr-multiselection-folder btn-danger-alt"
|
||||||
|
data-route="{{ url_for('slideshow_content_delete_bulk_explr') }}?path={{ working_folder_path }}">
|
||||||
<i class="fa fa-trash-alt"></i>
|
<i class="fa fa-trash-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -61,13 +89,13 @@
|
|||||||
<i class="fa fa-warning icon-left"></i>
|
<i class="fa fa-warning icon-left"></i>
|
||||||
{{ l.common_folder_not_empty_error }}
|
{{ l.common_folder_not_empty_error }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% elif request.args.get('referenced_in_slide_error') %}
|
||||||
|
|
||||||
{% if request.args.get('referenced_in_slide_error') %}
|
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<i class="fa fa-warning icon-left"></i>
|
<i class="fa fa-warning icon-left"></i>
|
||||||
{{ l.slideshow_content_referenced_in_slide_error }}
|
{{ l.slideshow_content_referenced_in_slide_error }}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-danger hidden"></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="bottom-content">
|
<div class="bottom-content">
|
||||||
@ -112,64 +140,73 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<ul class="explr-dirview">
|
<div class="dropzone" data-related-input="content_files">
|
||||||
<li class="new-folder hidden">
|
<ul class="explr-dirview">
|
||||||
<a href="javascript:void(0);">
|
<li class="new-folder hidden">
|
||||||
<i class="fa fa-folder"></i>
|
<a href="javascript:void(0);">
|
||||||
<form action="{{ url_for('slideshow_content_folder_add') }}" method="POST">
|
|
||||||
<input type="hidden" name="working_folder_path" value="{{ working_folder_path }}" />
|
|
||||||
<input type="text" name="name" autocomplete="off"/>
|
|
||||||
</form>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{% set parent_path = '/'.join(working_folder_path.rstrip('/').split('/')[:-1]) %}
|
|
||||||
{% if parent_path %}
|
|
||||||
<li class="previous-folder droppable" data-path="{{ parent_path }}"
|
|
||||||
data-id="{{ working_folder.parent_id }}" data-folder="1">
|
|
||||||
<a href="{{ url_for('slideshow_content_cd', path=parent_path) }}"
|
|
||||||
class="explr-link explr-item-selectable explr-item-folder">
|
|
||||||
<i class="fa fa-folder"></i>
|
<i class="fa fa-folder"></i>
|
||||||
..
|
<form action="{{ url_for('slideshow_content_folder_add') }}?path={{ working_folder_path }}" method="POST">
|
||||||
</a>
|
<input type="text" name="name" autocomplete="off"/>
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% for folder in working_folder_children %}
|
|
||||||
{% set folder_path = working_folder_path ~ '/' ~ folder.name %}
|
|
||||||
<li class="draggable droppable" data-path="{{ folder_path }}" data-id="{{ folder.id }}"
|
|
||||||
data-folder="1">
|
|
||||||
<a href="{{ url_for('slideshow_content_cd', path=folder_path) }}"
|
|
||||||
class="explr-link explr-item-selectable explr-item-actionable explr-item-folder">
|
|
||||||
<i class="fa fa-folder"></i>
|
|
||||||
<span>{{ truncate(folder.name, explr_limit_chars, '...') }}</span>
|
|
||||||
<form action="{{ url_for('slideshow_content_folder_rename') }}" method="POST">
|
|
||||||
<input type="text" name="name" value="{{ folder.name }}" autocomplete="off"/>
|
|
||||||
<input type="hidden" name="id" value="{{ folder.id }}"/>
|
|
||||||
</form>
|
</form>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
|
||||||
|
{% set parent_path = '/'.join(working_folder_path.rstrip('/').split('/')[:-1]) %}
|
||||||
|
{% if parent_path %}
|
||||||
|
<li class="previous-folder droppable" data-path="{{ parent_path }}"
|
||||||
|
data-id="{{ working_folder.parent_id }}" data-folder="1">
|
||||||
|
<a href="{{ url_for('slideshow_content_cd', path=parent_path) }}"
|
||||||
|
class="explr-link explr-item-selectable explr-item-folder">
|
||||||
|
<i class="fa fa-folder"></i>
|
||||||
|
..
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for folder in working_folder_children %}
|
||||||
|
{% set folder_path = working_folder_path ~ '/' ~ folder.name %}
|
||||||
|
<li class="draggable droppable" data-path="{{ folder_path }}" data-id="{{ folder.id }}"
|
||||||
|
data-folder="1">
|
||||||
|
<a href="{{ url_for('slideshow_content_cd', path=folder_path) }}"
|
||||||
|
class="explr-link explr-item-selectable explr-item-actionable explr-item-folder">
|
||||||
|
<i class="fa fa-folder"></i>
|
||||||
|
<span>{{ truncate(folder.name, explr_limit_chars, '...') }}</span>
|
||||||
|
<form action="{{ url_for('slideshow_content_folder_rename') }}?path={{ working_folder_path }}" method="POST">
|
||||||
|
<input type="text" name="name" value="{{ folder.name }}" autocomplete="off"/>
|
||||||
|
<input type="hidden" name="id" value="{{ folder.id }}"/>
|
||||||
|
</form>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
{% for content in foldered_contents[working_folder.id|default(None)]|default([]) %}
|
{% for content in foldered_contents[working_folder.id|default(None)]|default([]) %}
|
||||||
{% set icon = enum_content_type.get_fa_icon(content.type) %}
|
{% set icon = enum_content_type.get_fa_icon(content.type) %}
|
||||||
{% set color = enum_content_type.get_color_icon(content.type) %}
|
{% set color = enum_content_type.get_color_icon(content.type) %}
|
||||||
|
{% set thumbnail = content.type == enum_content_type.PICTURE %}
|
||||||
|
|
||||||
<li class="draggable" data-path="{{ working_folder_path }}" data-id="{{ content.id }}"
|
<li class="draggable" data-path="{{ working_folder_path }}" data-id="{{ content.id }}"
|
||||||
data-folder="0">
|
data-folder="0">
|
||||||
<a href="{{ url_for('slideshow_content_edit', content_id=content.id) }}"
|
<a href="{{ url_for('slideshow_content_edit', content_id=content.id) }}"
|
||||||
class="explr-link explr-item-selectable explr-item-actionable explr-item-entity">
|
class="explr-link explr-item-selectable explr-item-actionable explr-item-entity {{ 'with-thumbnail' if thumbnail }}">
|
||||||
<i class="fa {{ icon }} {{ color }}"></i>
|
|
||||||
<span>{{ truncate(content.name, explr_limit_chars, '...') }}</span>
|
{% if content.type == enum_content_type.PICTURE %}
|
||||||
<form action="{{ url_for('slideshow_content_rename') }}" method="POST">
|
<div class="img-holder">
|
||||||
<input type="text" name="name" value="{{ content.name }}" autocomplete="off"/>
|
<img src="/{{ content.location }}" alt=""/>
|
||||||
<input type="hidden" name="id" value="{{ content.id }}"/>
|
</div>
|
||||||
</form>
|
{% endif %}
|
||||||
</a>
|
|
||||||
</li>
|
<i class="fa {{ icon }} {{ color }}"></i>
|
||||||
{% endfor %}
|
<span>{{ truncate(content.name, explr_limit_chars, '...') }}</span>
|
||||||
</ul>
|
<form action="{{ url_for('slideshow_content_rename') }}?path={{ working_folder_path }}" method="POST">
|
||||||
|
<input type="text" name="name" value="{{ content.name }}" autocomplete="off"/>
|
||||||
|
<input type="hidden" name="id" value="{{ content.id }}"/>
|
||||||
|
</form>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modals hidden">
|
<div class="modals hidden">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user