From eee547b0cc6b268b11fa1b73cdf835dc015cd46e Mon Sep 17 00:00:00 2001 From: Doug Bell Date: Wed, 7 Apr 2010 09:50:09 -0500 Subject: [PATCH] Add drag'n'drop sorting to the Gallery Album Edit View (RFE 11007). --- docs/changelog/7.x.x.txt | 1 + ...t_import_gallery-templates_admin.css.wgpkg | Bin 0 -> 1940 bytes ...templates_default-gallery-edit-album.wgpkg | Bin 0 -> 2683 bytes ...gallery-templates_dragdropsorting.js.wgpkg | Bin 0 -> 4071 bytes lib/WebGUI/Asset/Wobject/GalleryAlbum.pm | 168 +++++++++++ t/Asset/Wobject/GalleryAlbum/ajax.t | 264 ++++++++++++++++++ 6 files changed, 433 insertions(+) create mode 100644 docs/upgrades/packages-7.9.3/root_import_gallery-templates_admin.css.wgpkg create mode 100644 docs/upgrades/packages-7.9.3/root_import_gallery-templates_default-gallery-edit-album.wgpkg create mode 100644 docs/upgrades/packages-7.9.3/root_import_gallery-templates_dragdropsorting.js.wgpkg create mode 100644 t/Asset/Wobject/GalleryAlbum/ajax.t diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 1607a9bea..1b6c9ef50 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,4 +1,5 @@ 7.9.3 + - added #11007: Added drag'n'drop sorting in Gallery Album Edit View 7.9.2 - added: Workflow to extend recurring Calendar events 2 years from the diff --git a/docs/upgrades/packages-7.9.3/root_import_gallery-templates_admin.css.wgpkg b/docs/upgrades/packages-7.9.3/root_import_gallery-templates_admin.css.wgpkg new file mode 100644 index 0000000000000000000000000000000000000000..8cbaecf00d3b180d08c9f4440c03f21b3f19381c GIT binary patch literal 1940 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 literal 0 HcmV?d00001 diff --git a/docs/upgrades/packages-7.9.3/root_import_gallery-templates_dragdropsorting.js.wgpkg b/docs/upgrades/packages-7.9.3/root_import_gallery-templates_dragdropsorting.js.wgpkg new file mode 100644 index 0000000000000000000000000000000000000000..b28f5e0b5650da4cb1ee4084be84e7ae8b638ba4 GIT binary patch literal 4071 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. The single +obligatory argument is C determining the service to be called. A list +of available services is given in the following. Additional arguments may be +required depending on the service. + +Results are returned in JSON format. The information returned depends on the +service called. Generally, success is indicated by a value of 0 in C. + +=head3 moveFile + +Service for changing the rank of files. Accepts the asset Id of the photo to be moved +in C. The asset Id of the photo to be replaced is specified in C +or C depending on the desired order. Returns -1 in C and an error +message in C if moving of the photo failed. + +=cut + +sub www_ajax { + my $self = shift; + my $session = $self->session; + my $form = $self->session->form; + my $result; + + # Get arguments encoded in json format + my $args = decode_json($form->get("args")); + + # Log some debug information + $session->log->debug("Ajax service called with args=" . $form->get("args")); + + # Process requests depending on action argument + SWITCH: { + + # Return if no action was specified + if ( $args->{action} eq '' ) { + $session->log->error("Call of ajax service without action argument."); + $result->{ errMessage } = "Action argument is missing."; + last; + } + + # ----- Move file action ----- + $args->{action} eq 'moveFile' && do { $result = $self->_moveFileAjaxRequest( $args ); last; }; + + # ----- Unkown action ----- + $session->log->error("Call of ajax service with unknown action '" . $args->{action} . "'."); + $result->{ errMessage } = "Action '" . $args->{action} ."' is unknown."; + } + + # Set error flag if error message exists + $result->{ err } = -1 if $result->{ errMessage }; + + # Return results encoded in json format + return encode_json( $result ); +} + + +#---------------------------------------------------------------------------- + +=head2 _moveFileAjaxRequest ( args ) + +AJAX service for changing the rank of single files. Returns a hash ref with +error information. Arguments passed to the ajax service are provided via the +hash ref C. Note that this is a private function owned by www_ajax. It +should not be used directly. + +=cut + +sub _moveFileAjaxRequest { + my $self = shift; + my $args = shift; + + my $session = $self->session; + my %result; + + # Return if current user is not allowed to edit this album + unless ( $self->canEdit ) { + $session->log->error("Call of moveFile action without having edit permission."); + $result{ errMessage } = "You do not have permission to move files."; + return \%result; + } + # Return if no target was specified + if ( $args->{target} eq '') { + $session->log->error("Call of moveFile action without target argument."); + $result{ errMessage } = "Target argument is missing."; + return \%result; + } + # Return if before or after argument is missing + unless( $args->{before} or $args->{after} ) { + $session->log->error("Call of moveFile action without before/after argument."); + $result{ errMessage } = "Before/after argument is missing."; + return \%result; + } + # Return if before and after arguments were specified + unless( $args->{before} xor $args->{after} ) { + $session->log->error("Call of moveFile action with before *and* after argument."); + $result{ errMessage } = "Both, before and after arguments were specified."; + return \%result; + } + + # Get Id of target photo and instantiate asset + my $targetId = $args->{target}; + my $target = WebGUI::Asset->newByDynamicClass( $session, $targetId ); + + # Return if target photo could not be instantiated + unless ( $target ) { + $session->log->error("Couldn't move file '$targetId' because we couldn't instantiate it."); + $result{ errMessage } = "ID of target file seems to be invalid."; + return \%result; + } + # Return if target is not a child of the current album + unless ( $target->getParent->getId eq $self->getId ) { + $session->log->error("Couldn't move file '$targetId' because it is not a child of this album."); + $result{ errMessage } = "ID of target file seems to be invalid."; + return \%result; + } + + my ($destId, $dest); + + # Instantiate file with ID in before/after argument + $destId = $args->{before} ? $args->{before} : $args->{after}; + $dest = WebGUI::Asset->newByDynamicClass( $session, $destId ); + + # Return if destination file could not be instantiated + unless ( $dest ) { + $session->log->error("Couldn't move file '$targetId' before/after file '$destId' because we couldn't instantiate the latter."); + $result{ errMessage } = "ID in before/after argument seems to be invalid."; + return \%result; + } + # Return if destination file is not a child of the current album + unless ( $dest->getParent->getId eq $self->getId ) { + $session->log->error("Couldn't move file '$targetId' before/after file '$destId' because the latter is not a child of the same album."); + $result{ errMessage } = "ID in before/after argument seems to be invalid."; + return \%result; + } + + # Check for use of after argument when lowering the rank + if ( $args->{after} && $target->getRank() > $dest->getRank() ) { + # Get ID of next sibling + $destId = $self->getNextFileId( $destId ); + # Instantiate next sibling + $dest = WebGUI::Asset->newByDynamicClass( $session, $destId ); + } + # Check for use of before argument when increasing the rank + if ( $args->{before} && $target->getRank() < $dest->getRank() ) { + # Get ID of previous sibling + $destId = $self->getPreviousFileId( $destId ); + # Instantiate previous sibling + $dest = WebGUI::Asset->newByDynamicClass( $session, $destId ); + } + + # Update rank of target photo + $target->setRank( $dest->getRank ); + + # Log some debug information + $session->log->debug("Successfully moved file '$targetId' before/after file '$destId'."); + + # Return reporting success + $result{ err } = 0; + return \%result; +} + +#---------------------------------------------------------------------------- + =head2 www_edit ( ) Show the form to add / edit a GalleryAlbum asset. diff --git a/t/Asset/Wobject/GalleryAlbum/ajax.t b/t/Asset/Wobject/GalleryAlbum/ajax.t new file mode 100644 index 000000000..679137595 --- /dev/null +++ b/t/Asset/Wobject/GalleryAlbum/ajax.t @@ -0,0 +1,264 @@ +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------- +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------- + +use FindBin; +use strict; +use lib "$FindBin::Bin/../../../lib"; + +## The goal of this test is to test the creation and deletion of album assets + +use JSON; +use WebGUI::Test; +use WebGUI::Session; +use Test::More; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; +my $node = WebGUI::Asset->getImportNode($session); +my $versionTag = WebGUI::VersionTag->getWorking($session); + +my %user; +$user{'1'} = WebGUI::User->new( $session, "new" ); +$user{'1'}->addToGroups( ['3'] ); # Admins +WebGUI::Test->usersToDelete($user{'1'}); +$user{'2'} = WebGUI::User->new( $session, "new" ); +WebGUI::Test->usersToDelete($user{'2'}); + +# Create everything as user no. 1 +$session->user({ user => $user{'1'} }); + +$versionTag->set({name=>"Album Test"}); + +# Create gallery and a single album +my $gallery + = $node->addChild({ + className => "WebGUI::Asset::Wobject::Gallery", + groupIdEdit => 3, # Admins + }, + undef, + undef, + { + skipAutoCommitWorkflows => 1, + }); +my $album + = $gallery->addChild({ + className => "WebGUI::Asset::Wobject::GalleryAlbum", + }, + undef, + undef, + { + skipAutoCommitWorkflows => 1, + }); + +# Create 5 photos inside the gallery +my @photoId; + +for (my $i = 0; $i < 5; $i++) +{ + my $photo + = $album->addChild({ + className => "WebGUI::Asset::File::GalleryFile::Photo", + }, + undef, + undef, + { + skipAutoCommitWorkflows => 1, + }); + $photoId[$i] = $photo->getId; +} + +# Commit all changes +$versionTag->commit; + +# Make album default asset +$session->asset( $album ); + +# Define some general variables +my $result; + +#---------------------------------------------------------------------------- +# Tests +plan tests => 19; + +#---------------------------------------------------------------------------- +# Test module compiles okay +use_ok("WebGUI::Asset::Wobject::GalleryAlbum"); + +#---------------------------------------------------------------------------- +# Test calling without arguments + +diag("general testing"); + +# Provide no arguments at all +$result = callAjaxService({ }); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after call without arguments." ); + +#---------------------------------------------------------------------------- +# Test moveFile action with incomplete of invalid arguments + +diag("moveFile action"); + +# Omit target +$result = callAjaxService({ + action => 'moveFile', + after => $photoId[4], + }); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action without 'target' specified." ); + + +# Omit before/after +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action without 'before/after' specified." ); + +# Specify invalid target ID +$result = callAjaxService({ + action => 'moveFile', + target => '123456', + after => $photoId[4], +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with invalid 'target' ID." ); + +# Specify invalid ID in after argument +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + after => '123456', +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with invalid ID in 'after' argument." ); + +# Specify invalid ID in before argument +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + before => '123456', +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with invalid ID in 'before' argument." ); + +# Specify non-child target ID +$result = callAjaxService({ + action => 'moveFile', + target => $album->getId, + after => $photoId[4], +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with non-child 'target' ID." ); + +# Specify non-child ID in after argument +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + after => $album->getId, +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with non-child ID in 'after' argument." ); + +# Specify non-child ID in before argument +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + before => $album->getId, +}); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with non-child ID in 'before' argument." ); + +#---------------------------------------------------------------------------- +# Test moving photos + +# Move photo no. 0 after photo no. 4 +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + after => $photoId[4], +}); + +is($result->{ err }, 0, 'Moving of photo no. 0 after photo no. 4 successful.'); +is($album->getPreviousFileId($photoId[0]), $photoId[4], 'Photo no. 0 is after photo no. 4.'); + +# Move photo no. 0 before photo no. 1 (restore initial order) +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + before => $photoId[1], + }); + +# Delete all stow variables. This is necessary or the list of file IDs will +# not get updated. +$session->stow->deleteAll; + +is($result->{ err }, 0, 'Moving of photo no. 0 before photo no. 1 successful.'); +is($album->getNextFileId($photoId[0]), $photoId[1], 'Photo no. 0 is before photo no. 1.'); + +# Move photo no. 0 before photo no. 0 +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + before => $photoId[0], + }); + +$session->stow->deleteAll; + +is($result->{ err }, 0, 'Moving of photo no. 0 before photo no. 0 successful.'); +is($album->getNextFileId($photoId[0]), $photoId[1], 'Photo no. 0 is still before photo no. 1.'); + +# Move photo no. 0 after photo no. 0 +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + after => $photoId[0], + }); + +$session->stow->deleteAll; + +is($result->{ err }, 0, 'Moving of photo no. 0 after photo no. 0 successful.'); +is($album->getNextFileId($photoId[0]), $photoId[1], 'Photo no. 0 is still before photo no. 1.'); + +# Try to move photo with insufficient permissions +$session->user({ user => $user{'2'} }); +$result = callAjaxService({ + action => 'moveFile', + target => $photoId[0], + after => $photoId[4], +}); +$session->user({ user => $user{'1'} }); + +ok( $result->{ err } != 0 && $result->{ errMessage }, "Error after request of moveFile action with insufficient permissions." ); + +#---------------------------------------------------------------------------- +# callAjaxService( args ) +# Makes a call to the www_ajax method of $album and returns the reply. The +# only argument is a hash ref pointing to arguments for the ajax service. +# The sub uses the global $session and $album variables. + +sub callAjaxService { + my $args = shift; + + # Setup the mock request object + $session->request->method('POST'); + $session->request->setup_body({ args => encode_json($args) }); + + # Call ajax service function and decode reply + return decode_json( $album->www_ajax() ); +} + +#---------------------------------------------------------------------------- +# Cleanup +END { + $versionTag->rollback(); +}