Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance MetaDataEditor Gallery Drag-&-Drop via jQuery-UI #5113

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import org.kitodo.production.services.ServiceManager;
import org.kitodo.production.services.file.FileService;
import org.primefaces.PrimeFaces;
import org.primefaces.event.DragDropEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

Expand Down Expand Up @@ -210,11 +209,15 @@ public List<GalleryStripe> getStripes() {
* @param event
* JSF drag'n'drop event description object
*/
public void onPageDrop(DragDropEvent event) {
int toStripeIndex = getDropStripeIndex(event);

if (toStripeIndex == -1 || !dragStripeIndexMatches(event)) {
logger.error("Unsupported drag'n'drop event from {} to {}", event.getDragId(), event.getDropId());
public void onPageDrop() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
String dragId = params.get("dragId");
String dropId = params.get("dropId");

int toStripeIndex = getDropStripeIndex(dropId);
if (toStripeIndex == -1 || !dragStripeIndexMatches(dragId)) {
logger.error("Unsupported drag'n'drop event from {} to {}", dragId, dropId);
return;
}

Expand All @@ -232,7 +235,7 @@ public void onPageDrop(DragDropEvent event) {

viewsToBeMoved.sort(IMAGE_ORDER_COMPARATOR);

int toMediaIndex = getMediaIndex(event);
int toMediaIndex = getMediaIndex(dropId);
try {
updateData(toStripe, viewsToBeMoved, toMediaIndex);
} catch (Exception e) {
Expand All @@ -244,25 +247,25 @@ public void onPageDrop(DragDropEvent event) {
updateAffectedStripes(toStripe, viewsToBeMoved);
}

private boolean dragStripeIndexMatches(DragDropEvent event) {
Matcher dragStripeImageMatcher = DRAG_STRIPE_IMAGE.matcher(event.getDragId());
Matcher dragUnstructuredMediaMatcher = DRAG_UNSTRUCTURED_MEDIA.matcher(event.getDragId());
private boolean dragStripeIndexMatches(String dragId) {
Matcher dragStripeImageMatcher = DRAG_STRIPE_IMAGE.matcher(dragId);
Matcher dragUnstructuredMediaMatcher = DRAG_UNSTRUCTURED_MEDIA.matcher(dragId);
return dragUnstructuredMediaMatcher.matches() || dragStripeImageMatcher.matches();
}

private int getDropStripeIndex(DragDropEvent event) {
private int getDropStripeIndex(String dropId) {
// empty stripe of structure element
Matcher dropStripeMatcher = DROP_STRIPE.matcher(event.getDropId());
Matcher dropStripeMatcher = DROP_STRIPE.matcher(dropId);
// between two pages of structure element
Matcher dropMediaAreaMatcher = DROP_MEDIA_AREA.matcher(event.getDropId());
Matcher dropMediaAreaMatcher = DROP_MEDIA_AREA.matcher(dropId);
// after last page of structure element
Matcher dropMediaLastAreaMatcher = DROP_MEDIA_LAST_AREA.matcher(event.getDropId());
Matcher dropMediaLastAreaMatcher = DROP_MEDIA_LAST_AREA.matcher(dropId);
// empty unstructured media stripe
Matcher dropUnstructuredMediaStripeMatcher = DROP_UNSTRUCTURED_STRIPE.matcher(event.getDropId());
Matcher dropUnstructuredMediaStripeMatcher = DROP_UNSTRUCTURED_STRIPE.matcher(dropId);
// between two pages of unstructured media stripe
Matcher dropUnstructuredMediaAreaMatcher = DROP_UNSTRUCTURED_MEDIA_AREA.matcher(event.getDropId());
Matcher dropUnstructuredMediaAreaMatcher = DROP_UNSTRUCTURED_MEDIA_AREA.matcher(dropId);
// after last page of unstructured media stripe
Matcher dropUnstructuredMediaLastAreaMatcher = DROP_UNSTRUCTURED_MEDIA_LAST_AREA.matcher(event.getDropId());
Matcher dropUnstructuredMediaLastAreaMatcher = DROP_UNSTRUCTURED_MEDIA_LAST_AREA.matcher(dropId);
if (dropStripeMatcher.matches()) {
return Integer.parseInt(dropStripeMatcher.group(1));
} else if (dropMediaAreaMatcher.matches()) {
Expand All @@ -279,11 +282,11 @@ private int getDropStripeIndex(DragDropEvent event) {
}
}

private int getMediaIndex(DragDropEvent event) {
Matcher dropMediaAreaMatcher = DROP_MEDIA_AREA.matcher(event.getDropId());
Matcher dropMediaLastAreaMatcher = DROP_MEDIA_LAST_AREA.matcher(event.getDropId());
Matcher dropUnstructuredMediaAreaMatcher = DROP_UNSTRUCTURED_MEDIA_AREA.matcher(event.getDropId());
Matcher dropUnstructuredMediaLastAreaMatcher = DROP_UNSTRUCTURED_MEDIA_LAST_AREA.matcher(event.getDropId());
private int getMediaIndex(String dropId) {
Matcher dropMediaAreaMatcher = DROP_MEDIA_AREA.matcher(dropId);
Matcher dropMediaLastAreaMatcher = DROP_MEDIA_LAST_AREA.matcher(dropId);
Matcher dropUnstructuredMediaAreaMatcher = DROP_UNSTRUCTURED_MEDIA_AREA.matcher(dropId);
Matcher dropUnstructuredMediaLastAreaMatcher = DROP_UNSTRUCTURED_MEDIA_LAST_AREA.matcher(dropId);
if (dropMediaAreaMatcher.matches()) {
return Integer.parseInt(dropMediaAreaMatcher.group(2));
} else if (dropMediaLastAreaMatcher.matches()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

/* global triggerOnPageDrop, PrimeFaces */

/**
* Registers event handler that makes relevant components of gallery
* draggable and droppable via jquery-ui.
*
* This is much faster than adding individual <p:draggable/> and
* <p:droppable/> primefaces components, which would initialize drag and
* drop capabilities individually for each component.
* Additionally, this reduces the form complexity of the gallery view, which
* results in faster form updates for very large galleries.
*/
function registerMakeDragAndDroppable() {

// define debouce function that will allow to make components draggable in one go
// after all of them have been updated via Primefaces when reloading the gallery
function makeDebounced(func, timeout = 100) {
let timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(func, timeout);
};
}

function onDrop(event, ui) {
let dragId = ui.draggable.attr('id');
let dropId = $(event.target).attr('id');
// trigger remote command, see gallery.xhtml and GalleryPanel.onPageDrop
triggerOnPageDrop([{"name": "dragId", "value": dragId}, {"name": "dropId", "value": dropId}]);
}

// apply jquery draggable and droppable to the relevant dom elements
let makeDragAndDroppable = makeDebounced(function () {
// make individual pages draggable
$("#imagePreviewForm\\:structuredPages .draggableStructurePagePanel").draggable({
scope: "assignedPagesDroppable",
stack: ".ui-panel",
revert: true,
});
$("#imagePreviewForm\\:unstructuredMediaList .draggableUnstructuredMediaPanel").draggable({
scope: "assignedPagesDroppable",
stack: ".ui-panel",
revert: true,
});

// make droppable containers before and after each page
$("#imagePreviewForm\\:structuredPages .page-drop-area").droppable({
scope: "assignedPagesDroppable",
activeClass: "media-stripe-index-active",
drop: onDrop,
});
$("#imagePreviewForm\\:unstructuredMediaList .page-drop-area").droppable({
scope: "assignedPagesDroppable",
activeClass: "media-stripe-index-active",
drop: onDrop,
});

// make droppable container for empty stripes
$("#imagePreviewForm\\:structuredPages .structureElementDataList").has(".ui-datalist-empty-message").droppable({
scope: "assignedPagesDroppable",
activeClass: "media-stripe-active",
drop: onDrop,
});
$("#imagePreviewForm\\:unstructuredMediaList").has(".ui-datalist-empty-message").droppable({
scope: "assignedPagesDroppable",
activeClass: "media-stripe-active",
drop: onDrop,
});
});

// update components after they have been updated via PrimeFaces
let backupFunc = PrimeFaces.ajax.Utils.updateElement;
PrimeFaces.ajax.Utils.updateElement = function() {
backupFunc.apply(this, arguments);
makeDragAndDroppable();
};

// make components draggable the very first time the gallery loads
makeDragAndDroppable();
}

$(function() {
registerMakeDragAndDroppable();
});
Loading