Merge branch 'master' of https://github.com/thelia/thelia into coupon

# By franck
# Via franck
* 'master' of https://github.com/thelia/thelia:
  Typo
  Added UrlRewritingTrait to manage URLs from model classes
  Started category management
This commit is contained in:
gmorel
2013-09-16 22:47:58 +02:00
38 changed files with 1074 additions and 1234 deletions

View File

@@ -24,52 +24,88 @@
namespace Thelia\Action; namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Category as CategoryModel;
use Thelia\Model\CategoryQuery; use Thelia\Model\CategoryQuery;
use Thelia\Model\Category as CategoryModel;
use Propel\Runtime\ActiveQuery\Criteria; use Thelia\Core\Event\TheliaEvents;
use Propel\Runtime\Propel;
use Thelia\Model\Map\CategoryTableMap;
use Thelia\Core\Event\CategoryUpdateEvent;
use Thelia\Core\Event\CategoryCreateEvent; use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Core\Event\CategoryDeleteEvent; use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Model\ConfigQuery;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent; use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryChangePositionEvent;
class Category extends BaseAction implements EventSubscriberInterface class Category extends BaseAction implements EventSubscriberInterface
{ {
/**
* Create a new category entry
*
* @param CategoryCreateEvent $event
*/
public function create(CategoryCreateEvent $event) public function create(CategoryCreateEvent $event)
{ {
$category = new CategoryModel(); $category = new CategoryModel();
$category $category
->setDispatcher($this->getDispatcher()) ->setDispatcher($this->getDispatcher())
->create(
$event->getTitle(), ->setLocale($event->getLocale())
$event->getParent(), ->setTitle($event->getTitle())
$event->getLocale() ->setParent($event->getParent())
); ->setVisible($event->getVisible())
->save()
;
$event->setCategory($category); $event->setCategory($category);
} }
public function update(CategoryChangeEvent $event) /**
* Change a category
*
* @param CategoryUpdateEvent $event
*/
public function update(CategoryUpdateEvent $event)
{ {
$search = CategoryQuery::create();
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
$category
->setDispatcher($this->getDispatcher())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->setParent($event->getParent())
->setVisible($event->getVisible())
->save();
$event->setCategory($category);
}
} }
/** /**
* Delete a category * Delete a category entry
* *
* @param ActionEvent $event * @param CategoryDeleteEvent $event
*/ */
public function delete(CategoryDeleteEvent $event) public function delete(CategoryDeleteEvent $event)
{ {
$category = CategoryQuery::create()->findPk($event->getCategoryId()); if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
if ($category !== null) { $category
->setDispatcher($this->getDispatcher())
->delete()
;
$category->setDispatcher($this->getDispatcher())->delete(); $event->setCategory($category);
} }
} }
@@ -80,178 +116,48 @@ class Category extends BaseAction implements EventSubscriberInterface
*/ */
public function toggleVisibility(CategoryToggleVisibilityEvent $event) public function toggleVisibility(CategoryToggleVisibilityEvent $event)
{ {
$category = CategoryQuery::create()->findPk($event->getCategoryId()); $category = $event->getCategory();
if ($category !== null) { $category
->setDispatcher($this->getDispatcher())
$category ->setVisible($category->getVisible() ? false : true)
->setDispatcher($this->getDispatcher()) ->save()
->setVisible($category->getVisible() ? false : true)
->save()
; ;
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $category = CategoryQuery::create()->findPk($event->getObjectId())) {
$category->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $category->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $category->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $category->movePositionDown();
} }
} }
/** /**
* Changes category position, selecting absolute ou relative change. * {@inheritDoc}
*
* @param CategoryChangePositionEvent $event
*/
public function changePosition(CategoryChangePositionEvent $event)
{
if ($event->getMode() == CategoryChangePositionEvent::POSITION_ABSOLUTE)
return $this->changeAbsolutePosition($event);
else
return $this->exchangePosition($event);
}
/**
* Move up or down a category
*
* @param CategoryChangePositionEvent $event
*/
protected function exchangePosition(CategoryChangePositionEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
if ($category !== null) {
// The current position of the category
$my_position = $category->getPosition();
// Find category to exchange position with
$search = CategoryQuery::create()
->filterByParent($category->getParent());
// Up or down ?
if ($event->getMode() == CategoryChangePositionEvent::POSITION_UP) {
// Find the category immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
} elseif ($event->getMode() == CategoryChangePositionEvent::POSITION_DOWN) {
// Find the category immediately after me
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
} else
return;
$result = $search->findOne();
// If we found the proper category, exchange their positions
if ($result) {
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
$category
->setDispatcher($this->getDispatcher())
->setPosition($result->getPosition())
->save()
;
$result->setPosition($my_position)->save();
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Changes category position
*
* @param CategoryChangePositionEvent $event
*/
protected function changeAbsolutePosition(CategoryChangePositionEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
if ($category !== null) {
// The required position
$new_position = $event->getPosition();
// The current position
$current_position = $category->getPosition();
if ($new_position != null && $new_position > 0 && $new_position != $current_position) {
// Find categories to offset
$search = CategoryQuery::create()->filterByParent($category->getParent());
if ($new_position > $current_position) {
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position));
$delta = -1;
} else {
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
$search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1));
$delta = 1;
}
$results = $search->find();
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
foreach ($results as $result) {
$result->setPosition($result->getPosition() + $delta)->save($cnx);
}
$category
->setDispatcher($this->getDispatcher())
->setPosition($new_position)
->save($cnx)
;
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Returns an array of event names this subscriber listens to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/ */
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array( return array(
TheliaEvents::CATEGORY_CREATE => array("create", 128), TheliaEvents::CATEGORY_CREATE => array("create", 128),
TheliaEvents::CATEGORY_UPDATE => array("update", 128), TheliaEvents::CATEGORY_UPDATE => array("update", 128),
TheliaEvents::CATEGORY_DELETE => array("delete", 128), TheliaEvents::CATEGORY_DELETE => array("delete", 128),
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128), TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128), TheliaEvents::CATEGORY_UPDATE_POSITION => array("updatePosition", 128)
"action.updateCategoryPositionU" => array("changePositionUp", 128),
"action.updateCategoryPositionDown" => array("changePositionDown", 128),
"action.updateCategoryPosition" => array("changePosition", 128),
); );
} }
} }

View File

@@ -22,7 +22,6 @@
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Action; namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Model\ConfigQuery; use Thelia\Model\ConfigQuery;
@@ -45,18 +44,9 @@ class Config extends BaseAction implements EventSubscriberInterface
{ {
$config = new ConfigModel(); $config = new ConfigModel();
$config $config->setDispatcher($this->getDispatcher())->setName($event->getEventName())->setValue($event->getValue())
->setDispatcher($this->getDispatcher()) ->setLocale($event->getLocale())->setTitle($event->getTitle())->setHidden($event->getHidden())
->setSecured($event->getSecured())->save();
->setName($event->getEventName())
->setValue($event->getValue())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setHidden($event->getHidden())
->setSecured($event->getSecured())
->save()
;
$event->setConfig($config); $event->setConfig($config);
} }
@@ -70,18 +60,13 @@ class Config extends BaseAction implements EventSubscriberInterface
{ {
$search = ConfigQuery::create(); $search = ConfigQuery::create();
if (null !== $config = $search->findOneById($event->getConfigId())) { if (null !== $config = $search->findPk($event->getConfigId())) {
if ($event->getValue() !== $config->getValue()) { if ($event->getValue() !== $config->getValue()) {
$config $config->setDispatcher($this->getDispatcher())->setValue($event->getValue())->save();
->setDispatcher($this->getDispatcher())
->setValue($event->getValue()) $event->setConfig($config);
->save()
;
$event->setConfig($config);
} }
} }
} }
@@ -95,23 +80,12 @@ class Config extends BaseAction implements EventSubscriberInterface
{ {
$search = ConfigQuery::create(); $search = ConfigQuery::create();
if (null !== $config = ConfigQuery::create()->findOneById($event->getConfigId())) { if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
$config $config->setDispatcher($this->getDispatcher())->setName($event->getEventName())->setValue($event->getValue())
->setDispatcher($this->getDispatcher()) ->setHidden($event->getHidden())->setSecured($event->getSecured())->setLocale($event->getLocale())
->setTitle($event->getTitle())->setDescription($event->getDescription())->setChapo($event->getChapo())
->setName($event->getEventName()) ->setPostscriptum($event->getPostscriptum())->save();
->setValue($event->getValue())
->setHidden($event->getHidden())
->setSecured($event->getSecured())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->save();
$event->setConfig($config); $event->setConfig($config);
} }
@@ -125,14 +99,11 @@ class Config extends BaseAction implements EventSubscriberInterface
public function delete(ConfigDeleteEvent $event) public function delete(ConfigDeleteEvent $event)
{ {
if (null !== ($config = ConfigQuery::create()->findOneById($event->getConfigId()))) { if (null !== ($config = ConfigQuery::create()->findPk($event->getConfigId()))) {
if (! $config->getSecured()) { if (!$config->getSecured()) {
$config $config->setDispatcher($this->getDispatcher())->delete();
->setDispatcher($this->getDispatcher())
->delete()
;
$event->setConfig($config); $event->setConfig($config);
} }
@@ -145,10 +116,15 @@ class Config extends BaseAction implements EventSubscriberInterface
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array( return array(
TheliaEvents::CONFIG_CREATE => array("create", 128), TheliaEvents::CONFIG_CREATE => array(
TheliaEvents::CONFIG_SETVALUE => array("setValue", 128), "create", 128
TheliaEvents::CONFIG_UPDATE => array("modify", 128), ), TheliaEvents::CONFIG_SETVALUE => array(
TheliaEvents::CONFIG_DELETE => array("delete", 128), "setValue", 128
), TheliaEvents::CONFIG_UPDATE => array(
"modify", 128
), TheliaEvents::CONFIG_DELETE => array(
"delete", 128
),
); );
} }
} }

View File

@@ -71,7 +71,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
{ {
$search = CurrencyQuery::create(); $search = CurrencyQuery::create();
if (null !== $currency = CurrencyQuery::create()->findOneById($event->getCurrencyId())) { if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
$currency $currency
->setDispatcher($this->getDispatcher()) ->setDispatcher($this->getDispatcher())
@@ -97,7 +97,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
{ {
$search = CurrencyQuery::create(); $search = CurrencyQuery::create();
if (null !== $currency = CurrencyQuery::create()->findOneById($event->getCurrencyId())) { if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
if ($currency->getByDefault() != $event->getIsDefault()) { if ($currency->getByDefault() != $event->getIsDefault()) {
@@ -123,7 +123,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
public function delete(CurrencyDeleteEvent $event) public function delete(CurrencyDeleteEvent $event)
{ {
if (null !== ($currency = CurrencyQuery::create()->findOneById($event->getCurrencyId()))) { if (null !== ($currency = CurrencyQuery::create()->findPk($event->getCurrencyId()))) {
$currency $currency
->setDispatcher($this->getDispatcher()) ->setDispatcher($this->getDispatcher())

View File

@@ -70,7 +70,7 @@ class Message extends BaseAction implements EventSubscriberInterface
{ {
$search = MessageQuery::create(); $search = MessageQuery::create();
if (null !== $message = MessageQuery::create()->findOneById($event->getMessageId())) { if (null !== $message = MessageQuery::create()->findPk($event->getMessageId())) {
$message $message
->setDispatcher($this->getDispatcher()) ->setDispatcher($this->getDispatcher())
@@ -99,7 +99,7 @@ class Message extends BaseAction implements EventSubscriberInterface
public function delete(MessageDeleteEvent $event) public function delete(MessageDeleteEvent $event)
{ {
if (null !== ($message = MessageQuery::create()->findOneById($event->getMessageId()))) { if (null !== ($message = MessageQuery::create()->findPk($event->getMessageId()))) {
$message $message
->setDispatcher($this->getDispatcher()) ->setDispatcher($this->getDispatcher())

View File

@@ -51,7 +51,7 @@
<form name="thelia.address.update" class="Thelia\Form\AddressUpdateForm" /> <form name="thelia.address.update" class="Thelia\Form\AddressUpdateForm" />
<form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/> <form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/>
<form name="thelia.admin.category.deletion" class="Thelia\Form\CategoryModificationForm"/> <form name="thelia.admin.category.modification" class="Thelia\Form\CategoryModificationForm"/>
<form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/> <form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/>
<form name="thelia.admin.product.deletion" class="Thelia\Form\ProductModificationForm"/> <form name="thelia.admin.product.deletion" class="Thelia\Form\ProductModificationForm"/>

View File

@@ -85,7 +85,7 @@
</route> </route>
<route id="admin.categories.set-default" path="/admin/categories/toggle-online"> <route id="admin.categories.set-default" path="/admin/categories/toggle-online">
<default key="_controller">Thelia\Controller\Admin\CategoryController::toggleOnlineAction</default> <default key="_controller">Thelia\Controller\Admin\CategoryController::setToggleVisibilityAction</default>
</route> </route>
<route id="admin.categories.delete" path="/admin/categories/delete"> <route id="admin.categories.delete" path="/admin/categories/delete">

View File

@@ -240,6 +240,17 @@ abstract class AbstractCrudController extends BaseAdminController
return null; return null;
} }
/**
* Put in this method post object position change processing if required.
*
* @param unknown $deleteEvent the delete event
* @return Response a response, or null to continue normal processing
*/
protected function performAdditionalUpdatePositionAction($positionChangeEvent)
{
return null;
}
/** /**
* Return the current list order identifier, updating it in the same time. * Return the current list order identifier, updating it in the same time.
*/ */
@@ -309,14 +320,18 @@ abstract class AbstractCrudController extends BaseAdminController
$this->adminLogAppend(sprintf("%s %s (ID %s) created", ucfirst($this->objectName), $this->getObjectLabel($createdObject), $this->getObjectId($createdObject))); $this->adminLogAppend(sprintf("%s %s (ID %s) created", ucfirst($this->objectName), $this->getObjectLabel($createdObject), $this->getObjectId($createdObject)));
} }
$this->performAdditionalCreateAction($createEvent); $response = $this->performAdditionalCreateAction($createEvent);
// Substitute _ID_ in the URL with the ID of the created object if ($response == null) {
$successUrl = str_replace('_ID_', $this->getObjectId($createdObject), $creationForm->getSuccessUrl()); // Substitute _ID_ in the URL with the ID of the created object
$successUrl = str_replace('_ID_', $this->getObjectId($createdObject), $creationForm->getSuccessUrl());
// Redirect to the success URL
$this->redirect($successUrl);
// Redirect to the success URL
$this->redirect($successUrl);
}
else {
return $response;
}
} }
catch (FormValidationException $ex) { catch (FormValidationException $ex) {
// Form cannot be validated // Form cannot be validated
@@ -396,16 +411,21 @@ abstract class AbstractCrudController extends BaseAdminController
$this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject)));
} }
$this->performAdditionalUpdateAction($changeEvent); $response = $this->performAdditionalUpdateAction($changeEvent);
// If we have to stay on the same page, do not redirect to the succesUrl, if ($response == null) {
// just redirect to the edit page again. // If we have to stay on the same page, do not redirect to the succesUrl,
if ($this->getRequest()->get('save_mode') == 'stay') { // just redirect to the edit page again.
$this->redirectToEditionTemplate($this->getRequest()); if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToEditionTemplate($this->getRequest());
}
// Redirect to the success URL
$this->redirect($changeForm->getSuccessUrl());
}
else {
return $response;
} }
// Redirect to the success URL
$this->redirect($changeForm->getSuccessUrl());
} }
catch (FormValidationException $ex) { catch (FormValidationException $ex) {
// Form cannot be validated // Form cannot be validated
@@ -452,7 +472,14 @@ abstract class AbstractCrudController extends BaseAdminController
return $this->errorPage($ex); return $this->errorPage($ex);
} }
$this->redirectToListTemplate(); $response = $this->performAdditionalUpdatePositionAction($event);
if ($response == null) {
$this->redirectToListTemplate();
}
else {
return $response;
}
} }
/** /**
@@ -475,7 +502,7 @@ abstract class AbstractCrudController extends BaseAdminController
return $this->errorPage($ex); return $this->errorPage($ex);
} }
$this->redirectToRoute('admin.categories.default'); $this->redirectToListTemplate();
} }
/** /**

View File

@@ -33,7 +33,7 @@ use Thelia\Form\AttributeAvCreationForm;
use Thelia\Core\Event\UpdatePositionEvent; use Thelia\Core\Event\UpdatePositionEvent;
/** /**
* Manages attributes-av sent by mail * Manages attributes-av
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -37,7 +37,7 @@ use Thelia\Core\Event\AttributeAvUpdateEvent;
use Thelia\Core\Event\AttributeEvent; use Thelia\Core\Event\AttributeEvent;
/** /**
* Manages attributes sent by mail * Manages attributes
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -23,226 +23,160 @@
namespace Thelia\Controller\Admin; namespace Thelia\Controller\Admin;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Form\CategoryCreationForm;
use Thelia\Core\Event\CategoryDeleteEvent; use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Core\Event\CategoryUpdatePositionEvent; use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryUpdateEvent;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Model\CategoryQuery; use Thelia\Model\CategoryQuery;
use Thelia\Form\CategoryModificationForm; use Thelia\Form\CategoryModificationForm;
use Thelia\Form\CategoryCreationForm;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
class CategoryController extends BaseAdminController /**
* Manages categories
*
* @author Franck Allimant <franck@cqfdev.fr>
*/
class CategoryController extends AbstractCrudController
{ {
/** public function __construct() {
* Render the categories list, ensuring the sort order is set. parent::__construct(
* 'category',
* @return Symfony\Component\HttpFoundation\Response the response 'manual',
*/ 'category_order',
protected function renderList()
{ 'admin.categories.default',
return $this->render('categories', $this->getTemplateArgs()); 'admin.categories.create',
'admin.categories.update',
'admin.categories.delete',
TheliaEvents::CATEGORY_CREATE,
TheliaEvents::CATEGORY_UPDATE,
TheliaEvents::CATEGORY_DELETE,
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY,
TheliaEvents::CATEGORY_UPDATE_POSITION
);
} }
protected function getTemplateArgs() protected function getCreationForm() {
{ return new CategoryCreationForm($this->getRequest());
// Get the category ID }
$category_id = $this->getRequest()->get('category_id', 0);
// Find the current category order protected function getUpdateForm() {
$category_order = $this->getRequest()->get( return new CategoryModificationForm($this->getRequest());
'order', }
$this->getSession()->get('admin.category_order', 'manual')
protected function getCreationEvent($formData) {
$createEvent = new CategoryCreateEvent();
$createEvent
->setTitle($formData['title'])
->setLocale($formData["locale"])
->setParent($formData['parent'])
->setVisible($formData['visible'])
;
return $createEvent;
}
protected function getUpdateEvent($formData) {
$changeEvent = new CategoryUpdateEvent($formData['id']);
// Create and dispatch the change event
$changeEvent
->setLocale($formData['locale'])
->setTitle($formData['title'])
->setChapo($formData['chapo'])
->setDescription($formData['description'])
->setPostscriptum($formData['postscriptum'])
->setVisible($formData['visible'])
->setUrl($formData['url'])
->setParent($formData['parent'])
;
return $changeEvent;
}
protected function createUpdatePositionEvent($positionChangeMode, $positionValue) {
return new UpdatePositionEvent(
$this->getRequest()->get('category_id', null),
$positionChangeMode,
$positionValue
);
}
protected function getDeleteEvent() {
return new CategoryDeleteEvent($this->getRequest()->get('category_id', 0));
}
protected function eventContainsObject($event) {
return $event->hasCategory();
}
protected function hydrateObjectForm($object) {
// Prepare the data that will hydrate the form
$data = array(
'id' => $object->getId(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'chapo' => $object->getChapo(),
'description' => $object->getDescription(),
'postscriptum' => $object->getPostscriptum(),
'visible' => $object->getVisible(),
'url' => $object->getRewritenUrl($this->getCurrentEditionLocale()),
'parent' => $object->getParent()
); );
$args = array( // Setup the object form
'current_category_id' => $category_id, return new CategoryModificationForm($this->getRequest(), "form", $data);
'category_order' => $category_order, }
protected function getObjectFromEvent($event) {
return $event->hasCategory() ? $event->getCategory() : null;
}
protected function getExistingObject() {
return CategoryQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->findOneById($this->getRequest()->get('category_id', 0));
}
protected function getObjectLabel($object) {
return $object->getTitle();
}
protected function getObjectId($object) {
return $object->getId();
}
protected function renderListTemplate($currentOrder) {
return $this->render('categories',
array(
'category_order' => $currentOrder,
'category_id' => $this->getRequest()->get('category_id', 0)
)
);
}
protected function renderEditionTemplate() {
return $this->render('category-edit', array('category_id' => $this->getRequest()->get('category_id', 0)));
}
protected function redirectToEditionTemplate() {
$this->redirectToRoute(
"admin.categories.update",
array('category_id' => $this->getRequest()->get('category_id', 0))
); );
// Store the current sort order in session
$this->getSession()->set('admin.category_order', $category_order);
return $args;
} }
/** protected function redirectToListTemplate() {
* The default action is displaying the categories list. $this->redirectToRoute(
* 'admin.categories.default',
* @return Symfony\Component\HttpFoundation\Response the response array('category_id' => $this->getRequest()->get('category_id', 0))
*/
public function defaultAction()
{
if (null !== $response = $this->checkAuth("admin.categories.view")) return $response;
return $this->renderList();
}
/**
* Create a new category object
*
* @return Symfony\Component\HttpFoundation\Response the response
*/
public function createAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.create")) return $response;
$error_msg = false;
// Create the Creation Form
$creationForm = new CategoryCreationForm($this->getRequest());
try {
// Validate the form, create the CategoryCreation event and dispatch it.
$form = $this->validateForm($creationForm, "POST");
$data = $form->getData();
$createEvent = new CategoryCreateEvent(
$data["title"],
$data["parent"],
$data["locale"]
);
$this->dispatch(TheliaEvents::CATEGORY_CREATE, $createEvent);
if (! $createEvent->hasCategory()) throw new \LogicException($this->getTranslator()->trans("No category was created."));
$createdObject = $createEvent->getCategory();
// Log category creation
$this->adminLogAppend(sprintf("Category %s (ID %s) created", $createdObject->getTitle(), $createdObject->getId()));
// Substitute _ID_ in the URL with the ID of the created object
$successUrl = str_replace('_ID_', $createdObject->getId(), $creationForm->getSuccessUrl());
// Redirect to the success URL
$this->redirect($successUrl);
} catch (FormValidationException $ex) {
// Form cannot be validated
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
} catch (\Exception $ex) {
// Any other error
$error_msg = $ex->getMessage();
}
$this->setupFormErrorContext("category creation", $error_msg, $creationForm, $ex);
// At this point, the form has error, and should be redisplayed.
return $this->renderList();
}
/**
* Load a category object for modification, and display the edit template.
*
* @return Symfony\Component\HttpFoundation\Response the response
*/
public function changeAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.update")) return $response;
// Load the category object
$category = CategoryQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->findOneById($this->getRequest()->get('category_id'));
if ($category != null) {
// Prepare the data that will hydrate the form
$data = array(
'id' => $category->getId(),
'locale' => $category->getLocale(),
'title' => $category->getTitle(),
'chapo' => $category->getChapo(),
'description' => $category->getDescription(),
'postscriptum' => $category->getPostscriptum(),
'parent' => $category->getParent(),
'visible' => $category->getVisible() ? true : false,
'url' => $category->getUrl($this->getCurrentEditionLocale())
// tbc !!!
);
// Setup the object form
$changeForm = new CategoryModificationForm($this->getRequest(), "form", $data);
// Pass it to the parser
$this->getParserContext()->addForm($changeForm);
}
// Render the edition template.
return $this->render('category-edit', $this->getTemplateArgs());
}
/**
* Save changes on a modified category object, and either go back to the category list, or stay on the edition page.
*
* @return Symfony\Component\HttpFoundation\Response the response
*/
public function saveChangeAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.update")) return $response;
$error_msg = false;
// Create the form from the request
$changeForm = new CategoryModificationForm($this->getRequest());
// Get the category ID
$category_id = $this->getRequest()->get('category_id');
try {
// Check the form against constraints violations
$form = $this->validateForm($changeForm, "POST");
// Get the form field values
$data = $form->getData();
$changeEvent = new CategoryUpdateEvent($data['id']);
// Create and dispatch the change event
$changeEvent
->setCategoryName($data['name'])
->setLocale($data["locale"])
->setSymbol($data['symbol'])
->setCode($data['code'])
->setRate($data['rate'])
;
$this->dispatch(TheliaEvents::CATEGORY_UPDATE, $changeEvent);
if (! $createEvent->hasCategory()) throw new \LogicException($this->getTranslator()->trans("No category was updated."));
// Log category modification
$changedObject = $changeEvent->getCategory();
$this->adminLogAppend(sprintf("Category %s (ID %s) modified", $changedObject->getTitle(), $changedObject->getId()));
// If we have to stay on the same page, do not redirect to the succesUrl,
// just redirect to the edit page again.
if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToRoute(
"admin.categories.update",
array('category_id' => $category_id)
); );
}
// Redirect to the success URL
$this->redirect($changeForm->getSuccessUrl());
} catch (FormValidationException $ex) {
// Form cannot be validated
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
} catch (\Exception $ex) {
// Any other error
$error_msg = $ex->getMessage();
}
$this->setupFormErrorContext("category modification", $error_msg, $changeForm, $ex);
// At this point, the form has errors, and should be redisplayed.
return $this->render('category-edit', array('category_id' => $category_id));
} }
/** /**
@@ -253,74 +187,41 @@ class CategoryController extends BaseAdminController
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; if (null !== $response = $this->checkAuth("admin.categories.update")) return $response;
$changeEvent = new CategoryUpdateEvent($this->getRequest()->get('category_id', 0)); $event = new CategoryToggleVisibilityEvent($this->getExistingObject());
// Create and dispatch the change event
$changeEvent->setIsDefault(true);
try { try {
$this->dispatch(TheliaEvents::CATEGORY_SET_DEFAULT, $changeEvent); $this->dispatch(TheliaEvents::CATEGORY_TOGGLE_VISIBILITY, $event);
} catch (\Exception $ex) { } catch (\Exception $ex) {
// Any error // Any error
return $this->errorPage($ex); return $this->errorPage($ex);
} }
$this->redirectToRoute('admin.categories.default'); // Ajax response -> no action
return $this->nullResponse();
} }
/** protected function performAdditionalDeleteAction($deleteEvent)
* Update categoryposition
*/
public function updatePositionAction()
{ {
// Check current user authorization // Redirect to parent category list
if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; $this->redirectToRoute(
'admin.categories.default',
array('category_id' => $deleteEvent->getCategory()->getParent())
);
}
try { protected function performAdditionalUpdatePositionAction($event)
$mode = $this->getRequest()->get('mode', null); {
if ($mode == 'up') $category = CategoryQuery::create()->findPk($event->getObjectId());
$mode = CategoryUpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = CategoryUpdatePositionEvent::POSITION_DOWN;
else
$mode = CategoryUpdatePositionEvent::POSITION_ABSOLUTE;
$position = $this->getRequest()->get('position', null); if ($category != null) {
// Redirect to parent category list
$event = new CategoryUpdatePositionEvent( $this->redirectToRoute(
$this->getRequest()->get('category_id', null), 'admin.categories.default',
$mode, array('category_id' => $category->getParent())
$this->getRequest()->get('position', null)
); );
$this->dispatch(TheliaEvents::CATEGORY_UPDATE_POSITION, $event);
} catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
} }
$this->redirectToRoute('admin.categories.default'); return null;
}
/**
* Delete a category object
*
* @return Symfony\Component\HttpFoundation\Response the response
*/
public function deleteAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.delete")) return $response;
// Get the category id, and dispatch the deleted request
$event = new CategoryDeleteEvent($this->getRequest()->get('category_id'));
$this->dispatch(TheliaEvents::CATEGORY_DELETE, $event);
if ($event->hasCategory())
$this->adminLogAppend(sprintf("Category %s (ID %s) deleted", $event->getCategory()->getTitle(), $event->getCategory()->getId()));
$this->redirectToRoute('admin.categories.default');
} }
} }

View File

@@ -33,7 +33,7 @@ use Thelia\Form\ConfigCreationForm;
use Thelia\Core\Event\UpdatePositionEvent; use Thelia\Core\Event\UpdatePositionEvent;
/** /**
* Manages variables sent by mail * Manages variables
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -33,7 +33,7 @@ use Thelia\Form\CurrencyCreationForm;
use Thelia\Core\Event\UpdatePositionEvent; use Thelia\Core\Event\UpdatePositionEvent;
/** /**
* Manages currencies sent by mail * Manages currencies
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -33,7 +33,7 @@ use Thelia\Form\FeatureAvCreationForm;
use Thelia\Core\Event\UpdatePositionEvent; use Thelia\Core\Event\UpdatePositionEvent;
/** /**
* Manages features-av sent by mail * Manages features-av
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -37,7 +37,7 @@ use Thelia\Core\Event\FeatureAvUpdateEvent;
use Thelia\Core\Event\FeatureEvent; use Thelia\Core\Event\FeatureEvent;
/** /**
* Manages features sent by mail * Manages features
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -41,7 +41,7 @@ use Thelia\Core\Event\TemplateAddFeatureEvent;
use Thelia\Core\Event\TemplateDeleteFeatureEvent; use Thelia\Core\Event\TemplateDeleteFeatureEvent;
/** /**
* Manages templates sent by mail * Manages product templates
* *
* @author Franck Allimant <franck@cqfdev.fr> * @author Franck Allimant <franck@cqfdev.fr>
*/ */

View File

@@ -28,13 +28,7 @@ class CategoryCreateEvent extends CategoryEvent
protected $title; protected $title;
protected $parent; protected $parent;
protected $locale; protected $locale;
protected $visible;
public function __construct($title, $parent, $locale)
{
$this->title = $title;
$this->parent = $parent;
$this->locale = $locale;
}
public function getTitle() public function getTitle()
{ {
@@ -71,4 +65,16 @@ class CategoryCreateEvent extends CategoryEvent
return $this; return $this;
} }
public function getVisible()
{
return $this->visible;
}
public function setVisible($visible)
{
$this->visible = $visible;
return $this;
}
} }

View File

@@ -0,0 +1,28 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
class CategoryToggleVisibilityEvent extends CategoryEvent
{
}

View File

@@ -32,7 +32,6 @@ class CategoryUpdateEvent extends CategoryCreateEvent
protected $postscriptum; protected $postscriptum;
protected $url; protected $url;
protected $visibility;
protected $parent; protected $parent;
public function __construct($category_id) public function __construct($category_id)
@@ -100,18 +99,6 @@ class CategoryUpdateEvent extends CategoryCreateEvent
return $this; return $this;
} }
public function getVisibility()
{
return $this->visibility;
}
public function setVisibility($visibility)
{
$this->visibility = $visibility;
return $this;
}
public function getParent() public function getParent()
{ {
return $this->parent; return $this->parent;

View File

@@ -145,50 +145,21 @@ final class TheliaEvents
// -- END ADDRESS MANAGEMENT --------------------------------------------------------- // -- END ADDRESS MANAGEMENT ---------------------------------------------------------
/** // -- Categories management -----------------------------------------------
* Sent once the category creation form has been successfully validated, and before category insertion in the database.
*/
const BEFORE_CREATECATEGORY = "action.before_createcategory";
/** const CATEGORY_CREATE = "action.createCategory";
* Create, change or delete a category const CATEGORY_UPDATE = "action.updateCategory";
*/ const CATEGORY_DELETE = "action.deleteCategory";
const CATEGORY_CREATE = "action.createCategory";
const CATEGORY_UPDATE = "action.updateCategory";
const CATEGORY_DELETE = "action.deleteCategory";
/**
* Toggle category visibility
*/
const CATEGORY_TOGGLE_VISIBILITY = "action.toggleCategoryVisibility"; const CATEGORY_TOGGLE_VISIBILITY = "action.toggleCategoryVisibility";
const CATEGORY_UPDATE_POSITION = "action.updateCategoryPosition";
/** const BEFORE_CREATECATEGORY = "action.before_createcategory";
* Change category position
*/
const CATEGORY_CHANGE_POSITION = "action.updateCategoryPosition";
/**
* Sent just after a successful insert of a new category in the database.
*/
const AFTER_CREATECATEGORY = "action.after_createcategory"; const AFTER_CREATECATEGORY = "action.after_createcategory";
/**
* Sent befonre deleting a category
*/
const BEFORE_DELETECATEGORY = "action.before_deletecategory";
/** const BEFORE_DELETECATEGORY = "action.before_deletecategory";
* Sent just after a successful delete of a category from the database.
*/
const AFTER_DELETECATEGORY = "action.after_deletecategory"; const AFTER_DELETECATEGORY = "action.after_deletecategory";
/**
* Sent just before a successful change of a category in the database.
*/
const BEFORE_UPDATECATEGORY = "action.before_updateCategory"; const BEFORE_UPDATECATEGORY = "action.before_updateCategory";
/**
* Sent just after a successful change of a category in the database.
*/
const AFTER_UPDATECATEGORY = "action.after_updateCategory"; const AFTER_UPDATECATEGORY = "action.after_updateCategory";
/** /**

View File

@@ -173,6 +173,22 @@ class Category extends BaseI18nLoop
$loopResult = new LoopResult($categories); $loopResult = new LoopResult($categories);
foreach ($categories as $category) { foreach ($categories as $category) {
// Find previous and next category
$previous = CategoryQuery::create()
->filterByParent($category->getParent())
->filterByPosition($category->getPosition(), Criteria::LESS_THAN)
->orderByPosition(Criteria::DESC)
->findOne()
;
$next = CategoryQuery::create()
->filterByParent($category->getParent())
->filterByPosition($category->getPosition(), Criteria::GREATER_THAN)
->orderByPosition(Criteria::ASC)
->findOne()
;
/* /*
* no cause pagination lost : * no cause pagination lost :
* if ($this->getNotEmpty() && $category->countAllProducts() == 0) continue; * if ($this->getNotEmpty() && $category->countAllProducts() == 0) continue;
@@ -193,7 +209,13 @@ class Category extends BaseI18nLoop
->set("PRODUCT_COUNT", $category->countChild()) ->set("PRODUCT_COUNT", $category->countChild())
->set("VISIBLE", $category->getVisible() ? "1" : "0") ->set("VISIBLE", $category->getVisible() ? "1" : "0")
->set("POSITION", $category->getPosition()) ->set("POSITION", $category->getPosition())
;
->set("HAS_PREVIOUS", $previous != null ? 1 : 0)
->set("HAS_NEXT" , $next != null ? 1 : 0)
->set("PREVIOUS", $previous != null ? $previous->getId() : -1)
->set("NEXT" , $next != null ? $next->getId() : -1)
;
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -59,7 +59,7 @@ class CategoryTree extends BaseI18nLoop
} }
// changement de rubrique // changement de rubrique
protected function buildCategoryTree($parent, $visible, $level, $max_level, array $exclude, LoopResult &$loopResult) protected function buildCategoryTree($parent, $visible, $level, $max_level, $exclude, LoopResult &$loopResult)
{ {
if ($level > $max_level) return; if ($level > $max_level) return;
@@ -73,7 +73,7 @@ class CategoryTree extends BaseI18nLoop
if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible); if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible);
$search->filterById($exclude, Criteria::NOT_IN); if ($exclude != null) $search->filterById($exclude, Criteria::NOT_IN);
$search->orderByPosition(Criteria::ASC); $search->orderByPosition(Criteria::ASC);

View File

@@ -39,7 +39,8 @@ class CategoryCreationForm extends BaseForm
"for" => "title" "for" => "title"
) )
)) ))
->add("parent", "integer", array( ->add("parent", "text", array(
"label" => Translator::getInstance()->trans("Parent category *"),
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
) )
@@ -49,6 +50,9 @@ class CategoryCreationForm extends BaseForm
new NotBlank() new NotBlank()
) )
)) ))
->add("visible", "integer", array(
"label" => Translator::getInstance()->trans("This category is online on the front office.")
))
; ;
} }

View File

@@ -24,6 +24,7 @@ namespace Thelia\Form;
use Symfony\Component\Validator\Constraints\GreaterThan; use Symfony\Component\Validator\Constraints\GreaterThan;
use Thelia\Core\Translation\Translator; use Thelia\Core\Translation\Translator;
use Symfony\Component\Validator\Constraints\NotBlank;
class CategoryModificationForm extends CategoryCreationForm class CategoryModificationForm extends CategoryCreationForm
{ {
@@ -36,12 +37,13 @@ class CategoryModificationForm extends CategoryCreationForm
$this->formBuilder $this->formBuilder
->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0))))) ->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0)))))
->add("visible", "checkbox", array( ->add("url", "text", array(
"label" => Translator::getInstance()->trans("This category is online on the front office.") "label" => Translator::getInstance()->trans("Rewriten URL *"),
"constraints" => array(new NotBlank())
)) ))
; ;
// Add standard description fields // Add standard description fields, excluding title and locale, which a re defined in parent class
$this->addStandardDescFields(array('title', 'locale')); $this->addStandardDescFields(array('title', 'locale'));
} }

View File

@@ -15,6 +15,8 @@ class Category extends BaseCategory
use \Thelia\Model\Tools\PositionManagementTrait; use \Thelia\Model\Tools\PositionManagementTrait;
use \Thelia\Model\Tools\UrlRewritingTrait;
/** /**
* @return int number of child for the current category * @return int number of child for the current category
*/ */
@@ -23,30 +25,12 @@ class Category extends BaseCategory
return CategoryQuery::countChild($this->getId()); return CategoryQuery::countChild($this->getId());
} }
public function getUrl($locale)
{
return URL::getInstance()->retrieve('category', $this->getId(), $locale)->toString();
}
/** /**
* Create a new category. * {@inheritDoc}
*
* @param string $title the category title
* @param int $parent the ID of the parent category
* @param string $locale the locale of the title
*/ */
public function create($title, $parent, $locale) protected function getRewritenUrlViewName() {
{ return 'category';
$this }
->setLocale($locale)
->setTitle($title)
->setParent($parent)
->setVisible(1)
->setPosition($this->getNextPosition($parent))
;
$this->save();
}
/** /**
* *
@@ -71,18 +55,38 @@ class Category extends BaseCategory
return $countProduct; return $countProduct;
} }
/**
* Calculate next position relative to our parent
*/
protected function addCriteriaToPositionQuery($query) {
$query->filterByParent($this->getParent());
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null) public function preInsert(ConnectionInterface $con = null)
{ {
$this->setPosition($this->getNextPosition());
$this->generateRewritenUrl($this->getLocale());
$this->dispatchEvent(TheliaEvents::BEFORE_CREATECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_CREATECATEGORY, new CategoryEvent($this));
return true; return true;
} }
/**
* {@inheritDoc}
*/
public function postInsert(ConnectionInterface $con = null) public function postInsert(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::AFTER_CREATECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::AFTER_CREATECATEGORY, new CategoryEvent($this));
} }
/**
* {@inheritDoc}
*/
public function preUpdate(ConnectionInterface $con = null) public function preUpdate(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::BEFORE_UPDATECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECATEGORY, new CategoryEvent($this));
@@ -90,16 +94,27 @@ class Category extends BaseCategory
return true; return true;
} }
/**
* {@inheritDoc}
*/
public function postUpdate(ConnectionInterface $con = null) public function postUpdate(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::AFTER_UPDATECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::AFTER_UPDATECATEGORY, new CategoryEvent($this));
} }
/**
* {@inheritDoc}
*/
public function preDelete(ConnectionInterface $con = null) public function preDelete(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::BEFORE_DELETECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_DELETECATEGORY, new CategoryEvent($this));
return true;
} }
/**
* {@inheritDoc}
*/
public function postDelete(ConnectionInterface $con = null) public function postDelete(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::AFTER_DELETECATEGORY, new CategoryEvent($this)); $this->dispatchEvent(TheliaEvents::AFTER_DELETECATEGORY, new CategoryEvent($this));

View File

@@ -4,11 +4,41 @@ namespace Thelia\Model;
use Thelia\Model\Base\Content as BaseContent; use Thelia\Model\Base\Content as BaseContent;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Propel\Runtime\Connection\ConnectionInterface;
class Content extends BaseContent class Content extends BaseContent
{ {
public function getUrl($locale) use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
use \Thelia\Model\Tools\UrlRewritingTrait;
/**
* {@inheritDoc}
*/
protected function getRewritenUrlViewName() {
return 'content';
}
/**
* Calculate next position relative to our parent
*/
protected function addCriteriaToPositionQuery($query) {
// TODO: Find the default folder for this content,
// and generate the position relative to this folder
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{ {
return URL::getInstance()->retrieve('content', $this->getId(), $locale)->toString(); $this->setPosition($this->getNextPosition());
$this->generateRewritenUrl($this->getLocale());
return true;
} }
} }

View File

@@ -4,9 +4,23 @@ namespace Thelia\Model;
use Thelia\Model\Base\Folder as BaseFolder; use Thelia\Model\Base\Folder as BaseFolder;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Propel\Runtime\Connection\ConnectionInterface;
class Folder extends BaseFolder class Folder extends BaseFolder
{ {
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
use \Thelia\Model\Tools\UrlRewritingTrait;
/**
* {@inheritDoc}
*/
protected function getRewritenUrlViewName() {
return 'folder';
}
/** /**
* @return int number of contents for the folder * @return int number of contents for the folder
*/ */
@@ -15,11 +29,6 @@ class Folder extends BaseFolder
return FolderQuery::countChild($this->getId()); return FolderQuery::countChild($this->getId());
} }
public function getUrl($locale)
{
return URL::getInstance()->retrieve('folder', $this->getId(), $locale)->toString();
}
/** /**
* *
* count all products for current category and sub categories * count all products for current category and sub categories
@@ -43,4 +52,23 @@ class Folder extends BaseFolder
return $contentsCount; return $contentsCount;
} }
/**
* Calculate next position relative to our parent
*/
protected function addCriteriaToPositionQuery($query) {
$query->filterByParent($this->getParent());
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->setPosition($this->getNextPosition());
$this->generateRewritenUrl($this->getLocale());
return true;
}
} }

View File

@@ -6,19 +6,29 @@ use Propel\Runtime\Exception\PropelException;
use Thelia\Model\Base\Product as BaseProduct; use Thelia\Model\Base\Product as BaseProduct;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Thelia\TaxEngine\Calculator; use Thelia\TaxEngine\Calculator;
use Propel\Runtime\Connection\ConnectionInterface;
class Product extends BaseProduct class Product extends BaseProduct
{ {
public function getUrl($locale) use \Thelia\Model\Tools\ModelEventDispatcherTrait;
{
return URL::getInstance()->retrieve('product', $this->getId(), $locale)->toString(); use \Thelia\Model\Tools\PositionManagementTrait;
use \Thelia\Model\Tools\UrlRewritingTrait;
/**
* {@inheritDoc}
*/
protected function getRewritenUrlViewName() {
return 'product';
} }
public function getRealLowestPrice($virtualColumnName = 'real_lowest_price') public function getRealLowestPrice($virtualColumnName = 'real_lowest_price')
{ {
try { try {
$amount = $this->getVirtualColumn($virtualColumnName); $amount = $this->getVirtualColumn($virtualColumnName);
} catch(PropelException $e) { }
catch(PropelException $e) {
throw new PropelException("Virtual column `$virtualColumnName` does not exist in Product::getRealLowestPrice"); throw new PropelException("Virtual column `$virtualColumnName` does not exist in Product::getRealLowestPrice");
} }
@@ -30,4 +40,26 @@ class Product extends BaseProduct
$taxCalculator = new Calculator(); $taxCalculator = new Calculator();
return $taxCalculator->load($this, $country)->getTaxedPrice($this->getRealLowestPrice()); return $taxCalculator->load($this, $country)->getTaxedPrice($this->getRealLowestPrice());
} }
/**
* Calculate next position relative to our default category
*/
protected function addCriteriaToPositionQuery($query) {
// TODO: Find the default category for this product,
// and generate the position relative to this category
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->setPosition($this->getNextPosition());
$this->generateRewritenUrl($this->getLocale());
return true;
}
} }

View File

@@ -0,0 +1,78 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Model\Tools;
use Thelia\Tools\URL;
/**
* A trait for managing Rewriten URLs from model classes
*/
trait UrlRewritingTrait {
/**
* @returns string the view name of the rewriten object (e.g., 'category', 'product')
*/
protected abstract function getRewritenUrlViewName();
/**
* Get the object URL for the given locale, rewriten if rewriting is enabled.
*
* @param string $locale a valid locale (e.g. en_US)
*/
public function getUrl($locale)
{
return URL::getInstance()->retrieve($this->getRewritenUrlViewName(), $this->getId(), $locale)->toString();
}
/**
* Generate a rewriten URL from the object title, and store it in the rewriting table
*
* @param string $locale a valid locale (e.g. en_US)
*/
public function generateRewritenUrl($locale)
{
URL::getInstance()->generateRewritenUrl($this->getRewritenUrlViewName(), $this->getId(), $locale, $this->getTitle());
}
/**
* return the rewriten URL for the given locale
*
* @param string $locale a valid locale (e.g. en_US)
*/
public function getRewritenUrl($locale)
{
return "fake url - TODO";
}
/**
* Set the rewriten URL for the given locale
*
* @param string $locale a valid locale (e.g. en_US)
*/
public function setRewritenUrl($locale, $url)
{
// TODO - code me !
return $this;
}
}

View File

@@ -183,6 +183,7 @@ class URL
return $this->absoluteUrl($path, $parameters); return $this->absoluteUrl($path, $parameters);
} }
/** /**
* Retrieve a rewritten URL from a view, a view id and a locale * Retrieve a rewritten URL from a view, a view id and a locale
* *
@@ -261,4 +262,50 @@ class URL
return $this->resolver; return $this->resolver;
} }
protected function sanitize($string, $force_lowercase = true, $alphabetic_only = false)
{
static $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "&#8216;", "&#8217;", "&#8220;", "&#8221;", "&#8211;", "&#8212;",
"—", "–", ",", "<", ".", ">", "/", "?");
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = preg_replace('/\s+/', "-", $clean);
$clean = ($alphabetic_only) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
/**
* Genenerate the file part of a rewriten URL from a given baseString, using a view, a view id and a locale
*
* @param $view
* @param $viewId
* @param $viewLocale
* @param $baseString the string to be converted in a valid URL
*
* @return A valid file part URL.
*/
public function generateRewritenUrl($view, $viewId, $viewLocale, $baseString)
{
// Borrowed from http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe
// Replace all weird characters with dashes
$string = preg_replace('/[^\w\-~_\.]+/u', '-', $baseString);
// Only allow one dash separator at a time (and make string lowercase)
$cleanString = mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8');
$urlFilePart = $cleanString . ".html";
// TODO :
// check if URL url already exists, and add a numeric suffix, or the like
// insert the URL in the rewriting table
}
} }

View File

@@ -217,6 +217,10 @@
text-transform: none; text-transform: none;
} }
} }
.inner-actions {
margin-top: 0.5em;
}
} }
// The overall form container // The overall form container

View File

@@ -1,396 +1,260 @@
{extends file="admin-layout.tpl"} {extends file="admin-layout.tpl"}
{block name="page-title"}{intl l='Catalog'}{/block} {block name="page-title"}{intl l='Categories'}{/block}
{block name="check-permissions"}admin.catalog.view{/block} {block name="check-permissions"}admin.categories.view{/block}
{block name="main-content"} {block name="main-content"}
<div class="catalog"> <div class="categories">
<div id="wrapper" class="container">
{include file="includes/catalog-breadcrumb.html"} <div id="wrapper" class="container">
{module_include location='catalog_top'} {include file="includes/catalog-breadcrumb.html"}
<div class="row"> {module_include location='categories_top'}
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed" id="category_list">
<caption>
{* display parent category name, and get current cat ID *}
{loop name="category_title" type="category" visible="*" id=$current_category_id}
{intl l="Categories in %cat" cat=$TITLE}
{$cat_id = $ID}
{/loop}
{elseloop rel="category_title"}
{intl l="Top level categories"}
{/elseloop}
{module_include location='category_list_caption'} <div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed" id="category_list">
<caption>
{* display parent category name, and get current cat ID *}
{loop name="category_title" type="category" visible="*" id=$category_id}
{intl l="Categories in %cat" cat=$TITLE}
{$cat_id = $ID}
{/loop}
{elseloop rel="category_title"}
{intl l="Top level categories"}
{/elseloop}
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"} {module_include location='category_list_caption'}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new category'}" href="#add_category_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
{ifloop rel="category_list"} {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"}
<thead> <a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new category'}" href="#category_creation_dialog" data-toggle="modal">
<tr> <span class="glyphicon glyphicon-plus-sign"></span>
<th class="object-title"> </a>
{admin_sortable_header {/loop}
current_order=$category_order </caption>
order='id'
reverse_order='id_reverse'
path={url path='/admin/catalog' id_category=$current_category_id}
label="{intl l='ID'}"
}
</th>
<th class="object-image">&nbsp;</th> {ifloop rel="category_list"}
<thead>
<tr>
<th class="object-title">
{admin_sortable_header
current_order=$category_order
order='id'
reverse_order='id_reverse'
path={url path='/admin/categories' id_category=$category_id}
request_parameter_name='category_order'
label="{intl l='ID'}"
}
</th>
<th class="object-title"> <th class="object-image">&nbsp;</th>
{admin_sortable_header
current_order=$category_order
order='alpha'
reverse_order='alpha_reverse'
path={url path='/admin/catalog' id_category=$current_category_id}
label="{intl l='Category title'}"
}
</th>
{module_include location='category_list_header'} <th class="object-title">
{admin_sortable_header
current_order=$category_order
order='alpha'
reverse_order='alpha_reverse'
path={url path='/admin/categories' id_category=$category_id}
request_parameter_name='category_order'
label="{intl l='Category title'}"
}
</th>
<th> {module_include location='category_list_header'}
{admin_sortable_header
current_order=$category_order
order='visible'
reverse_order='visible_reverse'
path={url path='/admin/catalog' id_category=$current_category_id}
label="{intl l='Online'}"
}
</th>
<th> <th>
{admin_sortable_header {admin_sortable_header
current_order=$category_order current_order=$category_order
order='manual' order='visible'
reverse_order='manual_reverse' reverse_order='visible_reverse'
path={url path='/admin/catalog' id_category=$current_category_id} path={url path='/admin/categories' id_category=$category_id}
label="{intl l='Position'}" request_parameter_name='category_order'
} label="{intl l='Online'}"
</th> }
</th>
<th class="actions">{intl l='Actions'}</th> <th>
</tr> {admin_sortable_header
</thead> current_order=$category_order
order='manual'
reverse_order='manual_reverse'
path={url path='/admin/categories' id_category=$category_id}
request_parameter_name='category_order'
label="{intl l='Position'}"
}
</th>
<tbody> <th class="actions">{intl l='Actions'}</th>
{loop name="category_list" type="category" visible="*" parent=$current_category_id order=$category_order backend_context="1" lang=$lang_id} </tr>
<tr> </thead>
<td>{$ID}</td>
<td> <tbody>
{loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} {loop name="category_list" type="category" visible="*" parent=$category_id order=$category_order backend_context="1" lang=$lang_id}
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}"><img class="img-thumbnail" src="{$IMAGE_URL}" alt="{$TITLE}" /></a> <tr>
{/loop} <td>{$ID}</td>
</td>
<td class="object-title"> <td>
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}"> {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
{$TITLE} <a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}"><img class="img-thumbnail" src="{$IMAGE_URL}" alt="{$TITLE}" /></a>
</a>
</td>
{module_include location='category_list_row'}
<td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="categoryVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="disabled" disabled="disabled" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{admin_position_block
permission="admin.categories.edit"
path={url path='admin/category/update-position' category_id=$ID}
url_parameter="category_id"
in_place_edit_class="categoryPositionChange"
position=$POSITION
id=$ID
}
</td>
<td>
<div class="btn-group">
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/category' category_id=$ID}"><i class="glyphicon glyphicon-folder-open"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='/admin/categories/update' category_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"}
<a class="btn btn-default btn-xs category-delete" title="{intl l='Delete this category and all its contents'}" href="#delete_category_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
{elseloop rel="category_list"}
<thead>
<tr>
<td class="message">
<div class="alert alert-info">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"}
{intl l="This category has no sub-categories. To create a new one, click the + button above."}
{/loop}
{elseloop rel="can_create"}
{intl l="This category has no sub-categories."}
{/elseloop}
</div>
</td>
</tr>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed">
<caption>
{* display parent category name *}
{loop name="category_title" type="category" visible="*" id=$current_category_id}
{intl l="Products in %cat" cat=$TITLE}
{/loop}
{elseloop rel="category_title"}
{intl l="Top level Products"}
{/elseloop}
{module_include location='product_list_caption'}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new product'}" href="#productAddModal" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
</caption>
{ifloop rel="product_list"}
<thead>
<tr>
<th class="object-title">
{admin_sortable_header
current_order=$product_order
order='id'
reverse_order='id_reverse'
path={url path='/admin/product' category_id=$current_category_id}
label="{intl l='ID'}"
}
<th>&nbsp;</th>
<th class="object-title">
{admin_sortable_header
current_order=$product_order
order='ref'
reverse_order='ref_reverse'
path={url path='/admin/product' category_id=$current_category_id}
label="{intl l='Reference'}"
}
</th>
<th class="object-title">
{admin_sortable_header
current_order=$product_order
order='alpha'
reverse_order='alpha_reverse'
path={url path='/admin/product' category_id=$current_category_id}
label="{intl l='Product title'}"
}
{module_include location='product_list_header'}
<th>
{admin_sortable_header
current_order=$product_order
order='visible'
reverse_order='visible_reverse'
path={url path='/admin/product' category_id=$current_category_id}
label="{intl l='Online'}"
}
</th>
<th>
{admin_sortable_header
current_order=$product_order
order='manual'
reverse_order='manual_reverse'
path={url path='/admin/product' category_id=$current_category_id}
label="{intl l='Position'}"
}
</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{loop name="product_list" type="product" category=$current_category_id order="manual"}
<tr>
<td>{$ID}</td>
<td>
{loop type="image" name="cat_image" source="product" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
<a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">
<img src="{$IMAGE_URL}" alt="{$TITLE}" />
</a>
{/loop}
<td class="object-title"><a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">{$REF}</a></td>
<td class="object-title"><a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">{$TITLE}</a></td>
{module_include location='product_list_row'}
<td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.products.edit"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="productVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="displayToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{admin_position_block
permission="admin.product.edit"
path={url path='admin/product' category_id=$ID}
url_parameter="product_id"
in_place_edit_class="productPositionChange"
position=$POSITION
id=$ID
}
</td>
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this product'}" href="{url path='admin/product/edit' product_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.delete"}
<a class="btn btn-default btn-xs product-delete" title="{intl l='Delete this product'}" href="{url path='admin/product/delete' id=$ID}"><i class="glyphicon glyphicon-trash"></i></a>
{/loop} {/loop}
</div> </td>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
{elseloop rel="product_list"} <td class="object-title">
<thead> <a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}">
<tr> {$TITLE}
<td class="message"><div class="alert alert-info">{intl l="This category doesn't have any products. To add a new product, <strong>click the + button</strong> above."}</div></td> </a>
</tr> </td>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
{module_include location='catalog_bottom'} {module_include location='category_list_row'}
</div>
</div>
{* Adding a new Category *} <td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<div class="make-switch switch-small categoryVisibleToggle" data-id="{$ID}" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="categoryVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{form name="thelia.admin.category.creation"} {elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="disabled" disabled="disabled" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{admin_position_block
permission="admin.categories.edit"
path={url path='admin/categories/update-position' category_id=$ID}
url_parameter="category_id"
in_place_edit_class="categoryPositionChange"
position=$POSITION
id=$ID
}
</td>
<td class="actions">
<div class="btn-group">
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/categories' category_id=$ID}"><i class="glyphicon glyphicon-folder-open"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='/admin/categories/update' category_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"}
<a class="btn btn-default btn-xs category-delete" title="{intl l='Delete this category and all its contents'}" href="#category_delete_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
{elseloop rel="category_list"}
<thead>
<tr>
<td class="message">
<div class="alert alert-info">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"}
{intl l="This category has no sub-categories. To create a new one, click the + button above."}
{/loop}
{elseloop rel="can_create"}
{intl l="This category has no sub-categories."}
{/elseloop}
</div>
</td>
</tr>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
{module_include location='categories_bottom'}
</div>
</div>
{* Adding a new category *}
{form name="thelia.admin.category.creation"}
{* Capture the dialog body, to pass it to the generic dialog *} {* Capture the dialog body, to pass it to the generic dialog *}
{capture "category_creation_dialog"} {capture "category_creation_dialog"}
{form_hidden_fields form=$form} {form_hidden_fields form=$form}
{form_field form=$form field='success_url'} {form_field form=$form field='success_url'}
{* on success, redirect to the edition page, _ID_ is replaced with the created object ID, see controller *} {* on success, redirect to the edition page, _ID_ is replaced with the created object ID, see controller *}
<input type="hidden" name="{$name}" value="{url path='/admin/categories/update' category_id='_ID_'}" /> <input type="hidden" name="{$name}" value="{url path='/admin/categories/update' category_id='_ID_'}" />
{/form_field} {/form_field}
{form_field form=$form field='parent'} {form_field form=$form field='parent'}
<input type="hidden" name="{$name}" value="{$current_category_id}" /> <input type="hidden" name="{$name}" value="{$category_id}" />
{/form_field} {/form_field}
{form_field form=$form field='title'} {form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label> <label for="{$label_attr.for}" class="control-label">{$label} : </label>
{loop type="lang" name="default-lang" default_only="1"}
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Name'}">
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="$TITLE" /></span>
</div>
{loop type="lang" name="default-lang" default_only="1"} <div class="help-block">{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}</div>
<div class="input-group"> {* Switch edition to the current locale *}
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Name'}"> <input type="hidden" name="edit_language_id" value="{$ID}" />
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="$TITLE" /></span>
</div>
<div class="help-block">{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}</div> {form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field}
{/loop}
</div>
{/form_field}
{* Switch edition to the current locale *} {form_field form=$form field='visible'}
<input type="hidden" name="edit_language_id" value="{$ID}" /> <div class="form-group {if $error}has-error{/if}">
<div class="checkbox">
{form_field form=$form field='locale'} <label>
<input type="hidden" name="{$name}" value="{$LOCALE}" /> <input type="checkbox" id="{$label_attr.for}" name="{$name}" value="1" checked="checked">
{/form_field} {$label}
{/loop} </label>
</div> </div>
{/form_field} </div>
{/form_field}
{module_include location='category_create_form'} {module_include location='category_create_form'}
{/capture} {/capture}
{include {include
file = "includes/generic-create-dialog.html" file = "includes/generic-create-dialog.html"
dialog_id = "add_category_dialog" dialog_id = "category_creation_dialog"
dialog_title = {intl l="Create a new category"} dialog_title = {intl l="Create a new category"}
dialog_body = {$smarty.capture.category_creation_dialog nofilter} dialog_body = {$smarty.capture.category_creation_dialog nofilter}
dialog_ok_label = {intl l="Create this category"} dialog_ok_label = {intl l="Create this category"}
dialog_cancel_label = {intl l="Cancel"}
form_action = {url path='/admin/categories/create'} form_action = {url path='/admin/categories/create'}
form_enctype = {form_enctype form=$form} form_enctype = {form_enctype form=$form}
form_error_message = $form_error_message form_error_message = $form_error_message
} }
{/form} {/form}
{* Delete category confirmation dialog *}
{* Delete confirmation dialog *}
{capture "category_delete_dialog"} {capture "category_delete_dialog"}
<input type="hidden" name="current_category_id" value="{$current_category_id}" /> <input type="hidden" name="category_id" id="category_delete_id" value="" />
<input type="hidden" name="category_id" id="delete_category_id" value"" />
{module_include location='category_delete_form'} {module_include location='category_delete_form'}
@@ -399,9 +263,9 @@
{include {include
file = "includes/generic-confirm-dialog.html" file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_category_dialog" dialog_id = "category_delete_dialog"
dialog_title = {intl l="Delete a category"} dialog_title = {intl l="Delete category"}
dialog_message = {intl l="Do you really want to delete this category, and <strong>all</strong> its contents ?"} dialog_message = {intl l="Do you really want to delete this category and all its content ?"}
form_action = {url path='/admin/categories/delete'} form_action = {url path='/admin/categories/delete'}
form_content = {$smarty.capture.category_delete_dialog nofilter} form_content = {$smarty.capture.category_delete_dialog nofilter}
@@ -410,108 +274,76 @@
{block name="javascript-initialization"} {block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'}
<script src="{$asset_url}"></script> <script src="{$asset_url}"></script>
{/javascripts} {/javascripts}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} {javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
<script src="{$asset_url}"></script> <script src="{$asset_url}"></script>
{/javascripts} {/javascripts}
<script> <script>
$(function() { $(function() {
// JS stuff for category creation form // Set proper category ID in delete from
{include $('a.category-delete').click(function(ev) {
file = "includes/generic-js-dialog.html" $('#category_delete_id').val($(this).data('id'));
});
dialog_id = "add_category_dialog" // JS stuff for creation form
form_name = "thelia.admin.category.creation" {include
} file = "includes/generic-js-dialog.html"
dialog_id = "category_creation_dialog"
form_name = "thelia.admin.category.creation"
}
// JS stuff for product creation form {* Toggle object visibility *}
{include
file = "includes/generic-js-dialog.html"
dialog_id = "add_product_dialog"
form_name = "thelia.admin.product.creation"
}
{* Set the proper ID in the delete confirmation dialog *} $(".categoryVisibleToggle").on('switch-change', function(event, data) {
console.log("yaya");
$.ajax({
url : "{url path='admin/categories/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});
});
$('a.category-delete').click(function(ev) { {* Inline editing of object position using bootstrap-editable *}
$('#delete_category_id').val($(this).data('id'));
});
$('a.product-delete').click(function(ev) { $('.categoryPositionChange').editable({
$('#delete_product_id').val($(this).data('id')); type : 'text',
}); title : '{intl l="Enter new category position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
{* Toggle object visibility *} // Reload the page
location.href = url;
}
});
{* Change default status *}
$('.change-default').change(function(ev) {
var url = "{url path='/admin/categories/set-default' category_id='__ID__'}";
// Perform ID subtitutions
url = url.replace('__ID__', $(this).val());
// Reload the page
location.href = url;
});
$(".categoryVisibleToggle").click(function() {
$.ajax({
url : "{url path='admin/categories/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
}); });
}); </script>
$(".productVisibleToggle").click(function() {
$.ajax({
url : "{url path='admin/products/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});
});
{* Inline editing of object position using bootstrap-editable *}
$('.categoryPositionChange').editable({
type : 'text',
title : '{intl l="Enter new category position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
$('.productPositionChange').editable({
type : 'text',
title : '{intl l="Enter new product position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/products/update-position' product_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
})
</script>
{/block} {/block}

View File

@@ -8,206 +8,154 @@
<div class="catalog edit-category"> <div class="catalog edit-category">
<div id="wrapper" class="container"> <div id="wrapper" class="container">
{include file="includes/catalog-breadcrumb.html"} {include file="includes/catalog-breadcrumb.html" editing_category="true"}
<div class="row"> <div class="row">
{loop name="category_edit" type="category" visible="*" id="{$current_category_id}" backend_context="1" lang="$edit_language_id"} {loop name="category_edit" type="category" visible="*" id="{$category_id}" backend_context="1" lang="$edit_language_id"}
<div class="col-md-12 general-block-decorator"> <div class="col-md-12 general-block-decorator">
<div class="row"> <div class="row">
<div class="col-md-7 title"> <div class="col-md-7 title">
{intl l='Edit category'} {intl l='Edit category %title' title=$TITLE}
</div> </div>
<div class="col-md-5 actions"> <div class="col-md-5 actions">
<button class="btn btn-default" title="{intl l='Edit previous category'}"><i class="glyphicon glyphicon-arrow-left"></i></button>
<button class="btn btn-default" title="{intl l='Preview category page'}"><i class="glyphicon glyphicon-eye-open"></i></button> {if $HAS_PREVIOUS != 0}
<button class="btn btn-default" title="{intl l='Edit next category'}"><i class="glyphicon glyphicon-arrow-right"></i></button> <a href="{url path='/admin/categories/update' category_id=$PREVIOUS}" class="btn btn-default" title="{intl l='Edit previous category'}"><span class="glyphicon glyphicon-arrow-left"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span></a>
{/if}
<a href="{$URL}" target="_blank" class="btn btn-default" title="{intl l='Preview category page'}"><span class="glyphicon glyphicon-eye-open"></span></a>
{if $HAS_NEXT != 0}
<a href="{url path='/admin/categories/update' category_id=$NEXT}" class="btn btn-default" title="{intl l='Edit next category'}"><span class="glyphicon glyphicon-arrow-right"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-right"></span></a>
{/if}
</div> </div>
</div> </div>
<form method="post"> <div class="row">
<div class="col-md-12">
<div class="tabbable"> <ul class="nav nav-tabs">
<ul class="nav nav-tabs admin-tabs" id="tabbed_menu"> <li class="active"><a href="#general_description" data-toggle="tab">{intl l="General description"}</a></li>
<li class="active">
<a href="#general_description">{intl l="General description"}</a>
</li>
<li> <li><a href="#details" data-toggle="tab">{intl l="Details"}</a></li>
<a href="#details">{intl l="Details"}</a> <li><a href="#images" data-toggle="tab">{intl l="Images"}</a></li>
</li> <li><a href="#documents" data-toggle="tab">{intl l="Documents"}</a></li>
<li> <li><a href="#modules" data-toggle="tab">{intl l="Modules"}</a></li>
<a href="#images">{intl l="Images"}</a> </ul>
</li>
<li>
<a href="#documents">{intl l="Documents"}</a>
</li>
<li>
<a href="#modules">{intl l="Modules"}</a>
</li>
</ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active form-container" id="general_description"> <div class="tab-pane fade active in" id="general_description">
<div class="form-horizontal col-md-12">
<fieldset>
{include file="includes/inner-form-toolbar.html" close_url="{url path='admin/catalog/category/edit' category_id=$current_category_id}"} <div class="form-container">
<div class="row"> {form name="thelia.admin.category.modification"}
<div class="col-md-12"> <form method="POST" action="{url path='/admin/categories/save'}" {form_enctype form=$form} class="clearfix">
<div class="control-group">
<label class="control-label">
{intl l='Title *'}
</label>
<div class="controls"> {include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/categories' category_id=$category_id}"}
<input type="text" required="required" title="{intl l='Category title'}" placeholder="{intl l='Category title'}" class="input-block-level" value="{$TITLE|htmlspecialchars}">
</div>
</div>
<div class="control-group"> {* Be sure to get the category ID, even if the form could not be validated *}
<label class="control-label"> <input type="hidden" name="category_id" value="{$category_id}" />
{intl l='Summary'}
<span class="label-help-block">{intl l="A short category description, used when a summary or an introduction is required"}</span>
</label>
<div class="controls"> {form_hidden_fields form=$form}
<textarea name="summary" rows="3" title="{intl l='Short category description'}" placeholder="{intl l='Short category description'}" class="input-block-level">{$CHAPO|htmlspecialchars}</textarea>
</div>
</div>
<div class="control-group"> {form_field form=$form field='success_url'}
<label class="control-label"> <input type="hidden" name="{$name}" value="{url path='/admin/category' category_id={$category_d}}" />
{intl l='Detailed description'} {/form_field}
<span class="label-help-block">{intl l="The détailed category description."}</span>
</label>
<div class="controls"> {form_field form=$form field='locale'}
<textarea name="summary" rows="10" class="input-block-level">{$DESCRIPTION|htmlspecialchars}</textarea> <input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field}
</div> {if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
</div>
<div class="control-group"> {include file="includes/standard-description-form-fields.html"}
<label class="control-label">
{intl l='Conclusion'}
<span class="label-help-block">{intl l="A short post-description information"}</span>
</label>
<div class="controls"> {form_field form=$form field='url'}
<textarea name="summary" rows="3" title="{intl l='Short category description'}" placeholder="{intl l='Short category description'}" class="input-block-level">{$POSTSCRIPTUM|htmlspecialchars}</textarea> <div class="form-group {if $error}has-error{/if}">
</div> <label for="{$label_attr.for}" class="control-label">
</div> {intl l="{$label}"} :
</label>
<div class="control-group"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Rewritten URL'}" placeholder="{intl l='Rewriten URL'}" class="form-control">
<label class="control-label"> </div>
{intl l='Rewriten URL'} {/form_field}
</label>
<div class="controls"> <div class="row">
<div class="input-group input-block-level"> <div class="col-md-6">
<input type="text" required="required" title="{intl l='Rewriten URL'}" placeholder="{intl l='Rewriten URL'}" class="input-block-level" value="{$URL|htmlspecialchars}"> {form_field form=$form field='parent'}
<a class="btn btn-default input-group-addon use_default_rewriten_url" href="#">{intl l='Use default'}</a> <div class="form-group {if $error}has-error{/if}">
</div>
<div class="help-block">{intl l="The rewritten URL to the category page. Click \"Use Default\" button to use the default URL. Use only digits, letters, - and _ characters."}</div>
</div>
</div>
</div> <label for="{$label_attr.for}" class="control-label">
</div> {intl l="{$label}"} :
</label>
<div class="row"> <select id="{$label_attr.for}" required="required" name="{$name}" class="form-control">
<div class="col-md-12"> <option value="0">{intl l="Top level"}</option>
<div class="control-group">
<lablel>&nbsp;</lablel>
<div class="controls">
<p>{intl l='Category created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}}</p>
</div>
</div>
</div>
</div>
</fieldset> {$myparent=$PARENT}
</div> {loop name="cat-parent" type="category-tree" visible="*" category="0"}
</div> <option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $myparent == $ID}selected="selected"{/if} {if $category_id == $ID}disabled="disabled"{/if}>{$TITLE}</option>
{/loop}
<div class="tab-pane form-container" id="details"> </select>
<div class="form-horizontal col-md-12"> </div>
<fieldset> {/form_field}
{include file="includes/inner-form-toolbar.html" close_url="{url path='admin/catalog/category/edit' category_id=$current_category_id}"} </div>
<div class="col-md-6">
{form_field form=$form field='visible'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l='Visibility'}</label>
<div class="checkbox">
<label>
<input type="checkbox" id="{$label_attr.for}" name="{$name}" value="1" {if $value != 0}checked="checked"{/if}>
{$label}
</label>
</div>
</div>
{/form_field}
</div>
</div>
<div class="row"> <div class="row">
<div class="col-md-6">
<div class="control-group">
<label class="control-label">
{intl l='Category ID'}
</label>
<div class="controls">
<input type="text" name="id" disabled="disabled" value="{$ID}" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="control-group">
<label class="control-label">
{intl l='Parent category *'}
</label>
<div class="controls">
<select required="required" name="parent">
<option value="0">{intl l="Top level"}</option>
{loop name="cat-parent" type="category-tree" visible="*" category="0" exclude="{$current_category_id}"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $parent_category_id == $ID}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12"> <div class="col-md-12">
<div class="control-group"> <div class="control-group">
<label class="control-label"> <lablel>&nbsp;</lablel>
{intl l='Visibility'} <div class="controls">
</label> <p>{intl l='Category created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}</p>
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="visible" {if $VISIBLE}checked="checked"{/if}> {intl l="Display this category on front-office"}
</label>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</fieldset> </form>
</div> {/form}
</div> </div>
</div>
<div class="tab-pane" id="images"> <div class="tab-pane fade" id="details">
<p>Images</p> klljkmk
</div> </div>
<div class="tab-pane" id="documents"> <div class="tab-pane fade" id="images">
<p>Documents</p> </div>
</div>
<div class="tab-pane" id="modules"> <div class="tab-pane fade" id="documents">
<p>Modules</p> </div>
</div>
</div> <div class="tab-pane fade" id="modules">
</div> </div>
</form> </div>
{/loop} </div>
</div>
</div> </div>
{/loop}
</div> </div>
</div> </div>
</div> </div>
@@ -217,10 +165,6 @@
<script> <script>
$(function() { $(function() {
$('#tabbed_menu a').click(function (e) {
e.preventDefault();
$(this).tab('show');
});
$('.use_default_rewriten_url').click(function(ev) { $('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal"); alert("Not functionnal");

View File

@@ -54,7 +54,7 @@
{form_field form=$form field='name'} {form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency name'}" placeholder="{intl l='Currency name'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Currency name'}" class="form-control">
<span class="help-block">&nbsp;</span> <span class="help-block">&nbsp;</span>
</div> </div>
{/form_field} {/form_field}
@@ -64,7 +64,7 @@
<label for="{$label_attr.for}" class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} : {intl l="{$label}"} :
</label> </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency ISO 4217 Code'}" placeholder="{intl l='Code'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency ISO 4217 Code'}" placeholder="{intl l='Code'}" class="form-control">
<span class="help-block"> <span class="help-block">
<a title="{intl l='More information about ISO 4217'}" href="http://fr.wikipedia.org/wiki/ISO_4217" target="_blank">List of ISO 4217 code</a> <a title="{intl l='More information about ISO 4217'}" href="http://fr.wikipedia.org/wiki/ISO_4217" target="_blank">List of ISO 4217 code</a>
</span> </span>
@@ -80,7 +80,7 @@
<label for="{$label_attr.for}" class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} : {intl l="{$label}"} :
</label> </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}" class="form-control">
<span class="help-block">{intl l='The symbol, such as $, £, &euro;...'}</span> <span class="help-block">{intl l='The symbol, such as $, £, &euro;...'}</span>
</div> </div>
{/form_field} {/form_field}
@@ -90,7 +90,7 @@
<label for="{$label_attr.for}" class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} : {intl l="{$label}"} :
</label> </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Rate from Euro'}" placeholder="{intl l='Rate'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Rate from Euro'}" placeholder="{intl l='Rate'}" class="form-control">
<span class="help-block">The rate from Euro: Price in Euro x rate = Price in this currency</span> <span class="help-block">The rate from Euro: Price in Euro x rate = Price in this currency</span>
</div> </div>
{/form_field} {/form_field}

View File

@@ -5,17 +5,17 @@
<li><a href="{url path='admin/catalog'}">Catalog</a> <li><a href="{url path='admin/catalog'}">Catalog</a>
{ifloop rel="category_path"}</li> {ifloop rel="category_path"}</li>
{loop name="category_path" type="category-path" visible="*" category=$current_category_id} {loop name="category_path" type="category-path" visible="*" category=$category_id}
{if $ID == $current_category_id} {if $ID == $category_id}
<li class="active"> <li class="active">
{if $action == 'edit'} {if $editing_category == true}
{intl l='Editing %cat' cat="{$TITLE}"} {intl l='Editing %cat' cat="{$TITLE}"}
{else} {else}
{$TITLE} <a href="{url path='admin/catalog/category/edit' category_id=$ID}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a> {$TITLE} <a href="{url path='/admin/categories/update' category_id=$ID}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a>
{/if} {/if}
</li> </li>
{else} {else}
<li><a href="{url path='admin/catalog/category' id=" $ID" action='browse'}">{$TITLE}</a></li> <li><a href="{url path='/admin/categories' category_id=" $ID" action='browse'}">{$TITLE}</a></li>
{/if} {/if}
{/loop} {/loop}
{/ifloop} {/ifloop}

View File

@@ -43,7 +43,7 @@
{/form_field} {/form_field}
{form_field form=$form field='id'} {form_field form=$form field='id'}
<input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" /> <input type="hidden" name="{$name}" value="{$value}" />
{/form_field} {/form_field}
{form_field form=$form field='locale'} {form_field form=$form field='locale'}
@@ -55,7 +55,7 @@
{form_field form=$form field='name'} {form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
</div> </div>
{/form_field} {/form_field}
@@ -71,14 +71,14 @@
{form_field form=$form field='title'} {form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{$value|htmlspecialchars}"> <input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{$value}">
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='subject'} {form_field form=$form field='subject'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Subject'}" placeholder="{intl l='Subject'}" class="form-control" value="{$value|htmlspecialchars}"> <input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Subject'}" placeholder="{intl l='Subject'}" class="form-control" value="{$value}">
</div> </div>
{/form_field} {/form_field}
@@ -88,7 +88,7 @@
{intl l="{$label}"} : {intl l="{$label}"} :
<span class="label-help-block">{intl l="The mailing template in HTML format."}</span> <span class="label-help-block">{intl l="The mailing template in HTML format."}</span>
</label> </label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea> <textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value}</textarea>
</div> </div>
{/form_field} {/form_field}
@@ -98,7 +98,7 @@
{intl l="{$label}"} : {intl l="{$label}"} :
<span class="label-help-block">{intl l="The mailing template in text-only format."}</span> <span class="label-help-block">{intl l="The mailing template in text-only format."}</span>
</label> </label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea> <textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value}</textarea>
</div> </div>
{/form_field} {/form_field}

View File

@@ -59,7 +59,7 @@
<div class="btn-group"> <div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a> <a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
@@ -83,7 +83,7 @@
<div class="btn-group"> <div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a> <a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
@@ -107,7 +107,7 @@
<div class="btn-group"> <div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a> <a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}

View File

@@ -45,7 +45,7 @@
{* We do not allow creation of hidden variables *} {* We do not allow creation of hidden variables *}
{form_field form=$form field='id'} {form_field form=$form field='id'}
<input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" /> <input type="hidden" name="{$name}" value="{$value}" />
{/form_field} {/form_field}
{form_field form=$form field='hidden'} {form_field form=$form field='hidden'}
@@ -61,14 +61,14 @@
{form_field form=$form field='name'} {form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='value'} {form_field form=$form field='value'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="form-control"> <input type="text" id="{$label_attr.for}" name="{$name}" value="{$value}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="form-control">
</div> </div>
{/form_field} {/form_field}

View File

@@ -95,7 +95,7 @@
{if $SECURED} {if $SECURED}
{$VALUE} {$VALUE}
{else} {else}
<input id="cancelable_edit_{$ID}" class="js-edit form-control" data-id="{$ID}" type="text" name="variable[{$ID}]" value="{$VALUE|htmlspecialchars}" /> <input id="cancelable_edit_{$ID}" class="js-edit form-control" data-id="{$ID}" type="text" name="variable[{$ID}]" value="{$VALUE}" />
{/if} {/if}
</td> </td>