obscreen/data/www/js/explorer.js

344 lines
12 KiB
JavaScript

let onPickedElement = function (element) {
};
jQuery(function ($) {
let lastClicked = null;
const explrSidebarOpenFromFolder = function (folderId) {
const $leaf = $('.li-explr-folder-' + folderId);
let $parent = $leaf;
while ($parent.length > 0) {
const $toggler = $parent.find('.explr-toggler:eq(0)');
if ($toggler.hasClass('explr-plus')) {
$parent.find('.explr-toggler:eq(0)').trigger('click');
}
$parent = $parent.parents('.li-explr-folder:eq(0)');
}
};
const initExplr = function () {
$('.explr').each(function () {
$(this).explr({
classesPlus: 'fa fa-chevron-right',
classesMinus: 'fa fa-chevron-down',
onLoadFinish: function ($tree) {
$tree.removeClass('hidden');
}
});
// Open complete path in explorer sidebar
explrSidebarOpenFromFolder($(this).attr('data-working-folder-id'));
});
$('.draggable').each(function () {
$(this).draggable({
revert: "invalid",
});
});
$('.droppable').each(function () {
$(this).droppable({
accept: ".draggable",
over: function (event, ui) {
$(this).addClass("highlight-drop");
},
out: function (event, ui) {
$(this).removeClass("highlight-drop");
},
drop: function (event, ui) {
$(this).removeClass("highlight-drop");
const $form = $('#folder-move-form');
const $moved = ui.draggable;
const $target = $(this);
$form.find('[name=is_folder]').val($moved.attr('data-folder'))
$form.find('[name=entity_id]').val($moved.attr('data-id'))
$form.find('[name=new_folder_id]').val($target.attr('data-id'))
ui.draggable.position({
my: "center",
at: "center",
of: $(this),
using: function (pos) {
$(this).animate(pos, 50);
}
});
$form.submit();
}
});
});
};
const main = function () {
initExplr();
};
const updateBodyClasses = function () {
const $selectedLinks = $('a.explr-link.highlight-clicked');
const isMultiSelect = $selectedLinks.length > 1;
const isSingleSelect = $selectedLinks.length === 1;
const $link = $selectedLinks.last();
$('body')
.toggleClass('explr-selection', isSingleSelect)
.toggleClass('explr-selection-actionable', isSingleSelect && $link.hasClass('explr-item-actionable'))
.toggleClass('explr-selection-entity', isSingleSelect && $link.hasClass('explr-item-entity'))
.toggleClass('explr-selection-folder', isSingleSelect && $link.hasClass('explr-item-folder'))
.toggleClass('explr-multiselection', isMultiSelect)
.toggleClass('explr-multiselection-actionable', isMultiSelect && $selectedLinks.hasClass('explr-item-actionable'))
.toggleClass('explr-multiselection-entity', isMultiSelect && $selectedLinks.hasClass('explr-item-entity'))
.toggleClass('explr-multiselection-folder', isMultiSelect && $selectedLinks.hasClass('explr-item-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 () {
return $('.explr-dirview li.highlight-clicked');
};
const renameExplrItem = function ($item) {
$('.dirview .renaming').removeClass('renaming');
$item.addClass('renaming');
$item.find('input').focus().select();
}
$(document).on('click', '.explr-item-edit', function () {
document.location.href = $(this).attr('data-entity-route').replace('!c!', getExplrSelection().attr('data-id'));
});
$(document).on('click', '.explr-item-rename', function () {
renameExplrItem(getExplrSelection());
});
$(document).on('click', '.explr-item-delete', function () {
const $item = getExplrSelection();
const is_folder = $item.attr('data-folder') === '1';
let route;
if (is_folder) {
route = $(this).attr('data-folder-route') + '&id=' + $item.attr('data-id');
} else {
route = $(this).attr('data-entity-route') + '&id=' + $item.attr('data-id');
}
if (confirm(l.js_common_are_you_sure)) {
document.location.href = route;
}
});
$(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) {
const $selectedLink = $('.explr-item-selectable.highlight-clicked');
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) {
return;
}
if (e.code === "Space") {
renameExplrItem($selectedLi);
} else if ($selectedLink.length) {
const $prevLi = $selectedLi.prev('li:visible');
const $nextLi = $selectedLi.next('li:visible');
const verticalNeighbors = getAboveBelowElement($selectedLi);
if (e.key === "Enter") {
$selectedLink.trigger('dblclick');
} else if (e.key === "ArrowLeft" && $prevLi.length) {
selectEpxlrLink($prevLi.find('.explr-link'));
} else if (e.key === "ArrowRight" && $nextLi.length) {
selectEpxlrLink($nextLi.find('.explr-link'));
} else if (e.key === "ArrowUp" && verticalNeighbors.above) {
selectEpxlrLink(verticalNeighbors.above.find('.explr-link'));
} else if (e.key === "ArrowDown" && verticalNeighbors.below) {
selectEpxlrLink(verticalNeighbors.below.find('.explr-link'));
} else if (e.key === "Backspace") {
if ($('.explr-item-delete:visible').length) {
$('.explr-item-delete:visible').click();
}
if ($('.explr-items-delete:visible').length) {
$('.explr-items-delete:visible').click();
}
}
} else if (e.key.indexOf('Arrow') === 0) {
selectEpxlrLink($('.explr-dirview li:visible:eq(0)').find('.explr-link'));
}
});
// Explorer item selection
$(document).on('click', 'a.explr-link', function (event) {
event.preventDefault();
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) {
event.preventDefault();
const callback = $(this).attr('data-callback');
if (callback) {
window[callback]($(this));
}
});
$(document).on('dblclick', 'a.explr-link', function (event) {
event.preventDefault();
$(this).off('click');
const href = $(this).attr('href');
const callback = $(this).attr('data-callback');
if (callback) {
window[callback]($(this));
} else if ($(this).attr('target') === '_blank') {
window.open(href);
} else {
window.location.href = href;
}
});
$(document).on('click', function (event) {
const $parentClickable = $(event.target).parents('a, button');
if ($parentClickable.length === 0) {
$('a.explr-link').removeClass('highlight-clicked');
$('a.explr-link').parent().removeClass('highlight-clicked');
$('body').removeClass('explr-selection explr-selection-entity explr-selection-folder explr-selection-actionable');
}
});
$(document).on('click', '.modal-explr-picker .explr-pick-folder', function () {
$(this).parents('li:eq(0)').find('.explr-toggler').click();
});
$(document).on('click', '.modal-explr-picker .explr-pick-element', function () {
onPickedElement(JSON.parse($(this).parents('li:eq(0)').attr('data-entity-json')));
hidePicker();
});
const getAboveBelowElement = function ($elem) {
const $liElements = $elem.parents('ul:eq(0)').find('li');
const positions = [];
// Get the Y positions of each element
$liElements.each(function () {
const $this = $(this);
positions.push({
element: $this,
y: $this.offset().top,
x: $this.offset().left
});
});
// Group elements by their Y position
const groupedByY = positions.reduce((acc, pos) => {
if (!acc[pos.y]) {
acc[pos.y] = [];
}
acc[pos.y].push(pos);
return acc;
}, {});
// Convert groupedByY to an array of arrays
const rows = Object.values(groupedByY);
let targetRowIndex = -1;
let targetColIndex = -1;
// Find the row and column index of the target element
rows.forEach((row, rowIndex) => {
row.forEach((pos, colIndex) => {
if (pos.element.is($elem)) {
targetRowIndex = rowIndex;
targetColIndex = colIndex;
}
});
});
const result = {
above: null,
below: null
};
if (targetRowIndex > 0) {
const aboveRow = rows[targetRowIndex - 1];
if (targetColIndex < aboveRow.length) {
result.above = aboveRow[targetColIndex].element;
}
}
if (targetRowIndex < rows.length - 1) {
const belowRow = rows[targetRowIndex + 1];
if (targetColIndex < belowRow.length) {
result.below = belowRow[targetColIndex].element;
}
}
return result;
}
main();
});