diff --git a/core/lib/Thelia/Action/Image.php b/core/lib/Thelia/Action/Image.php index ed7010a09..83bf3b774 100755 --- a/core/lib/Thelia/Action/Image.php +++ b/core/lib/Thelia/Action/Image.php @@ -28,6 +28,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\Image\ImageCreateOrUpdateEvent; use Thelia\Core\Event\Image\ImageDeleteEvent; use Thelia\Core\Event\Image\ImageEvent; +use Thelia\Core\Event\UpdateImagePositionEvent; use Thelia\Model\ConfigQuery; use Thelia\Tools\FileManager; use Thelia\Tools\URL; @@ -301,6 +302,13 @@ class Image extends BaseCachedFile implements EventSubscriberInterface $event->setModelImage($event->getModelImage()); } + public function updatePosition(UpdateImagePositionEvent $event) + { + return $this->genericUpdatePosition($event->getQuery(), $event); + + $out = true; + } + /** * Take care of deleting image in the database and file storage * @@ -441,6 +449,7 @@ class Image extends BaseCachedFile implements EventSubscriberInterface TheliaEvents::IMAGE_DELETE => array("deleteImage", 128), TheliaEvents::IMAGE_SAVE => array("saveImage", 128), TheliaEvents::IMAGE_UPDATE => array("updateImage", 128), + TheliaEvents::IMAGE_UPDATE_POSITION => array("updatePosition", 128), ); } } diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 591e5c0e7..c67f15977 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -59,6 +59,11 @@ .* \d+ + + Thelia\Controller\Admin\FileController::updateImagePositionAction + .* + \d+ + Thelia\Controller\Admin\FileController::viewImageAction .* diff --git a/core/lib/Thelia/Controller/Admin/FileController.php b/core/lib/Thelia/Controller/Admin/FileController.php index f4d2c3f73..cc32ef93d 100755 --- a/core/lib/Thelia/Controller/Admin/FileController.php +++ b/core/lib/Thelia/Controller/Admin/FileController.php @@ -25,6 +25,7 @@ namespace Thelia\Controller\Admin; use Propel\Runtime\Exception\PropelException; use Symfony\Component\HttpFoundation\File\UploadedFile; +use Thelia\Core\Event\UpdatePositionEvent; use Thelia\Core\HttpFoundation\Response; use Thelia\Core\Security\Resource\AdminResources; use Thelia\Core\Event\Document\DocumentCreateOrUpdateEvent; @@ -519,6 +520,8 @@ class FileController extends BaseAdminController */ public function deleteImageAction($imageId, $parentType) { + $message = null; + $this->checkAuth(AdminResources::retrieve($parentType), array(), AccessManager::UPDATE); $this->checkXmlHttpRequest(); @@ -569,14 +572,79 @@ class FileController extends BaseAdminController 'image' ) ); + $message = $this->getTranslator() + ->trans( + 'Fail to delete image for %id% with parent id %parentId% (Exception : %e%)', + array( + '%id%' => $imageDeleteEvent->getImageToDelete()->getId(), + '%parentId%' => $imageDeleteEvent->getImageToDelete()->getParentId(), + '%e%' => $e->getMessage() + ), + 'image' + ); } - $message = $this->getTranslator() - ->trans( - 'Images deleted successfully', - array(), - 'image' + if(null === $message) { + $message = $this->getTranslator() + ->trans( + 'Images deleted successfully', + array(), + 'image' + ); + } + + return new Response($message); + } + + public function updateImagePositionAction($parentType, $parentId) + { + $message = null; + + $imageId = $this->getRequest()->request->get('image_id'); + $position = $this->getRequest()->request->get('position'); + + $this->checkAuth(AdminResources::retrieve($parentType), array(), AccessManager::UPDATE); + $this->checkXmlHttpRequest(); + + $fileManager = new FileManager($this->container); + $imageModelQuery = $fileManager->getImageModelQuery($parentType); + $model = $imageModelQuery->findPk($imageId); + + if ($model === null || $position === null) { + return $this->pageNotFound(); + } + + // Feed event + $imageUpdatePositionEvent = new UpdatePositionEvent( + $imageId, + UpdatePositionEvent::POSITION_ABSOLUTE, + $position + ); + + // Dispatch Event to the Action + try { + $this->dispatch( + TheliaEvents::IMAGE_UPDATE_POSITION, + $imageUpdatePositionEvent ); + } catch (\Exception $e) { + + $message = $this->getTranslator() + ->trans( + 'Fail to update image position', + array(), + 'image' + ) . $e->getMessage(); + } + + if(null === $message) { + $message = $this->getTranslator() + ->trans( + 'Image position updated', + array(), + 'image' + ); + } return new Response($message); } diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 15a049512..8073f99cf 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -424,6 +424,7 @@ final class TheliaEvents * Save given images */ const IMAGE_UPDATE = "action.updateImages"; + const IMAGE_UPDATE_POSITION = "action.updateImagePosition"; /** * Delete given image diff --git a/core/lib/Thelia/Core/Event/UpdateImagePositionEvent.php b/core/lib/Thelia/Core/Event/UpdateImagePositionEvent.php new file mode 100644 index 000000000..cf4479bba --- /dev/null +++ b/core/lib/Thelia/Core/Event/UpdateImagePositionEvent.php @@ -0,0 +1,60 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Propel\Runtime\ActiveQuery\ModelCriteria; + +class UpdateImagePositionEvent extends UpdatePositionEvent +{ + protected $query; + + /** + * @param ModelCriteria $query + * @param $object_id + * @param null $mode + * @param null $position + */ + public function __construct(ModelCriteria $query, $object_id, $mode, $position = null) + { + parent::__construct($object_id, $mode, $position); + + $this->setQuery($query); + } + + /** + * @param ModelCriteria $query + */ + public function setQuery(ModelCriteria $query) + { + $this->query = $query; + } + + /** + * @return ModelCriteria|null + */ + public function getQuery() + { + return $this->query; + } +} diff --git a/core/lib/Thelia/Model/Category.php b/core/lib/Thelia/Model/Category.php index 8b8b53e4f..8f1dd8eb4 100755 --- a/core/lib/Thelia/Model/Category.php +++ b/core/lib/Thelia/Model/Category.php @@ -106,7 +106,11 @@ class Category extends BaseCategory public function preDelete(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::BEFORE_DELETECATEGORY, new CategoryEvent($this)); - $this->reorderBeforeDelete(); + $this->reorderBeforeDelete( + array( + "parent" => $this->getParent(), + ) + ); return true; } diff --git a/core/lib/Thelia/Model/CategoryImage.php b/core/lib/Thelia/Model/CategoryImage.php index 17ee387b5..b1f0ff4a9 100755 --- a/core/lib/Thelia/Model/CategoryImage.php +++ b/core/lib/Thelia/Model/CategoryImage.php @@ -52,4 +52,13 @@ class CategoryImage extends BaseCategoryImage return $this->getCategoryId(); } + public function preDelete(ConnectionInterface $con = null) + { + $this->reorderBeforeDelete( + array( + "category_id" => $this->getCategoryId(), + ) + ); + return true; + } } diff --git a/core/lib/Thelia/Model/ContentImage.php b/core/lib/Thelia/Model/ContentImage.php index b6a3085d4..e26f6f6af 100755 --- a/core/lib/Thelia/Model/ContentImage.php +++ b/core/lib/Thelia/Model/ContentImage.php @@ -49,4 +49,14 @@ class ContentImage extends BaseContentImage { return $this->getContentId(); } + + public function preDelete(ConnectionInterface $con = null) + { + $this->reorderBeforeDelete( + array( + "content_id" => $this->getContentId(), + ) + ); + return true; + } } \ No newline at end of file diff --git a/core/lib/Thelia/Model/Folder.php b/core/lib/Thelia/Model/Folder.php index 9249c94e2..b267ce5f1 100755 --- a/core/lib/Thelia/Model/Folder.php +++ b/core/lib/Thelia/Model/Folder.php @@ -94,7 +94,11 @@ class Folder extends BaseFolder public function preDelete(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::BEFORE_DELETEFOLDER, new FolderEvent($this)); - $this->reorderBeforeDelete(); + $this->reorderBeforeDelete( + array( + "parent" => $this->getParent(), + ) + ); return true; } diff --git a/core/lib/Thelia/Model/FolderImage.php b/core/lib/Thelia/Model/FolderImage.php index f9491c9a5..725faf744 100755 --- a/core/lib/Thelia/Model/FolderImage.php +++ b/core/lib/Thelia/Model/FolderImage.php @@ -49,4 +49,14 @@ class FolderImage extends BaseFolderImage { return $this->getFolderId(); } + + public function preDelete(ConnectionInterface $con = null) + { + $this->reorderBeforeDelete( + array( + "folder_id" => $this->getFolderId(), + ) + ); + return true; + } } diff --git a/core/lib/Thelia/Model/ProductImage.php b/core/lib/Thelia/Model/ProductImage.php index 6cc3ddd8c..32026bdd3 100755 --- a/core/lib/Thelia/Model/ProductImage.php +++ b/core/lib/Thelia/Model/ProductImage.php @@ -49,4 +49,14 @@ class ProductImage extends BaseProductImage { return $this->getProductId(); } + + public function preDelete(ConnectionInterface $con = null) + { + $this->reorderBeforeDelete( + array( + "product_id" => $this->getProductId(), + ) + ); + return true; + } } diff --git a/core/lib/Thelia/Model/Tools/PositionManagementTrait.php b/core/lib/Thelia/Model/Tools/PositionManagementTrait.php index e8d64d07e..ea9f23dd4 100644 --- a/core/lib/Thelia/Model/Tools/PositionManagementTrait.php +++ b/core/lib/Thelia/Model/Tools/PositionManagementTrait.php @@ -199,19 +199,26 @@ trait PositionManagementTrait { } } - protected function reorderBeforeDelete() + protected function reorderBeforeDelete($fields = array()) { // Find DATABASE_NAME constant $mapClassName = self::TABLE_MAP; - $sql = sprintf("UPDATE `%s` SET position=(position-1) WHERE parent=:parent AND position>:position", $mapClassName::TABLE_NAME); + $data = array(); + $whereCriteria = array(); + + foreach($fields as $field => $value) { + $whereCriteria[] = $field . '=:' . $field; + $data[':' . $field] = $value; + } + + $data[':position'] = $this->getPosition(); + + $sql = sprintf("UPDATE `%s` SET position=(position-1) WHERE " . (count($whereCriteria)>0 ? implode(" AND ", $whereCriteria) : '1') . " AND position>:position", $mapClassName::TABLE_NAME); $con = Propel::getConnection($mapClassName::DATABASE_NAME); $statement = $con->prepare($sql); - $statement->execute(array( - ':parent' => $this->getParent(), - ':position' => $this->getPosition() - )); + $statement->execute($data); } } \ No newline at end of file diff --git a/templates/backOffice/default/assets/js/image-upload.js b/templates/backOffice/default/assets/js/image-upload.js index c1414c73b..c4509c09e 100755 --- a/templates/backOffice/default/assets/js/image-upload.js +++ b/templates/backOffice/default/assets/js/image-upload.js @@ -4,11 +4,11 @@ $(function($){ Dropzone.autoDiscover = false; - - // Remove image on click $.imageUploadManager.initImageDropZone = function() { + $.imageUploadManager.onClickDeleteImage(); + $.imageUploadManager.sortImage(); var imageDropzone = new Dropzone("#images-dropzone", { dictDefaultMessage : $('.btn-browse').html(), @@ -65,6 +65,7 @@ $(function($){ data ); $.imageUploadManager.onClickDeleteImage(); + $.imageUploadManager.sortImage(); }); }; @@ -95,8 +96,63 @@ $(function($){ $(".image-manager .message").html( data ); + + /* refresh position */ + $( "#js-sort-image").children('li').each(function(position, element) { + $(element).find('.js-sorted-position').html(position + 1); + }); }); return false; }); }; + + $.imageUploadManager.sortImage = function() { + $( "#js-sort-image" ).sortable({ + placeholder: "ui-sortable-placeholder col-sm-6 col-md-3", + change: function( event, ui ) { + /* refresh position */ + var pickedElement = ui.item; + var position = 0; + $( "#js-sort-image").children('li').each(function(k, element) { + if($(element).data('sort-id') == pickedElement.data('sort-id')) { + return true; + } + position++; + if($(element).is('.ui-sortable-placeholder')) { + pickedElement.find('.js-sorted-position').html(position); + } else { + $(element).find('.js-sorted-position').html(position); + } + }); + }, + stop: function( event, ui ) { + event.preventDefault(); + + /* update */ + var newPosition = ui.item.find('.js-sorted-position').html(); + var imageId = ui.item.data('sort-id'); + + $.ajax({ + type: "POST", + url: imageReorder, + data: { + image_id: imageId, + position: newPosition + }, + statusCode: { + 404: function() { + $(".image-manager .message").html( + imageReorderErrorMessage + ); + } + } + }).done(function(data) { + $(".image-manager .message").html( + data + ); + }); + } + }); + $( "#js-sort-image" ).disableSelection(); + }; }); diff --git a/templates/backOffice/default/includes/document-upload-list-ajax.html b/templates/backOffice/default/includes/document-upload-list-ajax.html index 5c271e769..29effddd7 100755 --- a/templates/backOffice/default/includes/document-upload-list-ajax.html +++ b/templates/backOffice/default/includes/document-upload-list-ajax.html @@ -10,13 +10,14 @@ Parameters: {ifloop rel="document"} - {loop type="document" name="document" source="{$documentType}" order="manual-reverse" source_id="{$parentId}"} + {loop type="document" name="document" source="{$documentType}" order="manual" source_id="{$parentId}"}
{$TITLE}
+ {$POSITION} diff --git a/templates/backOffice/default/includes/image-upload-form.html b/templates/backOffice/default/includes/image-upload-form.html index 00915e8a7..7b7d7eb65 100755 --- a/templates/backOffice/default/includes/image-upload-form.html +++ b/templates/backOffice/default/includes/image-upload-form.html @@ -32,5 +32,7 @@ Parameters: diff --git a/templates/backOffice/default/includes/image-upload-list-ajax.html b/templates/backOffice/default/includes/image-upload-list-ajax.html index 8acb5c7ef..937aca1a5 100755 --- a/templates/backOffice/default/includes/image-upload-list-ajax.html +++ b/templates/backOffice/default/includes/image-upload-list-ajax.html @@ -9,14 +9,15 @@ Parameters: *} {ifloop rel="image"} -
- {loop type="image" name="image" source="{$imageType}" order="manual-reverse" source_id="{$parentId}" width="200" height="100" resize_mode="borders"} -
+
    + {loop type="image" name="image" source="{$imageType}" order="manual" source_id="{$parentId}" width="200" height="100" resize_mode="borders"} +
  • {$TITLE}
    + {$POSITION} @@ -24,9 +25,9 @@ Parameters:
    -
+ {/loop} -
+ {/ifloop} {elseloop rel="image"}
{intl l='There is no images attached to this %type.' type=$imageType}
diff --git a/templates/backOffice/default/product-edit.html b/templates/backOffice/default/product-edit.html index 36af15aa0..e0266d637 100755 --- a/templates/backOffice/default/product-edit.html +++ b/templates/backOffice/default/product-edit.html @@ -144,6 +144,10 @@ {/javascripts} + {javascripts file='assets/js/jquery-ui-1.10.3.custom.min.js'} + + {/javascripts} +