Categories ordrering in the catalog

This commit is contained in:
franck
2013-08-09 10:18:08 +02:00
parent 376471db04
commit c46a708346
23 changed files with 7875 additions and 94 deletions

View File

@@ -28,14 +28,38 @@ use Thelia\Form\BaseForm;
use Thelia\Core\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Request;
use Thelia\Action\Exception\FormValidationException; use Thelia\Action\Exception\FormValidationException;
use Thelia\Core\Event\ActionEvent; use Thelia\Core\Event\ActionEvent;
use Symfony\Component\Form\Form;
use Symfony\Component\DependencyInjection\ContainerAware;
use Thelia\Core\Template\ParserContext;
use Thelia\Log\Tlog;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Core\Security\SecurityContext;
use Thelia\Core\Security\Exception\AuthorizationException;
abstract class BaseAction class BaseAction
{ {
/**
* @var The container
*/
protected $container;
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
/**
* Validate a BaseForm
*
* @param BaseForm $aBaseForm the form
* @param string $expectedMethod the expected method, POST or GET, or null for any of them
* @throws FormValidationException is the form contains error, or the method is not the right one
* @return Symfony\Component\Form\Form Form the symfony form object
*/
protected function validateForm(BaseForm $aBaseForm, $expectedMethod = null) protected function validateForm(BaseForm $aBaseForm, $expectedMethod = null)
{ {
$form = $aBaseForm->getForm(); $form = $aBaseForm->getForm();
if ($aBaseForm->getRequest()->isMethod($expectedMethod)) { if ($expectedMethod == null || $aBaseForm->getRequest()->isMethod($expectedMethod)) {
$form->bind($aBaseForm->getRequest()); $form->bind($aBaseForm->getRequest());
@@ -53,10 +77,11 @@ abstract class BaseAction
} }
/** /**
* Propagate a form error in the action event
* *
* @param BaseForm $aBaseForm * @param BaseForm $aBaseForm the form
* @param string $error_message * @param string $error_message an error message that may be displayed to the customer
* @param ActionEvent $event * @param ActionEvent $event the action event
*/ */
protected function propagateFormError(BaseForm $aBaseForm, $error_message, ActionEvent $event) { protected function propagateFormError(BaseForm $aBaseForm, $error_message, ActionEvent $event) {
@@ -71,6 +96,62 @@ abstract class BaseAction
$event->stopPropagation(); $event->stopPropagation();
} }
/**
* Check current user authorisations.
*
* @param mixed $roles a single role or an array of roles.
* @param mixed $permissions a single permission or an array of permissions.
*
* @throws AuthenticationException if permissions are not granted to the current user.
*/
protected function checkAuth($roles, $permissions, $context = false) {
if (! $this->getSecurityContext($context)->isGranted(
is_array($roles) ? $roles : array($roles),
is_array($permissions) ? $permissions : array($permissions)) ) {
Tlog::getInstance()->addAlert("Authorization roles:", $roles, " permissions:", $permissions, " refused.");
throw new AuthorizationException("Sorry, you're not allowed to perform this action");
}
}
/**
* Return the event dispatcher,
*
* @return ParserContext
*/
protected function getDispatcher()
{
return $this->container->get('event_dispatcher');
}
/**
* Return the parser context,
*
* @return ParserContext
*/
protected function getParserContext()
{
return $this->container->get('thelia.parser.context');
}
/**
* Return the security context, by default in admin mode.
*
* @param string the context, either SecurityContext::CONTEXT_BACK_OFFICE or SecurityContext::CONTEXT_FRONT_OFFICE
*
* @return Thelia\Core\Security\SecurityContext
*/
protected function getSecurityContext($context = false)
{
$securityContext = $this->container->get('thelia.securityContext');
$securityContext->setContext($context === false ? SecurityContext::CONTEXT_BACK_OFFICE : $context);
return $securityContext;
}
protected function redirect($url, $status = 302) protected function redirect($url, $status = 302)
{ {
$response = new RedirectResponse($url, $status); $response = new RedirectResponse($url, $status);
@@ -78,5 +159,4 @@ abstract class BaseAction
$response->send(); $response->send();
exit; exit;
} }
} }

View File

@@ -53,18 +53,6 @@ use Thelia\Model\Customer;
class Cart extends BaseAction implements EventSubscriberInterface class Cart extends BaseAction implements EventSubscriberInterface
{ {
use \Thelia\Cart\CartTrait; use \Thelia\Cart\CartTrait;
/**
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $dispatcher;
/**
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
*/
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/** /**
* *
@@ -122,7 +110,7 @@ class Cart extends BaseAction implements EventSubscriberInterface
protected function updateQuantity(CartItem $cartItem, $quantity) protected function updateQuantity(CartItem $cartItem, $quantity)
{ {
$cartItem->setDisptacher($this->dispatcher); $cartItem->setDisptacher($this->getDispatcher());
$cartItem->addQuantity($quantity) $cartItem->addQuantity($quantity)
->save(); ->save();
} }
@@ -130,7 +118,7 @@ class Cart extends BaseAction implements EventSubscriberInterface
protected function addItem(\Thelia\Model\Cart $cart, $productId, $productSaleElementsId, $quantity, ProductPrice $productPrice) protected function addItem(\Thelia\Model\Cart $cart, $productId, $productSaleElementsId, $quantity, ProductPrice $productPrice)
{ {
$cartItem = new CartItem(); $cartItem = new CartItem();
$cartItem->setDisptacher($this->dispatcher); $cartItem->setDisptacher($this->getDispatcher());
$cartItem $cartItem
->setCart($cart) ->setCart($cart)
->setProductId($productId) ->setProductId($productId)

View File

@@ -34,11 +34,16 @@ use Thelia\Model\CategoryQuery;
use Thelia\Model\AdminLog; use Thelia\Model\AdminLog;
use Thelia\Form\CategoryDeletionForm; use Thelia\Form\CategoryDeletionForm;
use Thelia\Action\Exception\FormValidationException; use Thelia\Action\Exception\FormValidationException;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Propel;
use Thelia\Model\Map\CategoryTableMap;
class Category extends BaseAction implements EventSubscriberInterface class Category extends BaseAction implements EventSubscriberInterface
{ {
public function create(ActionEvent $event) public function create(ActionEvent $event)
{ {
$this->checkAuth("ADMIN", "admin.category.create");
$request = $event->getRequest(); $request = $event->getRequest();
try { try {
@@ -82,6 +87,8 @@ class Category extends BaseAction implements EventSubscriberInterface
public function modify(ActionEvent $event) public function modify(ActionEvent $event)
{ {
$this->checkAuth("ADMIN", "admin.category.delete");
/* /*
$request = $event->getRequest(); $request = $event->getRequest();
@@ -154,6 +161,8 @@ class Category extends BaseAction implements EventSubscriberInterface
*/ */
public function delete(ActionEvent $event) public function delete(ActionEvent $event)
{ {
$this->checkAuth("ADMIN", "admin.category.delete");
$request = $event->getRequest(); $request = $event->getRequest();
try { try {
@@ -204,9 +213,11 @@ class Category extends BaseAction implements EventSubscriberInterface
*/ */
public function toggleVisibility(ActionEvent $event) public function toggleVisibility(ActionEvent $event)
{ {
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest(); $request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('id', 0)); $category = CategoryQuery::create()->findPk($request->get('category_id', 0));
if ($category !== null) { if ($category !== null) {
@@ -220,6 +231,144 @@ class Category extends BaseAction implements EventSubscriberInterface
} }
} }
/**
* Move category up
*
* @param ActionEvent $event
*/
public function changePositionUp(ActionEvent $event) {
return $this->exchangePosition($event, 'up');
}
/**
* Move category down
*
* @param ActionEvent $event
*/
public function changePositionDown(ActionEvent $event) {
return $this->exchangePosition($event, 'down');
}
/**
* Move up or down a category
*
* @param ActionEvent $event
* @param string $direction up to move up, down to move down
*/
protected function exchangePosition(ActionEvent $event, $direction) {
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
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 ($direction == 'up') {
// Find the category immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
}
else if ($direction == '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->setPosition($result->getPosition())->save();
$result->setPosition($my_position)->save();
$cnx->commit();
}
catch(Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Changes category position
*
* @param ActionEvent $event
*/
public function changePosition(ActionEvent $event) {
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
if ($category !== null) {
// The required position
$new_position = $request->get('position', null);
// 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->setPosition($new_position)->save($cnx);
$cnx->commit();
}
catch(Exception $e) {
$cnx->rollback();
}
}
}
}
/** /**
* Returns an array of event names this subscriber listens to. * Returns an array of event names this subscriber listens to.
* *
@@ -248,6 +397,9 @@ class Category extends BaseAction implements EventSubscriberInterface
"action.deleteCategory" => array("delete", 128), "action.deleteCategory" => array("delete", 128),
"action.toggleCategoryVisibility" => array("toggleVisibility", 128), "action.toggleCategoryVisibility" => array("toggleVisibility", 128),
"action.changeCategoryPositionUp" => array("changePositionUp", 128),
"action.changeCategoryPositionDown" => array("changePositionDown", 128),
"action.changeCategoryPosition" => array("changePosition", 128),
); );
} }
} }

View File

@@ -43,18 +43,8 @@ use Thelia\Core\Security\Exception\UsernameNotFoundException;
use Propel\Runtime\Exception\PropelException; use Propel\Runtime\Exception\PropelException;
use Thelia\Action\Exception\FormValidationException; use Thelia\Action\Exception\FormValidationException;
class Customer extends BaseAction implements EventSubscriberInterface class Customer extends BaseAction implements EventSubscriberInterface
{ {
/**
* @var Thelia\Core\Security\SecurityContext
*/
protected $securityContext;
public function __construct(SecurityContext $securityContext) {
$this->securityContext = $securityContext;
}
public function create(ActionEvent $event) public function create(ActionEvent $event)
{ {
$request = $event->getRequest(); $request = $event->getRequest();
@@ -88,9 +78,15 @@ class Customer extends BaseAction implements EventSubscriberInterface
$customerEvent = new CustomerEvent($customer); $customerEvent = new CustomerEvent($customer);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECUSTOMER, $customerEvent); $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECUSTOMER, $customerEvent);
if (isset($data['auto_login']) && $data['auto_login']) {
// Connect the newly created user,and redirect to the success URL // Connect the newly created user,and redirect to the success URL
$this->processSuccessfulLogin($event, $customer, $customerCreationForm, true); $this->processSuccessfulLogin($event, $customer, $customerCreationForm, true);
} }
else {
$this->redirect($form->getSuccessUrl());
}
}
catch (PropelException $e) { catch (PropelException $e) {
Tlog::getInstance()->error(sprintf('error during creating customer on action/createCustomer with message "%s"', $e->getMessage())); Tlog::getInstance()->error(sprintf('error during creating customer on action/createCustomer with message "%s"', $e->getMessage()));
@@ -139,10 +135,15 @@ class Customer extends BaseAction implements EventSubscriberInterface
$customerEvent->customer = $customer; $customerEvent->customer = $customer;
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent);
if (isset($data['update_logged_in_user']) && $data['update_logged_in_user']) {
// Update the logged-in user, and redirect to the success URL (exits) // Update the logged-in user, and redirect to the success URL (exits)
// We don-t send the login event, as the customer si already logged. // We don't send the login event, as the customer si already logged.
$this->processSuccessfulLogin($event, $customer, $customerModification); $this->processSuccessfulLogin($event, $customer, $customerModification);
} }
else {
$this->redirect($form->getSuccessUrl());
}
}
catch(PropelException $e) { catch(PropelException $e) {
Tlog::getInstance()->error(sprintf('error during modifying customer on action/modifyCustomer with message "%s"', $e->getMessage())); Tlog::getInstance()->error(sprintf('error during modifying customer on action/modifyCustomer with message "%s"', $e->getMessage()));
@@ -168,7 +169,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
{ {
$event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGOUT, $event); $event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGOUT, $event);
$this->getSecurityContext()->clear(); $this->getFrontSecurityContext()->clear();
} }
/** /**
@@ -259,7 +260,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
protected function processSuccessfulLogin(ActionEvent $event, CustomerModel $user, BaseForm $form, $sendLoginEvent = false) protected function processSuccessfulLogin(ActionEvent $event, CustomerModel $user, BaseForm $form, $sendLoginEvent = false)
{ {
// Success -> store user in security context // Success -> store user in security context
$this->getSecurityContext()->setUser($user); $this->getFrontSecurityContext()->setUser($user);
if ($sendLoginEvent) $event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGIN, $event); if ($sendLoginEvent) $event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGIN, $event);
@@ -272,9 +273,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
* *
* @return SecurityContext the security context * @return SecurityContext the security context
*/ */
protected function getSecurityContext() { protected function getFrontSecurityContext() {
$this->securityContext->setContext(SecurityContext::CONTEXT_FRONT_OFFICE); return $this->getSecurityContext(SecurityContext::CONTEXT_FRONT_OFFICE);
return $this->securityContext;
} }
} }

View File

@@ -70,9 +70,29 @@ class BaseAdminController extends ContainerAware
// Nothing special // Nothing special
} }
return $this->pageNotFound();
}
/**
* Return a 404 error
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function pageNotFound() {
return new Response($this->renderRaw(self::TEMPLATE_404), 404); return new Response($this->renderRaw(self::TEMPLATE_404), 404);
} }
/**
* Return a general error page
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function errorPage($message) {
return $this->render('general_error', array(
"error_message" => $message)
);
}
/** /**
* Check current admin user authorisations. An ADMIN role is assumed. * Check current admin user authorisations. An ADMIN role is assumed.
* *

View File

@@ -25,13 +25,11 @@ namespace Thelia\Admin\Controller;
use Thelia\Model\CategoryQuery; use Thelia\Model\CategoryQuery;
use Thelia\Core\Security\Exception\AuthenticationException; use Thelia\Core\Security\Exception\AuthenticationException;
use Thelia\Core\Security\Exception\AuthorizationException;
class CategoryController extends BaseAdminController { class CategoryController extends BaseAdminController {
protected function createNewCategory($args) { protected function createNewCategory($args) {
$this->checkAuth("ADMIN", "admin.category.create");
$this->dispatchEvent("createCategory"); $this->dispatchEvent("createCategory");
// At this point, the form has error, and should be redisplayed. // At this point, the form has error, and should be redisplayed.
@@ -40,24 +38,16 @@ class CategoryController extends BaseAdminController {
protected function editCategory($args) { protected function editCategory($args) {
$this->checkAuth("AMIN", "admin.category.edit"); $this->checkAuth("ADMIN", "admin.category.edit");
return $this->render('edit_category', $args); return $this->render('edit_category', $args);
} }
protected function deleteCategory($category_id) { protected function deleteCategory($args) {
$this->checkAuth("AMIN", "admin.category.delete");
$category = CategoryQuery::create()->findPk($category_id);
$this->dispatchEvent("deleteCategory"); $this->dispatchEvent("deleteCategory");
// Something was wrong, category was not deleted. Display parent category list // Something was wrong, category was not deleted. Display parent category list
return $this->render( return $this->render('categories', $args);
'categories',
array('current_category_id' => $category->getParent())
);
} }
protected function browseCategory($args) { protected function browseCategory($args) {
@@ -68,32 +58,32 @@ class CategoryController extends BaseAdminController {
} }
protected function visibilityToggle($args) { protected function visibilityToggle($args) {
$this->checkAuth("AMIN", "admin.category.edit");
$this->dispatchEvent("toggleCategoryVisibility"); $this->dispatchEvent("toggleCategoryVisibility");
return $this->nullResponse(); return $this->nullResponse();
} }
protected function changePosition($args) { protected function changePosition($args) {
$this->checkAuth("AMIN", "admin.category.edit");
$this->dispatchEvent("changeCategoryPosition"); $this->dispatchEvent("changeCategoryPosition");
return $this->render('categories', $args); return $this->render('categories', $args);
} }
protected function positionDown($args) {
$this->dispatchEvent("changeCategoryPositionDown");
return $this->render('categories', $args);
}
protected function positionUp($args) {
$this->dispatchEvent("changeCategoryPositionUp");
return $this->render('categories', $args);
}
public function indexAction() public function indexAction()
{ {
// Show top level categories and products return $this->processAction();
$args = array(
'action' => 'browse',
'current_category_id' => 0
);
return $this->browseCategory($args);
} }
public function processAction() public function processAction()
@@ -121,19 +111,29 @@ class CategoryController extends BaseAdminController {
return $this->editCategory($args); return $this->editCategory($args);
case 'delete' : // Delete an existing category case 'delete' : // Delete an existing category
return $this->deleteCategory($id); return $this->deleteCategory($args);
case 'visibilityToggle' : // Toggle visibility case 'visibilityToggle' : // Toggle visibility
return $this->visibilityToggle($id); return $this->visibilityToggle($id);
case 'changePosition' : // Change position case 'changePosition' : // Change position
return $this->changePosition($args); return $this->changePosition($args);
case 'positionUp' : // Move up category
return $this->positionUp($args);
case 'positionDown' : // Move down category
return $this->positionDown($args);
} }
} }
catch(AuthorizationException $ex) {
return $this->errorPage($ex->getMessage());
}
catch(AuthenticationException $ex) { catch(AuthenticationException $ex) {
return $this->render('general_error', array( return $this->errorPage($ex->getMessage());
"error_message" => $ex->getMessage())
);
} }
// We did not recognized the action -> return a 404 page
return $this->pageNotFound();
} }
} }

View File

@@ -13,18 +13,17 @@
<services> <services>
<service id="thelia.action.cart" class="Thelia\Action\Cart"> <service id="thelia.action.cart" class="Thelia\Action\Cart">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/> <tag name="kernel.event_subscriber"/>
<argument type="service" id="event_dispatcher"/>
</service> </service>
<service id="thelia.action.customer" class="Thelia\Action\Customer" scope="request"> <service id="thelia.action.customer" class="Thelia\Action\Customer">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/> <tag name="kernel.event_subscriber"/>
<argument type="service" id="thelia.securityContext"/>
</service> </service>
<service id="thelia.action.category" class="Thelia\Action\Category"> <service id="thelia.action.category" class="Thelia\Action\Category">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/> <tag name="kernel.event_subscriber"/>
</service> </service>

View File

@@ -133,7 +133,7 @@ class SecurityContext {
} }
// Get permissions from profile // Get permissions from profile
// $userPermissions = $user->getPermissions(); // $userPermissions = $user->getPermissions(); FIXME
// TODO: Finalize permissions system !; // TODO: Finalize permissions system !;

View File

@@ -49,7 +49,13 @@ class UrlGenerator extends AbstractSmartyPlugin
// the path to process // the path to process
$path = $this->getParam($params, 'path'); $path = $this->getParam($params, 'path');
return URL::absoluteUrl($path, $this->getArgsFromParam($params, array('path'))); $target = $this->getParam($params, 'target', null);
$url = URL::absoluteUrl($path, $this->getArgsFromParam($params, array('path', 'target')));
if ($target != null) $url .= '#'.$target;
return $url;
} }
/** /**
@@ -84,7 +90,7 @@ class UrlGenerator extends AbstractSmartyPlugin
// the related action (optionale) // the related action (optionale)
$action = $this->getParam($params, 'action'); $action = $this->getParam($params, 'action');
$args = $this->getArgsFromParam($params, array('view', 'action')); $args = $this->getArgsFromParam($params, array('view', 'action', 'target'));
if (! empty($action)) $args['action'] = $action; if (! empty($action)) $args['action'] = $action;

View File

@@ -30,7 +30,7 @@ class CategoryDeletionForm extends BaseForm {
protected function buildForm() protected function buildForm()
{ {
$this->formBuilder $this->formBuilder
->add("id", "integer", array( ->add("category_id", "integer", array(
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
) )

View File

@@ -33,6 +33,7 @@ class CustomerCreation extends BaseForm
protected function buildForm() protected function buildForm()
{ {
$this->formBuilder $this->formBuilder
->add("auto_login", "boolean")
->add("firstname", "text", array( ->add("firstname", "text", array(
"constraints" => array( "constraints" => array(
new Constraints\NotBlank() new Constraints\NotBlank()

View File

@@ -53,6 +53,7 @@ class CustomerModification extends BaseForm {
{ {
$this->formBuilder $this->formBuilder
->add('update_logged_in_user', 'boolean') // In a front office context, update the in-memory logged-in user data
->add("firstname", "text", array( ->add("firstname", "text", array(
"constraints" => array( "constraints" => array(
new Constraints\NotBlank() new Constraints\NotBlank()

View File

@@ -27,7 +27,7 @@ INSERT INTO `currency` (`id` ,`code` ,`symbol` ,`rate` ,`by_default`, `position`
VALUES VALUES
(1, 'EUR', '', '1', '1', '1', NOW() , NOW()), (1, 'EUR', '', '1', '1', '1', NOW() , NOW()),
(2, 'USD', '$', '1.26', '0', '2', NOW(), NOW()), (2, 'USD', '$', '1.26', '0', '2', NOW(), NOW()),
(3, 'GBP', '£', '0.89', '0', '3', NOW(), NOW()); (3, 'GBP', '£', '0.89', '0', '3',NOW(), NOW());
INSERT INTO `currency_i18n` (`id` ,`locale` ,`name`) INSERT INTO `currency_i18n` (`id` ,`locale` ,`name`)
VALUES VALUES

View File

@@ -0,0 +1,656 @@
/*! X-editable - v1.4.6
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
.editableform {
margin-bottom: 0; /* overwrites bootstrap margin */
}
.editableform .control-group {
margin-bottom: 0; /* overwrites bootstrap margin */
white-space: nowrap; /* prevent wrapping buttons on new line */
line-height: 20px; /* overwriting bootstrap line-height. See #133 */
}
.editable-buttons {
display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
vertical-align: top;
margin-left: 7px;
/* inline-block emulation for IE7*/
zoom: 1;
*display: inline;
}
.editable-buttons.editable-buttons-bottom {
display: block;
margin-top: 7px;
margin-left: 0;
}
.editable-input {
vertical-align: top;
display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
width: auto; /* bootstrap-responsive has width: 100% that breakes layout */
white-space: normal; /* reset white-space decalred in parent*/
/* display-inline emulation for IE7*/
zoom: 1;
*display: inline;
}
.editable-buttons .editable-cancel {
margin-left: 7px;
}
/*for jquery-ui buttons need set height to look more pretty*/
.editable-buttons button.ui-button-icon-only {
height: 24px;
width: 30px;
}
.editableform-loading {
background: url('../img/loading.gif') center center no-repeat;
height: 25px;
width: auto;
min-width: 25px;
}
.editable-inline .editableform-loading {
background-position: left 5px;
}
.editable-error-block {
max-width: 300px;
margin: 5px 0 0 0;
width: auto;
white-space: normal;
}
/*add padding for jquery ui*/
.editable-error-block.ui-state-error {
padding: 3px;
}
.editable-error {
color: red;
}
/* ---- For specific types ---- */
.editableform .editable-date {
padding: 0;
margin: 0;
float: left;
}
/* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */
.editable-inline .add-on .icon-th {
margin-top: 3px;
margin-left: 1px;
}
/* checklist vertical alignment */
.editable-checklist label input[type="checkbox"],
.editable-checklist label span {
vertical-align: middle;
margin: 0;
}
.editable-checklist label {
white-space: nowrap;
}
/* set exact width of textarea to fit buttons toolbar */
.editable-wysihtml5 {
width: 566px;
height: 250px;
}
/* clear button shown as link in date inputs */
.editable-clear {
clear: both;
font-size: 0.9em;
text-decoration: none;
text-align: right;
}
/* IOS-style clear button for text inputs */
.editable-clear-x {
background: url('../img/clear.png') center center no-repeat;
display: block;
width: 13px;
height: 13px;
position: absolute;
opacity: 0.6;
z-index: 100;
top: 50%;
right: 6px;
margin-top: -6px;
}
.editable-clear-x:hover {
opacity: 1;
}
.editable-pre-wrapped {
white-space: pre-wrap;
}
.editable-container.editable-popup {
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
}
.editable-container.popover {
width: auto; /* without this rule popover does not stretch */
}
.editable-container.editable-inline {
display: inline-block;
vertical-align: middle;
width: auto;
/* inline-block emulation for IE7*/
zoom: 1;
*display: inline;
}
.editable-container.ui-widget {
font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */
z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */
}
.editable-click,
a.editable-click,
a.editable-click:hover {
text-decoration: none;
border-bottom: dashed 1px #0088cc;
}
.editable-click.editable-disabled,
a.editable-click.editable-disabled,
a.editable-click.editable-disabled:hover {
color: #585858;
cursor: default;
border-bottom: none;
}
.editable-empty, .editable-empty:hover, .editable-empty:focus{
font-style: italic;
color: #DD1144;
/* border-bottom: none; */
text-decoration: none;
}
.editable-unsaved {
font-weight: bold;
}
.editable-unsaved:after {
/* content: '*'*/
}
.editable-bg-transition {
-webkit-transition: background-color 1400ms ease-out;
-moz-transition: background-color 1400ms ease-out;
-o-transition: background-color 1400ms ease-out;
-ms-transition: background-color 1400ms ease-out;
transition: background-color 1400ms ease-out;
}
/*see https://github.com/vitalets/x-editable/issues/139 */
.form-horizontal .editable
{
padding-top: 5px;
display:inline-block;
}
/*!
* Datepicker for Bootstrap
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.datepicker {
padding: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
}*/
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
top: -7px;
left: 6px;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
position: absolute;
top: -6px;
left: 7px;
}
.datepicker > div {
display: none;
}
.datepicker.days div.datepicker-days {
display: block;
}
.datepicker.months div.datepicker-months {
display: block;
}
.datepicker.years div.datepicker-years {
display: block;
}
.datepicker table {
margin: 0;
}
.datepicker td,
.datepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.day:hover {
background: #eeeeee;
cursor: pointer;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #999999;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
background-image: linear-gradient(top, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #000;
}
.datepicker table tr td.today:hover,
.datepicker table tr td.today:hover:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today:hover.disabled,
.datepicker table tr td.today.disabled.disabled,
.datepicker table tr td.today.disabled:hover.disabled,
.datepicker table tr td.today[disabled],
.datepicker table tr td.today:hover[disabled],
.datepicker table tr td.today.disabled[disabled],
.datepicker table tr td.today.disabled:hover[disabled] {
background-color: #fdf59a;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
.datepicker table tr td.today:hover:hover {
color: #000;
}
.datepicker table tr td.today.active:hover {
color: #fff;
}
.datepicker table tr td.range,
.datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:hover {
background: #eeeeee;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today,
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:hover {
background-color: #f3d17a;
background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
background-image: linear-gradient(top, #f3c17a, #f3e97a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
border-color: #f3e97a #f3e97a #edde34;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today:hover:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today:hover.disabled,
.datepicker table tr td.range.today.disabled.disabled,
.datepicker table tr td.range.today.disabled:hover.disabled,
.datepicker table tr td.range.today[disabled],
.datepicker table tr td.range.today:hover[disabled],
.datepicker table tr td.range.today.disabled[disabled],
.datepicker table tr td.range.today.disabled:hover[disabled] {
background-color: #f3e97a;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active {
background-color: #efe24b \9;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
background-color: #9e9e9e;
background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
background-image: -o-linear-gradient(top, #b3b3b3, #808080);
background-image: linear-gradient(top, #b3b3b3, #808080);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
border-color: #808080 #808080 #595959;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected:hover:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected:hover.disabled,
.datepicker table tr td.selected.disabled.disabled,
.datepicker table tr td.selected.disabled:hover.disabled,
.datepicker table tr td.selected[disabled],
.datepicker table tr td.selected:hover[disabled],
.datepicker table tr td.selected.disabled[disabled],
.datepicker table tr td.selected.disabled:hover[disabled] {
background-color: #808080;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active {
background-color: #666666 \9;
}
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active:hover:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active:hover.disabled,
.datepicker table tr td.active.disabled.disabled,
.datepicker table tr td.active.disabled:hover.disabled,
.datepicker table tr td.active[disabled],
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker table tr td span:hover {
background: #eeeeee;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active:hover.disabled,
.datepicker table tr td span.active.disabled.disabled,
.datepicker table tr td span.active.disabled:hover.disabled,
.datepicker table tr td span.active[disabled],
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #999999;
}
.datepicker th.datepicker-switch {
width: 145px;
}
.datepicker thead tr:first-child th,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover,
.datepicker tfoot tr th:hover {
background: #eeeeee;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.datepicker thead tr:first-child th.cw {
cursor: default;
background-color: transparent;
}
.input-append.date .add-on i,
.input-prepend.date .add-on i {
display: block;
cursor: pointer;
width: 16px;
height: 16px;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.input-daterange .add-on {
display: inline-block;
width: auto;
min-width: 16px;
height: 18px;
padding: 4px 5px;
font-weight: normal;
line-height: 18px;
text-align: center;
text-shadow: 0 1px 0 #ffffff;
vertical-align: middle;
background-color: #eeeeee;
border: 1px solid #ccc;
margin-left: -5px;
margin-right: -5px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -718,3 +718,9 @@ label {
padding: 20px 20px 0 20px; padding: 20px 20px 0 20px;
} }
} }
// -- Editable tweaks ---------------------------------------------------------
.editable-click, a.editable-click, a.editable-click:hover {
border-bottom: 1px dotted #0088CC;
}

View File

@@ -2,6 +2,8 @@
{$page_title={intl l='Catalog'}} {$page_title={intl l='Catalog'}}
{$thelia_page_css_file = "assets/bootstrap-editable/css/bootstrap-editable.css"}
{include file='includes/header.inc.html'} {include file='includes/header.inc.html'}
<div class="catalog"> <div class="catalog">
@@ -16,7 +18,7 @@
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<div class="general-block-decorator"> <div class="general-block-decorator">
<table class="table table-striped table-condensed"> <table class="table table-striped table-condensed" id="category_list">
<caption> <caption>
{* display parent category name, and get current cat ID *} {* display parent category name, and get current cat ID *}
{loop name="category_title" type="category" visible="*" id="{$current_category_id}"} {loop name="category_title" type="category" visible="*" id="{$current_category_id}"}
@@ -68,9 +70,9 @@
<td> <td>
{loop type="auth" name="can_change" context="admin" roles="ADMIN" permissions="admin.category.edit"} {loop type="auth" name="can_change" context="admin" roles="ADMIN" permissions="admin.category.edit"}
<a href="{url path='admin/catalog/category' id="{$ID}" action='positionUp'}"><i class="icon-arrow-up"></i></a> <a href="{url path='admin/catalog/category' category_id="{$ID}" action='positionUp'}"><i class="icon-arrow-up"></i></a>
<span class="object_classement_editable" data-action="changeCategoryPosition" data-name="category_id" data-id="{$ID}">{$POSITION}</span> <span class="categoryPositionChange" data-id="{$ID}">{$POSITION}</span>
<a href="{url path='admin/catalog/category' id="{$ID}" action='positionDown'}"><i class="icon-arrow-down"></i></a> <a href="{url path='admin/catalog/category' category_id="{$ID}" action='positionDown'}"><i class="icon-arrow-down"></i></a>
{/loop} {/loop}
{elseloop rel="can_change"} {elseloop rel="can_change"}
@@ -200,6 +202,10 @@
{include file='includes/js.inc.html'} {include file='includes/js.inc.html'}
{javascripts file='assets/bootstrap-editable/js/bootstrap-editable.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script> <script>
$(function() { $(function() {
@@ -211,7 +217,8 @@ $(function() {
{/if} {/if}
{/form} {/form}
{* Always reset dialog on close *} {* Always reset create dialog on close *}
$('#add_category_dialog').on('hidden',function() { $('#add_category_dialog').on('hidden',function() {
// Hide error message // Hide error message
$('#add_category_dialog_error').remove(); $('#add_category_dialog_error').remove();
@@ -224,6 +231,7 @@ $(function() {
}); });
{* Set the proper category ID in the delete confirmation dialog *} {* Set the proper category ID in the delete confirmation dialog *}
$(document).on("click", ".category-delete", function () { $(document).on("click", ".category-delete", function () {
$('#'+'delete-category-id').val($(this).data('id')); $('#'+'delete-category-id').val($(this).data('id'));
}); });
@@ -239,6 +247,27 @@ $(function() {
}); });
}); });
{* 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/catalog/category' action='changePosition' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
}) })
</script> </script>

View File

@@ -16,7 +16,7 @@
{form_hidden_fields form=$form} {form_hidden_fields form=$form}
{form_field form=$form field='id'} {form_field form=$form field='category_id'}
<input type="hidden" name="{$name}" id="delete-category-id" value="" /> <input type="hidden" name="{$name}" id="delete-category-id" value="" />
{/form_field} {/form_field}

View File

@@ -15,6 +15,14 @@
<link rel="stylesheet" href="{$asset_url}"> <link rel="stylesheet" href="{$asset_url}">
{/stylesheets} {/stylesheets}
{* Include here page specifc CSS file, if any *}
{if ! empty($thelia_page_css_file)}
{stylesheets file="../$thelia_page_css_file" filters='less,cssembed'}
<link rel="stylesheet" href="{$asset_url}" target="screen">
{/stylesheets}
{/if}
{stylesheets file='../assets/css/*' filters='less,cssembed'} {stylesheets file='../assets/css/*' filters='less,cssembed'}
<link rel="stylesheet" href="{$asset_url}"> <link rel="stylesheet" href="{$asset_url}">
{/stylesheets} {/stylesheets}
@@ -22,7 +30,7 @@
{* Include here page specifc CSS file, if any *} {* Include here page specifc CSS file, if any *}
{if ! empty($thelia_page_css_file)} {if ! empty($thelia_page_css_file)}
{stylesheets file='../assets/css/$thelia_page_css_file' filters='less,cssembed'} {stylesheets file="../$thelia_page_css_file" filters='less,cssembed'}
<link rel="stylesheet" href="{$asset_url}" target="screen"> <link rel="stylesheet" href="{$asset_url}" target="screen">
{/stylesheets} {/stylesheets}
{/if} {/if}

View File

@@ -20,6 +20,10 @@
<input type="hidden" name="{$name}" value="{$RETURN_TO_URL}" /> {* the url the user is redirected to on login success *} <input type="hidden" name="{$name}" value="{$RETURN_TO_URL}" /> {* the url the user is redirected to on login success *}
{/form_field} {/form_field}
{form_field form=$form field='auto_login'}
<input type="hidden" name="{$name}" value="1" /> {* the customer will be loogged-in automatically *}
{/form_field}
{* {*
The form error status and the form error messages are defined in Customer action, The form error status and the form error messages are defined in Customer action,
and passed back to the form plugin through the ParserContext. and passed back to the form plugin through the ParserContext.