Merge branch 'master' into debugbar

This commit is contained in:
Manuel Raynaud
2013-09-07 16:31:29 +02:00
70 changed files with 2294 additions and 991 deletions

View File

@@ -107,6 +107,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
CurrencyQuery::create()->filterByByDefault(true)->update(array('ByDefault' => false)); CurrencyQuery::create()->filterByByDefault(true)->update(array('ByDefault' => false));
$currency $currency
->setDispatcher($this->getDispatcher())
->setByDefault($event->getIsDefault()) ->setByDefault($event->getIsDefault())
->save() ->save()
; ;
@@ -139,7 +140,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
$rates_url = ConfigQuery::read('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml'); $rates_url = ConfigQuery::read('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
$rate_data = file_get_contents($rates_url); $rate_data = @file_get_contents($rates_url);
if ($rate_data && $sxe = new \SimpleXMLElement($rate_data)) { if ($rate_data && $sxe = new \SimpleXMLElement($rate_data)) {
@@ -149,12 +150,16 @@ class Currency extends BaseAction implements EventSubscriberInterface
$rate = floatval($last['rate']); $rate = floatval($last['rate']);
if (null !== $currency = CurrencyQuery::create()->findOneByCode($code)) { if (null !== $currency = CurrencyQuery::create()->findOneByCode($code)) {
$currency->setRate($rate)->save(); $currency
->setDispatcher($this->getDispatcher())
->setRate($rate)
->save()
;
} }
} }
} }
else { else {
throw new \RuntimeException(sprintf("Failed to get currency rates data from URL %s", $url)); throw new \RuntimeException(sprintf("Failed to get currency rates data from URL %s", $rates_url));
} }
} }
@@ -165,12 +170,18 @@ class Currency extends BaseAction implements EventSubscriberInterface
*/ */
public function updatePosition(CurrencyUpdatePositionEvent $event) public function updatePosition(CurrencyUpdatePositionEvent $event)
{ {
if (null !== $category = CurrencyQuery::create()->findOneById($event->getObjectId())) { if (null !== $currency = CurrencyQuery::create()->findOneById($event->getObjectId())) {
if ($event->getMode() == BaseChangePositionEvent::POSITION_ABSOLUTE) $currency->setDispatcher($this->getDispatcher());
return $category->changeAbsolutePosition($event->getPosition());
else $mode = $event->getMode();
return $this->exchangePosition($event->getMode());
if ($mode == CurrencyUpdatePositionEvent::POSITION_ABSOLUTE)
return $currency->changeAbsolutePosition($event->getPosition());
else if ($mode == CurrencyUpdatePositionEvent::POSITION_UP)
return $currency->movePositionUp();
else if ($mode == CurrencyUpdatePositionEvent::POSITION_DOWN)
return $currency->movePositionDown();
} }
} }

View File

@@ -24,6 +24,7 @@
namespace Thelia\Command; namespace Thelia\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Exception\IOException;
@@ -44,7 +45,14 @@ class CacheClear extends ContainerAwareCommand
{ {
$this $this
->setName("cache:clear") ->setName("cache:clear")
->setDescription("Invalidate all caches"); ->setDescription("Invalidate all caches")
->addOption(
"without-assets",
null,
InputOption::VALUE_NONE,
"remove cache assets"
)
;
} }
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
@@ -52,20 +60,28 @@ class CacheClear extends ContainerAwareCommand
$cacheDir = $this->getContainer()->getParameter("kernel.cache_dir"); $cacheDir = $this->getContainer()->getParameter("kernel.cache_dir");
if (!is_writable($cacheDir)) { $this->clearCache($cacheDir, $output);
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $cacheDir)); if(!$input->getOption("without-assets")) {
} $this->clearCache(THELIA_WEB_DIR . "/assets", $output);
$output->writeln(sprintf("Clearing cache in <info>%s</info> directory", $cacheDir));
$fs = new Filesystem();
try {
$fs->remove($cacheDir);
$output->writeln("<info>cache cleared successfully</info>");
} catch (IOException $e) {
$output->writeln(sprintf("error during clearing cache : %s", $e->getMessage()));
} }
} }
protected function clearCache($dir, OutputInterface $output)
{
if (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $dir));
}
$output->writeln(sprintf("Clearing cache in <info>%s</info> directory", $dir));
$fs = new Filesystem();
try {
$fs->remove($dir);
$output->writeln(sprintf("<info>%s cache dir cleared successfully</info>", $dir));
} catch (IOException $e) {
$output->writeln(sprintf("error during clearing cache : %s", $e->getMessage()));
}
}
} }

View File

@@ -129,6 +129,7 @@
<service id="smarty.plugin.assetic" class="Thelia\Core\Template\Smarty\Plugins\Assetic" > <service id="smarty.plugin.assetic" class="Thelia\Core\Template\Smarty\Plugins\Assetic" >
<tag name="thelia.parser.register_plugin"/> <tag name="thelia.parser.register_plugin"/>
<argument>%kernel.environment%</argument>
</service> </service>
<service id="smarty.plugin.theliasyntax" class="Thelia\Core\Template\Smarty\Plugins\TheliaSyntax" > <service id="smarty.plugin.theliasyntax" class="Thelia\Core\Template\Smarty\Plugins\TheliaSyntax" >
@@ -184,6 +185,7 @@
<service id="smarty.plugin.dataAccess" class="Thelia\Core\Template\Smarty\Plugins\DataAccessFunctions" scope="request"> <service id="smarty.plugin.dataAccess" class="Thelia\Core\Template\Smarty\Plugins\DataAccessFunctions" scope="request">
<tag name="thelia.parser.register_plugin"/> <tag name="thelia.parser.register_plugin"/>
<argument type="service" id="request" />
<argument type="service" id="thelia.securityContext" /> <argument type="service" id="thelia.securityContext" />
<argument type="service" id="thelia.parser.context"/> <argument type="service" id="thelia.parser.context"/>
</service> </service>

View File

@@ -75,6 +75,10 @@
<argument key="debug">%kernel.debug%</argument> <argument key="debug">%kernel.debug%</argument>
</argument> </argument>
<argument type="service" id="request.context"/> <argument type="service" id="request.context"/>
<tag name="router.register" priority="254"/>
</service>
<service id="router.rewrite" class="Thelia\Core\Routing\RewritingRouter">
<tag name="router.register" priority="255"/> <tag name="router.register" priority="255"/>
</service> </service>

View File

@@ -113,10 +113,19 @@
<default key="_controller">Thelia\Controller\Admin\CurrencyController::deleteAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::deleteAction</default>
</route> </route>
<route id="admin.configuration.currencies.delete" path="/admin/configuration/currencies/update-position"> <route id="admin.configuration.attribute" path="/admin/configuration/product_attributes">
<default key="_controller">Thelia\Controller\Admin\AttributeController::defaultAction</default>
</route>
<!-- attribute and feature routes management -->
<route id="admin.configuration.currencies.update-position" path="/admin/configuration/product_attributes">
<default key="_controller">Thelia\Controller\Admin\CurrencyController::updatePositionAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::updatePositionAction</default>
</route> </route>
<!-- end attribute and feature routes management -->
<!-- The default route, to display a template --> <!-- The default route, to display a template -->
<route id="admin.processTemplate" path="/admin/{template}"> <route id="admin.processTemplate" path="/admin/{template}">

View File

@@ -60,13 +60,4 @@
<default key="_view">cart</default> <default key="_view">cart</default>
</route> </route>
<!-- Empêche l'accès àl'admin, genre: http://localhost/thelia2/index_dev.php/admin/login amène sur l'accueuil de la boutique
<route id="url-rewriting.check" path="/{rewritten_url}" methods="GET">
<default key="_controller">Thelia\Controller\Front\UrlRewritingController::check</default>
<requirement key="rewritten_url">.*</requirement>
</route>
-->
</routes> </routes>

View File

@@ -0,0 +1,57 @@
<?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\Controller\Admin;
use Thelia\Core\Event\MessageDeleteEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Tools\URL;
use Thelia\Core\Event\MessageUpdateEvent;
use Thelia\Core\Event\MessageCreateEvent;
use Thelia\Log\Tlog;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Core\Security\Exception\AuthorizationException;
use Thelia\Model\MessageQuery;
use Thelia\Form\MessageModificationForm;
use Thelia\Form\MessageCreationForm;
/**
* Manages messages sent by mail
*
* @author Franck Allimant <franck@cqfdev.fr>
*/
class AttributeController extends BaseAdminController
{
/**
* The default action is displaying the messages list.
*
* @return Symfony\Component\HttpFoundation\Response the response
*/
public function defaultAction() {
if (null !== $response = $this->checkAuth("admin.configuration.attributes.view")) return $response;
return $this->render('product_attributes');
}
}

View File

@@ -241,7 +241,7 @@ class ConfigController extends BaseAdminController
if ($this->getRequest()->get('save_mode') == 'stay') { if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToRoute( $this->redirectToRoute(
"admin.configuration.variables.change", "admin.configuration.variables.update",
array('variable_id' => $variable_id) array('variable_id' => $variable_id)
); );
} }

View File

@@ -316,17 +316,22 @@ class CurrencyController extends BaseAdminController
if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
try { try {
$id = $this->getRequest()->get('currency_id', 0);
$mode = $this->getRequest()->get('mode', null); $mode = $this->getRequest()->get('mode', null);
if ($mode == 'up')
$mode = CurrencyUpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = CurrencyUpdatePositionEvent::POSITION_DOWN;
else
$mode = CurrencyUpdatePositionEvent::POSITION_ABSOLUTE;
$position = $this->getRequest()->get('position', null); $position = $this->getRequest()->get('position', null);
$event = new CurrencyUpdatePositionEvent(); $event = new CurrencyUpdatePositionEvent(
$this->getRequest()->get('currency_id', null),
$event $mode,
->setObjectId($this->getRequest()->get('currency_id', 0)) $this->getRequest()->get('position', null)
->setPosition($this->getRequest()->get('position', 0)) );
->setMode($mode)
;
$this->dispatch(TheliaEvents::CURRENCY_UPDATE_POSITION, $event); $this->dispatch(TheliaEvents::CURRENCY_UPDATE_POSITION, $event);
} }

View File

@@ -81,6 +81,17 @@ class BaseController extends ContainerAware
return $this->container->get('event_dispatcher'); return $this->container->get('event_dispatcher');
} }
/**
*
* return the Translator
*
* @return mixed \Thelia\Core\Translation\Translator
*/
public function getTranslator()
{
return $this->container->get('thelia.translator');
}
/** /**
* Return the parser context, * Return the parser context,
* *
@@ -215,7 +226,7 @@ class BaseController extends ContainerAware
$route = $this->container->get($routerName)->getRouteCollection()->get($routeId); $route = $this->container->get($routerName)->getRouteCollection()->get($routeId);
if ($route == null) { if ($route == null) {
throw new InvalidArgumentException(sprintf("Route ID '%s' does not exists.", $routeId)); throw new \InvalidArgumentException(sprintf("Route ID '%s' does not exists.", $routeId));
} }
return $route->getPath(); return $route->getPath();

View File

@@ -46,16 +46,6 @@ class DefaultController extends BaseFrontController
*/ */
public function noAction(Request $request) public function noAction(Request $request)
{ {
if(ConfigQuery::isRewritingEnable()) {
/* Does the query GET parameters match a rewritten URL ? */
$rewrittenUrl = URL::getInstance()->retrieveCurrent($request);
if($rewrittenUrl->rewrittenUrl !== null) {
/* 301 redirection to rewritten URL */
$this->redirect($rewrittenUrl->rewrittenUrl, 301);
}
}
$view = null; $view = null;
if (! $view = $request->query->get('view')) { if (! $view = $request->query->get('view')) {
@@ -71,5 +61,15 @@ class DefaultController extends BaseFrontController
$request->attributes->set("_view", "index"); $request->attributes->set("_view", "index");
} }
if(ConfigQuery::isRewritingEnable()) {
if($request->attributes->get('_rewritten', false) === false) {
/* Does the query GET parameters match a rewritten URL ? */
$rewrittenUrl = URL::getInstance()->retrieveCurrent($request);
if($rewrittenUrl->rewrittenUrl !== null) {
/* 301 redirection to rewritten URL */
$this->redirect($rewrittenUrl->rewrittenUrl, 301);
}
}
}
} }
} }

View File

@@ -74,14 +74,4 @@ class BaseUpdatePositionEvent extends ActionEvent
$this->object_id = $object_id; $this->object_id = $object_id;
return $this; return $this;
} }
public function getObjectId()
{
return $this->object_id;
}
public function setObjectId($object_id)
{
$this->object_id = $object_id;
}
} }

View File

@@ -23,6 +23,6 @@
namespace Thelia\Core\Event; namespace Thelia\Core\Event;
class CategoryChangePositionEvent extends BaseChangePositionEvent class CurrencyUpdatePositionEvent extends BaseUpdatePositionEvent
{ {
} }

View File

@@ -0,0 +1,219 @@
<?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\Routing;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouterInterface;
use Thelia\Exception\RedirectException;
use Thelia\Exception\UrlRewritingException;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\Redirect;
use Thelia\Tools\URL;
/**
* Class RewritingRouter
* @package Thelia\Core\Routing
* @author Manuel Raynaud <mraynaud@openstudio.fr>
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*/
class RewritingRouter implements RouterInterface, RequestMatcherInterface
{
/**
* @var RequestContext The context
*/
protected $context;
/**
* @var options, don't use for now but mandatory
*/
protected $options;
/**
* Sets the request context.
*
* @param RequestContext $context The context
*
* @api
*/
public function setContext(RequestContext $context)
{
// TODO: Implement setContext() method.
$this->context = $context;
}
/**
* Gets the request context.
*
* @return RequestContext The context
*
* @api
*/
public function getContext()
{
// TODO: Implement getContext() method.
return $this->context;
}
public function setOption($key, $value)
{
//NOTHING TO DO FOR NOW
}
/**
* Gets the RouteCollection instance associated with this Router.
*
* @return RouteCollection A RouteCollection instance
*/
public function getRouteCollection()
{
return new RouteCollection();
}
/**
* Generates a URL or path for a specific route based on the given parameters.
*
* Parameters that reference placeholders in the route pattern will substitute them in the
* path or host. Extra params are added as query string to the URL.
*
* When the passed reference type cannot be generated for the route because it requires a different
* host or scheme than the current one, the method will return a more comprehensive reference
* that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
* but the route requires the https scheme whereas the current scheme is http, it will instead return an
* ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
* the route in any case.
*
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
*
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param Boolean|string $referenceType The type of reference to be generated (one of the constants)
*
* @return string The generated URL
*
* @throws RouteNotFoundException If the named route doesn't exist
* @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
* @throws InvalidParameterException When a parameter value for a placeholder is not correct because
* it does not match the requirement
*
* @api
*/
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
// TODO: Implement generate() method.
}
/**
* Tries to match a URL path with a set of routes.
*
* If the matcher can not find information, it must throw one of the exceptions documented
* below.
*
* @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
*
* @return array An array of parameters
*
* @throws ResourceNotFoundException If the resource could not be found
* @throws MethodNotAllowedException If the resource was found but the request method is not allowed
*
* @api
*/
public function match($pathinfo)
{
throw new ResourceNotFoundException("impossible to find route with this method, please use matchRequest method");
}
/**
* Tries to match a request with a set of routes.
*
* If the matcher can not find information, it must throw one of the exceptions documented
* below.
*
* @param Request $request The request to match
*
* @throws \Exception|\Thelia\Exception\UrlRewritingException
* @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException
* @throws \Thelia\Exception\RedirectException
* @return array An array of parameters
*
*/
public function matchRequest(Request $request)
{
if(ConfigQuery::isRewritingEnable()) {
try {
$rewrittenUrlData = URL::getInstance()->resolve($request->getPathInfo());
} catch(UrlRewritingException $e) {
switch($e->getCode()) {
case UrlRewritingException::URL_NOT_FOUND :
throw new ResourceNotFoundException();
break;
default:
throw $e;
}
}
/* is the URL redirected ? */
if(null !== $rewrittenUrlData->redirectedToUrl) {
$this->redirect($rewrittenUrlData->redirectedToUrl, 301);
}
/* define GET arguments in request */
if(null !== $rewrittenUrlData->view) {
$request->attributes->set('_view', $rewrittenUrlData->view);
if(null !== $rewrittenUrlData->viewId) {
$request->query->set($rewrittenUrlData->view . '_id', $rewrittenUrlData->viewId);
}
}
if(null !== $rewrittenUrlData->locale) {
$request->query->set('locale', $rewrittenUrlData->locale);
}
foreach($rewrittenUrlData->otherParameters as $parameter => $value) {
$request->query->set($parameter, $value);
}
return array (
'_controller' => 'Thelia\\Controller\\Front\\DefaultController::noAction',
'_route' => 'rewrite',
'_rewritten' => true,
);
}
throw new ResourceNotFoundException();
}
protected function redirect($url, $status = 302)
{
Redirect::exec($url, $status);
}
}

View File

@@ -43,15 +43,16 @@ class AsseticHelper
* Generates assets from $asset_path in $output_path, using $filters. * Generates assets from $asset_path in $output_path, using $filters.
* *
* @param string $asset_path the full path to the asset file (or file collection) * @param string $asset_path the full path to the asset file (or file collection)
* @param unknown $output_path the full disk path to the output directory (shoud be visible to web server) * @param string $output_path the full disk path to the output directory (shoud be visible to web server)
* @param unknown $output_url the URL to the generated asset directory * @param string $output_url the URL to the generated asset directory
* @param unknown $asset_type the asset type: css, js, ... The generated files will have this extension. Pass an empty string to use the asset source extension. * @param string $asset_type the asset type: css, js, ... The generated files will have this extension. Pass an empty string to use the asset source extension.
* @param unknown $filters a list of filters, as defined below (see switch($filter_name) ...) * @param array $filters a list of filters, as defined below (see switch($filter_name) ...)
* @param unknown $debug true / false * @param boolean $debug true / false
* @param boolean $dev_mode true / false. If true, assets are not cached and always compiled.
* @throws \InvalidArgumentException if an invalid filter name is found * @throws \InvalidArgumentException if an invalid filter name is found
* @return string The URL to the generated asset file. * @return string The URL to the generated asset file.
*/ */
public function asseticize($asset_path, $output_path, $output_url, $asset_type, $filters, $debug) public function asseticize($asset_path, $output_path, $output_url, $asset_type, $filters, $debug, $dev_mode = false)
{ {
$asset_name = basename($asset_path); $asset_name = basename($asset_path);
$asset_dir = dirname($asset_path); $asset_dir = dirname($asset_path);
@@ -106,17 +107,49 @@ class AsseticHelper
$factory->setDebug($debug); $factory->setDebug($debug);
$factory->addWorker(new CacheBustingWorker()); $factory->addWorker(new CacheBustingWorker('-'));
// Prepare the assets writer // We do not pass the filter list here, juste to get the asset file name
$writer = new AssetWriter($output_path); $asset = $factory->createAsset($asset_name);
$asset = $factory->createAsset($asset_name, $filter_list); $asset_target_path = $asset->getTargetPath();
$cache = new AssetCache($asset, new FilesystemCache($output_path)); $target_file = sprintf("%s/%s", $output_path, $asset_target_path);
$writer->writeAsset($cache); // As it seems that assetic cannot handle a real file cache, let's do the job ourselves.
// It works only if the CacheBustingWorker is used, as a new file name is generated for each version.
//
// the previous version of the file is deleted, by getting the first part of the ouput file name
// (the one before '-'), and delete aby file beginning with the same string. Example:
// old name: 3bc974a-dfacc1f.css
// new name: 3bc974a-ad3ef47.css
//
// before generating 3bc974a-ad3ef47.css, delete 3bc974a-* files.
//
if ($dev_mode == true || ! file_exists($target_file)) {
return rtrim($output_url, '/').'/'.$asset->getTargetPath(); // Delete previous version of the file
list($commonPart, $dummy) = explode('-', $asset_target_path);
foreach (glob("$output_path/$commonPart-*") as $filename) {
@unlink($filename);
}
// Apply filters now
foreach ($filter_list as $filter) {
if ('?' != $filter[0]) {
$asset->ensureFilter($fm->get($filter));
}
elseif (!$debug) {
$asset->ensureFilter($fm->get(substr($filter, 1)));
}
}
$writer = new AssetWriter($output_path);
$writer->writeAsset($asset);
}
return rtrim($output_url, '/').'/'.$asset_target_path;
} }
} }

View File

@@ -162,7 +162,8 @@ class Attribute extends BaseI18nLoop
->set("TITLE",$attribute->getVirtualColumn('i18n_TITLE')) ->set("TITLE",$attribute->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $attribute->getVirtualColumn('i18n_CHAPO')) ->set("CHAPO", $attribute->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $attribute->getVirtualColumn('i18n_DESCRIPTION')) ->set("DESCRIPTION", $attribute->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $attribute->getVirtualColumn('i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $attribute->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $attribute->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -131,7 +131,8 @@ class AttributeAvailability extends BaseI18nLoop
->set("TITLE",$attributeAv->getVirtualColumn('i18n_TITLE')) ->set("TITLE",$attributeAv->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $attributeAv->getVirtualColumn('i18n_CHAPO')) ->set("CHAPO", $attributeAv->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $attributeAv->getVirtualColumn('i18n_DESCRIPTION')) ->set("DESCRIPTION", $attributeAv->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $attributeAv->getVirtualColumn('i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $attributeAv->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $attributeAv->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -113,10 +113,10 @@ class Country extends BaseI18nLoop
->set("TITLE",$country->getVirtualColumn('i18n_TITLE')) ->set("TITLE",$country->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $country->getVirtualColumn('i18n_CHAPO')) ->set("CHAPO", $country->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $country->getVirtualColumn('i18n_DESCRIPTION')) ->set("DESCRIPTION", $country->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $country->getVirtualColumn('i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $country->getVirtualColumn('i18n_POSTSCRIPTUM'))
$loopResultRow->set("ISOCODE", $country->getIsocode()); ->set("ISOCODE", $country->getIsocode())
$loopResultRow->set("ISOALPHA2", $country->getIsoalpha2()); ->set("ISOALPHA2", $country->getIsoalpha2())
$loopResultRow->set("ISOALPHA3", $country->getIsoalpha3()); ->set("ISOALPHA3", $country->getIsoalpha3());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -154,7 +154,8 @@ class Feature extends BaseI18nLoop
->set("TITLE",$feature->getVirtualColumn('i18n_TITLE')) ->set("TITLE",$feature->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $feature->getVirtualColumn('i18n_CHAPO')) ->set("CHAPO", $feature->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $feature->getVirtualColumn('i18n_DESCRIPTION')) ->set("DESCRIPTION", $feature->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $feature->getVirtualColumn('i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $feature->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $feature->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -129,7 +129,8 @@ class FeatureAvailability extends BaseI18nLoop
->set("TITLE",$featureAv->getVirtualColumn('i18n_TITLE')) ->set("TITLE",$featureAv->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $featureAv->getVirtualColumn('i18n_CHAPO')) ->set("CHAPO", $featureAv->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $featureAv->getVirtualColumn('i18n_DESCRIPTION')) ->set("DESCRIPTION", $featureAv->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $featureAv->getVirtualColumn('i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $featureAv->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $featureAv->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -149,7 +149,8 @@ class FeatureValue extends BaseI18nLoop
->set("TITLE",$featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_TITLE')) ->set("TITLE",$featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_TITLE'))
->set("CHAPO", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_CHAPO')) ->set("CHAPO", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_CHAPO'))
->set("DESCRIPTION", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_DESCRIPTION')) ->set("DESCRIPTION", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM')); ->set("POSTSCRIPTUM", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM'))
->set("POSITION", $featureValue->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -89,7 +89,8 @@ class Title extends BaseI18nLoop
->set("LOCALE",$locale) ->set("LOCALE",$locale)
->set("DEFAULT", $title->getByDefault()) ->set("DEFAULT", $title->getByDefault())
->set("SHORT", $title->getVirtualColumn('i18n_SHORT')) ->set("SHORT", $title->getVirtualColumn('i18n_SHORT'))
->set("LONG", $title->getVirtualColumn('i18n_LONG')); ->set("LONG", $title->getVirtualColumn('i18n_LONG'))
->set("POSITION", $title->getPosition());
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -34,18 +34,22 @@ class SmartyAssetsManager
private $web_root; private $web_root;
private $path_relative_to_web_root; private $path_relative_to_web_root;
private $developmentMode;
/** /**
* Creates a new SmartyAssetsManager instance * Creates a new SmartyAssetsManager instance
* *
* @param string $web_root the disk path to the web root * @param string $web_root the disk path to the web root
* @param string $path_relative_to_web_root the path (relative to web root) where the assets will be generated * @param string $path_relative_to_web_root the path (relative to web root) where the assets will be generated
* @param boolean $developmentMode true / false. If true, assets are not cached, and always generated.
*/ */
public function __construct($web_root, $path_relative_to_web_root) public function __construct($web_root, $path_relative_to_web_root, $developmentMode)
{ {
$this->web_root = $web_root; $this->web_root = $web_root;
$this->path_relative_to_web_root = $path_relative_to_web_root; $this->path_relative_to_web_root = $path_relative_to_web_root;
$this->developmentMode = $developmentMode;
$this->assetic_manager = new AsseticHelper(); $this->assetic_manager = new AsseticHelper();
} }
@@ -73,7 +77,8 @@ class SmartyAssetsManager
URL::getInstance()->absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */), URL::getInstance()->absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */),
$assetType, $assetType,
$filters, $filters,
$debug $debug,
$this->developmentMode
); );
return $url; return $url;

View File

@@ -71,11 +71,11 @@ class AdminUtilities extends AbstractSmartyPlugin
if ($permissions == null || $this->securityContext->isGranted("ADMIN", array($permission))) { if ($permissions == null || $this->securityContext->isGranted("ADMIN", array($permission))) {
return sprintf( return sprintf(
'<a href="%s"><i class="glyphicon glyphicon-arrow-up"></i></a><span class="%s" data-id="%s">%s</span><a href="%s"><i class="glyphicon glyphicon-arrow-down"></i></a>', '<a href="%s"><i class="glyphicon glyphicon-arrow-up"></i></a><span class="%s" data-id="%s">%s</span><a href="%s"><i class="glyphicon glyphicon-arrow-down"></i></a>',
URL::getInstance()->absoluteUrl("$path/positionUp", array($url_parameter => $id)), URL::getInstance()->absoluteUrl($path, array('mode' => 'up', $url_parameter => $id)),
$in_place_edit_class, $in_place_edit_class,
$id, $id,
$position, $position,
URL::getInstance()->absoluteUrl("$path/positionDown", array($url_parameter => $id)) URL::getInstance()->absoluteUrl($path, array('mode' => 'down', $url_parameter => $id))
); );
} }
else { else {
@@ -121,7 +121,7 @@ class AdminUtilities extends AbstractSmartyPlugin
} }
if (! empty($icon)) if (! empty($icon))
$output = sprintf('<i class="icon icon-chevron-%s"></i> ', $icon); $output = sprintf('<i class="glyphicon glyphicon-chevron-%s"></i> ', $icon);
else else
$output = ''; $output = '';

View File

@@ -32,13 +32,13 @@ class Assetic extends AbstractSmartyPlugin
{ {
public $assetManager; public $assetManager;
public function __construct() public function __construct($developmentMode)
{ {
$web_root = THELIA_WEB_DIR; $web_root = THELIA_WEB_DIR;
$asset_dir_from_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets'); $asset_dir_from_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets');
$this->assetManager = new SmartyAssetsManager($web_root, $asset_dir_from_web_root); $this->assetManager = new SmartyAssetsManager($web_root, $asset_dir_from_web_root, $developmentMode == 'dev');
} }
public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat) public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat)

View File

@@ -23,10 +23,20 @@
namespace Thelia\Core\Template\Smarty\Plugins; namespace Thelia\Core\Template\Smarty\Plugins;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Core\Template\Smarty\AbstractSmartyPlugin; use Thelia\Core\Template\Smarty\AbstractSmartyPlugin;
use Thelia\Core\Security\SecurityContext; use Thelia\Core\Security\SecurityContext;
use Thelia\Core\Template\ParserContext; use Thelia\Core\Template\ParserContext;
use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor;
use Thelia\Model\CategoryQuery;
use Thelia\Model\ContentQuery;
use Thelia\Model\FolderQuery;
use Thelia\Model\Product;
use Thelia\Model\ProductQuery;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Tools\DateTimeFormat;
/** /**
* Implementation of data access to main Thelia objects (users, cart, etc.) * Implementation of data access to main Thelia objects (users, cart, etc.)
* *
@@ -37,10 +47,13 @@ class DataAccessFunctions extends AbstractSmartyPlugin
{ {
private $securityContext; private $securityContext;
protected $parserContext; protected $parserContext;
protected $request;
public function __construct(SecurityContext $securityContext, ParserContext $parserContext) public function __construct(Request $request, SecurityContext $securityContext, ParserContext $parserContext)
{ {
$this->securityContext = $securityContext; $this->securityContext = $securityContext;
$this->parserContext = $parserContext;
$this->request = $request;
} }
/** /**
@@ -52,7 +65,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/ */
public function adminDataAccess($params, &$smarty) public function adminDataAccess($params, &$smarty)
{ {
return $this->userDataAccess("Admin User", $this->securityContext->getAdminUser(), $params); return $this->dataAccess("Admin User", $params, $this->securityContext->getAdminUser());
} }
/** /**
@@ -64,37 +77,146 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/ */
public function customerDataAccess($params, &$smarty) public function customerDataAccess($params, &$smarty)
{ {
return $this->userDataAccess("Customer User", $this->securityContext->getCustomerUser(), $params); return $this->dataAccess("Customer User", $params, $this->securityContext->getCustomerUser());
} }
public function productDataAccess($params, &$smarty)
{
$productId = $this->request->get('product_id');
if($productId !== null) {
$search = ProductQuery::create()
->filterById($productId);
return $this->dataAccessWithI18n("Product", $params, $search);
}
}
public function categoryDataAccess($params, &$smarty)
{
$categoryId = $this->request->get('category_id');
if($categoryId !== null) {
$search = CategoryQuery::create()
->filterById($categoryId);
return $this->dataAccessWithI18n("Category", $params, $search);
}
}
public function contentDataAccess($params, &$smarty)
{
$contentId = $this->request->get('content_id');
if($contentId !== null) {
$search = ContentQuery::create()
->filterById($contentId);
return $this->dataAccessWithI18n("Content", $params, $search);
}
}
public function folderDataAccess($params, &$smarty)
{
$folderId = $this->request->get('folder_id');
if($folderId !== null) {
$search = FolderQuery::create()
->filterById($folderId);
return $this->dataAccessWithI18n("Folder", $params, $search);
}
}
/** /**
* Provides access to user attributes using the accessors. * @param $objectLabel
* @param $params
* @param ModelCriteria $search
* @param array $columns
* @param null $foreignTable
* @param string $foreignKey
* *
* @param array $params * @return string
* @param unknown $smarty
* @return string the value of the requested attribute
* @throws InvalidArgumentException if the object does not have the requested attribute.
*/ */
protected function userDataAccess($objectLabel, $user, $params) protected function dataAccessWithI18n($objectLabel, $params, ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID')
{ {
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr')); $lang = $this->getNormalizedParam($params, array('lang'));
if($lang === null) {
$lang = $this->request->getSession()->getLang()->getId();
}
if (! empty($attribute)) { ModelCriteriaTools::getI18n(
false,
$lang,
$search,
$this->request->getSession()->getLang()->getLocale(),
$columns,
$foreignTable,
$foreignKey,
true
);
if (null != $user) { $data = $search->findOne();
$getter = sprintf("get%s", ucfirst($attribute));
if (method_exists($user, $getter)) { $noGetterData = array();
return $user->$getter(); foreach($columns as $column) {
} $noGetterData[$column] = $data->getVirtualColumn('i18n_' . $column);
}
throw new \InvalidArgumentException(sprintf("%s has no '%s' attribute", $objectLabel, $attribute)); return $this->dataAccess($objectLabel, $params, $data, $noGetterData);
}
} /**
} * @param $objectLabel
* @param $params
* @param $data
* @param array $noGetterData
*
* @return string
* @throws \InvalidArgumentException
*/
protected function dataAccess($objectLabel, $params, $data, $noGetterData = array())
{
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));
if (! empty($attribute)) {
if (null != $data) {
$keyAttribute = strtoupper($attribute);
if(array_key_exists($keyAttribute, $noGetterData)) {
return $noGetterData[$keyAttribute];
}
$getter = sprintf("get%s", ucfirst($attribute));
if (method_exists($data, $getter)) {
$return = $data->$getter();
if($return instanceof \DateTime) {
if (array_key_exists("format", $params)) {
$format = $params["format"];
} else {
$format = DateTimeFormat::getInstance($this->request)->getFormat(array_key_exists("output", $params) ? $params["output"] : null);
}
$return = $return->format($format);
}
return $return;
}
throw new \InvalidArgumentException(sprintf("%s has no '%s' attribute", $objectLabel, $attribute));
}
}
return '';
}
return '';
}
/** /**
* Define the various smarty plugins hendled by this class * Define the various smarty plugins hendled by this class
* *
@@ -104,7 +226,11 @@ class DataAccessFunctions extends AbstractSmartyPlugin
{ {
return array( return array(
new SmartyPluginDescriptor('function', 'admin', $this, 'adminDataAccess'), new SmartyPluginDescriptor('function', 'admin', $this, 'adminDataAccess'),
new SmartyPluginDescriptor('function', 'customer', $this, 'customerDataAccess') new SmartyPluginDescriptor('function', 'customer', $this, 'customerDataAccess'),
new SmartyPluginDescriptor('function', 'product', $this, 'productDataAccess'),
new SmartyPluginDescriptor('function', 'category', $this, 'categoryDataAccess'),
new SmartyPluginDescriptor('function', 'content', $this, 'contentDataAccess'),
new SmartyPluginDescriptor('function', 'folder', $this, 'folderDataAccess'),
); );
} }
} }

View File

@@ -27,6 +27,7 @@ use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Template\Smarty\AbstractSmartyPlugin; use Thelia\Core\Template\Smarty\AbstractSmartyPlugin;
use Thelia\Core\Template\Smarty\Exception\SmartyPluginException; use Thelia\Core\Template\Smarty\Exception\SmartyPluginException;
use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor;
use Thelia\Tools\DateTimeFormat;
/** /**
* *
@@ -79,29 +80,10 @@ class Format extends AbstractSmartyPlugin
return ""; return "";
} }
$format = null;
$output = array_key_exists("output", $params) ? $params["output"] : null;
if (array_key_exists("format", $params)) { if (array_key_exists("format", $params)) {
$format = $params["format"]; $format = $params["format"];
} else { } else {
$session = $this->request->getSession(); $format = DateTimeFormat::getInstance($this->request)->getFormat(array_key_exists("output", $params) ? $params["output"] : null);
$lang = $session->getLang();
if($lang) {
switch ($output) {
case "date" :
$format = $lang->getDateFormat();
break;
case "time" :
$format = $lang->getTimeFormat();
break;
default:
case "datetime" :
$format = $lang->getDateTimeFormat();
break;
}
}
} }
return $date->format($format); return $date->format($format);

View File

@@ -169,7 +169,7 @@ class UrlGenerator extends AbstractSmartyPlugin
protected function getCurrentUrl() protected function getCurrentUrl()
{ {
return URL::getInstance()->retrieveCurrent()->toString(); return URL::getInstance()->retrieveCurrent($this->request)->toString();
} }
protected function getReturnToUrl() protected function getReturnToUrl()

View File

@@ -43,12 +43,31 @@ abstract class BaseDescForm extends BaseForm
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
),
"label" => "Title",
"label_attr" => array(
"for" => "title"
) )
) )
) )
->add("chapo", "text", array()) ->add("chapo", "text", array(
->add("description", "text", array()) "label" => "Summary",
->add("postscriptum", "text", array()) "label_attr" => array(
"for" => "summary"
)
))
->add("description", "text", array(
"label" => "Detailed description",
"label_attr" => array(
"for" => "detailed_description"
)
))
->add("postscriptum", "text", array(
"label" => "Conclusion",
"label_attr" => array(
"for" => "conclusion"
)
))
; ;
} }
} }

View File

@@ -32,6 +32,10 @@ class CategoryCreationForm extends BaseForm
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
),
"label" => "Category title *",
"label_attr" => array(
"for" => "title"
) )
)) ))
->add("parent", "integer", array( ->add("parent", "integer", array(

View File

@@ -40,11 +40,19 @@ class ConfigCreationForm extends BaseForm
$this->formBuilder $this->formBuilder
->add("name", "text", array( ->add("name", "text", array(
"constraints" => $name_constraints "constraints" => $name_constraints,
"label" => "Name *",
"label_attr" => array(
"for" => "name"
)
)) ))
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(
new Constraints\NotBlank() new Constraints\NotBlank()
),
"label" => "Purpose *",
"label_attr" => array(
"for" => "purpose"
) )
)) ))
->add("locale", "hidden", array( ->add("locale", "hidden", array(
@@ -52,9 +60,16 @@ class ConfigCreationForm extends BaseForm
new Constraints\NotBlank() new Constraints\NotBlank()
) )
)) ))
->add("value", "text", array()) ->add("value", "text", array(
"label" => "Value *",
"label_attr" => array(
"for" => "value"
)
))
->add("hidden", "hidden", array()) ->add("hidden", "hidden", array())
->add("secured", "hidden", array()) ->add("secured", "hidden", array(
"label" => "Prevent variable modification or deletion, except for super-admin"
))
; ;
} }

View File

@@ -44,11 +44,22 @@ class ConfigModificationForm extends BaseDescForm
->add("name", "text", array( ->add("name", "text", array(
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
),
"label" => "Name",
"label_attr" => array(
"for" => "name"
)
))
->add("value", "text", array(
"label" => "Value",
"label_attr" => array(
"for" => "value"
) )
)) ))
->add("value", "text", array())
->add("hidden", "hidden", array()) ->add("hidden", "hidden", array())
->add("secured", "hidden", array()) ->add("secured", "hidden", array(
"label" => "Prevent variable modification or deletion, except for super-admin"
))
; ;
} }

View File

@@ -40,11 +40,47 @@ class CurrencyCreationForm extends BaseForm
} }
$this->formBuilder $this->formBuilder
->add("name" , "text" , array("constraints" => array(new NotBlank()))) ->add("name" , "text" , array(
->add("locale" , "text" , array("constraints" => array(new NotBlank()))) "constraints" => array(
->add("symbol" , "text" , array("constraints" => array(new NotBlank()))) new NotBlank()
->add("rate" , "text" , array("constraints" => array(new NotBlank()))) ),
->add("code" , "text" , array("constraints" => $code_constraints)) "label" => "Name *",
"label_attr" => array(
"for" => "name"
))
)
->add("locale" , "text" , array(
"constraints" => array(
new NotBlank()
))
)
->add("symbol" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "Symbol *",
"label_attr" => array(
"for" => "symbol"
))
)
->add("rate" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "Rate from &euro; *",
"label_attr" => array(
"for" => "rate"
))
)
->add("code" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "ISO 4217 code *",
"label_attr" => array(
"for" => "iso_4217_code"
))
)
; ;
} }

View File

@@ -40,11 +40,19 @@ class MessageCreationForm extends BaseForm
$this->formBuilder $this->formBuilder
->add("name", "text", array( ->add("name", "text", array(
"constraints" => $name_constraints "constraints" => $name_constraints,
"label" => "Name *",
"label_attr" => array(
"for" => "name"
)
)) ))
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(
new Constraints\NotBlank() new Constraints\NotBlank()
),
"label" => "Purpose *",
"label_attr" => array(
"for" => "purpose"
) )
)) ))
->add("locale", "hidden", array( ->add("locale", "hidden", array(

View File

@@ -33,13 +33,43 @@ class MessageModificationForm extends BaseForm
{ {
$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("name" , "text" , array("constraints" => array(new NotBlank()))) ->add("name" , "text" , array(
->add("secured" , "text" , array()) "constraints" => array(new NotBlank()),
"label" => "Name *",
"label_attr" => array(
"for" => "name"
)
))
->add("secured" , "text" , array(
"label" => "Prevent mailing template modification or deletion, except for super-admin"
))
->add("locale" , "text" , array()) ->add("locale" , "text" , array())
->add("title" , "text" , array("constraints" => array(new NotBlank()))) ->add("title" , "text" , array(
->add("subject" , "text" , array("constraints" => array(new NotBlank()))) "constraints" => array(new NotBlank()),
->add("html_message" , "text" , array()) "label" => "Title *",
->add("text_message" , "text" , array()) "label_attr" => array(
"for" => "title"
)
))
->add("subject" , "text" , array(
"constraints" => array(new NotBlank()),
"label" => "Message subject *",
"label_attr" => array(
"for" => "subject"
)
))
->add("html_message" , "text" , array(
"label" => "HTML Message",
"label_attr" => array(
"for" => "html_message"
)
))
->add("text_message" , "text" , array(
"label" => "Text Message",
"label_attr" => array(
"for" => "text_message"
)
))
; ;
} }

View File

@@ -20,6 +20,9 @@ class Currency extends BaseCurrency {
{ {
$this->dispatchEvent(TheliaEvents::BEFORE_CREATECURRENCY, new CurrencyEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_CREATECURRENCY, new CurrencyEvent($this));
// Set the current position for the new object
$this->setPosition($this->getNextPosition());
return true; return true;
} }

View File

@@ -113,7 +113,7 @@ class ModelCriteriaTools
$localeSearch = LangQuery::create()->findOneById($requestedLangId); $localeSearch = LangQuery::create()->findOneById($requestedLangId);
if ($localeSearch === null) { if ($localeSearch === null) {
throw new \InvalidArgumentException(sprintf('Incorrect lang argument given in attribute loop: lang ID %d not found', $requestedLangId)); throw new \InvalidArgumentException(sprintf('Incorrect lang argument given : lang ID %d not found', $requestedLangId));
} }
$locale = $localeSearch->getLocale(); $locale = $localeSearch->getLocale();

View File

@@ -44,6 +44,11 @@ trait ModelEventDispatcherTrait {
return $this; return $this;
} }
public function getDispatcher()
{
return $this->dispatcher;
}
protected function dispatchEvent($eventName, ActionEvent $event) protected function dispatchEvent($eventName, ActionEvent $event)
{ {
if (!is_null($this->dispatcher)) { if (!is_null($this->dispatcher)) {

View File

@@ -25,6 +25,7 @@ namespace Thelia\Model\Tools;
use Propel\Runtime\ActiveQuery\PropelQuery; use Propel\Runtime\ActiveQuery\PropelQuery;
use Propel\Runtime\ActiveQuery\Criteria; use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Propel;
trait PositionManagementTrait { trait PositionManagementTrait {
@@ -48,13 +49,15 @@ trait PositionManagementTrait {
/** /**
* Get the position of the next inserted object * Get the position of the next inserted object
*/ */
public function getNextPosition($parent) { public function getNextPosition($parent = null) {
$last = $this->createQuery() $query = $this->createQuery()
->filterByParent($parent)
->orderByPosition(Criteria::DESC) ->orderByPosition(Criteria::DESC)
->limit(1) ->limit(1);
->findOne()
if ($parent !== null) $last->filterByParent($parent);
$last = $query->findOne()
; ;
return $last != null ? $last->getPosition() + 1 : 1; return $last != null ? $last->getPosition() + 1 : 1;
@@ -63,14 +66,14 @@ trait PositionManagementTrait {
/** /**
* Move up a object * Move up a object
*/ */
protected function movePositionUp() { public function movePositionUp() {
$this->movePositionUpOrDown(true); $this->movePositionUpOrDown(true);
} }
/** /**
* Move down a object * Move down a object
*/ */
protected function movePositionDown() { public function movePositionDown() {
$this->movePositionUpOrDown(false); $this->movePositionUpOrDown(false);
} }
@@ -85,8 +88,9 @@ trait PositionManagementTrait {
$my_position = $this->getPosition(); $my_position = $this->getPosition();
// Find object to exchange position with // Find object to exchange position with
$search = $this->createQuery() $search = $this->createQuery();
->filterByParent($this->getParent());
if (method_exists($this, 'getParent')) $search->filterByParent($this->getParent());
// Up or down ? // Up or down ?
if ($up === true) { if ($up === true) {
@@ -103,18 +107,17 @@ trait PositionManagementTrait {
// If we found the proper object, exchange their positions // If we found the proper object, exchange their positions
if ($result) { if ($result) {
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); $cnx = Propel::getWriteConnection($this->getDatabaseName());
$cnx->beginTransaction(); $cnx->beginTransaction();
try { try {
$this $this
->setDispatcher($this->getDispatcher())
->setPosition($result->getPosition()) ->setPosition($result->getPosition())
->save() ->save()
; ;
$result->setPosition($my_position)->save(); $result->setDispatcher($this->getDispatcher())->setPosition($my_position)->save();
$cnx->commit(); $cnx->commit();
} catch (Exception $e) { } catch (Exception $e) {
@@ -123,12 +126,22 @@ trait PositionManagementTrait {
} }
} }
/**
* Simply return the database name, from the constant in the MAP class.
*/
protected function getDatabaseName() {
// Find DATABASE_NAME constant
$mapClassName = self::TABLE_MAP;
return $mapClassName::DATABASE_NAME;
}
/** /**
* Changes object position * Changes object position
* *
* @param newPosition * @param newPosition
*/ */
protected function changeAbsolutePosition($newPosition) public function changeAbsolutePosition($newPosition)
{ {
// The current position // The current position
$current_position = $this->getPosition(); $current_position = $this->getPosition();
@@ -136,7 +149,9 @@ trait PositionManagementTrait {
if ($newPosition != null && $newPosition > 0 && $newPosition != $current_position) { if ($newPosition != null && $newPosition > 0 && $newPosition != $current_position) {
// Find categories to offset // Find categories to offset
$search = $this->createQuery()->filterByParent($this->getParent()); $search = $this->createQuery();
if (method_exists($this, 'getParent')) $search->filterByParent($this->getParent());
if ($newPosition > $current_position) { if ($newPosition > $current_position) {
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position // The new position is after the current position -> we will offset + 1 all categories located between us and the new position
@@ -152,17 +167,16 @@ trait PositionManagementTrait {
$results = $search->find(); $results = $search->find();
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); $cnx = Propel::getWriteConnection($this->getDatabaseName());
$cnx->beginTransaction(); $cnx->beginTransaction();
try { try {
foreach ($results as $result) { foreach ($results as $result) {
$result->setPosition($result->getPosition() + $delta)->save($cnx); $result->setDispatcher($this->getDispatcher())->setPosition($result->getPosition() + $delta)->save($cnx);
} }
$this $this
->setDispatcher($this->getDispatcher())
->setPosition($newPosition) ->setPosition($newPosition)
->save($cnx) ->save($cnx)
; ;

View File

@@ -58,6 +58,8 @@ class RewritingResolver
public function load($rewrittenUrl) public function load($rewrittenUrl)
{ {
$rewrittenUrl = ltrim($rewrittenUrl, '/');
$this->search = $this->rewritingUrlQuery->getResolverSearch($rewrittenUrl); $this->search = $this->rewritingUrlQuery->getResolverSearch($rewrittenUrl);
if($this->search->count() == 0) { if($this->search->count() == 0) {

View File

@@ -66,6 +66,7 @@ class RewritingRetriever
$allParametersWithoutView[$view . '_id'] = $viewId; $allParametersWithoutView[$view . '_id'] = $viewId;
} }
$this->rewrittenUrl = null;
$this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView); $this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
if($this->search !== null) { if($this->search !== null) {
$this->rewrittenUrl = $this->search->getUrl(); $this->rewrittenUrl = $this->search->getUrl();
@@ -93,6 +94,7 @@ class RewritingRetriever
$allParametersWithoutView[$view . '_id'] = $viewId; $allParametersWithoutView[$view . '_id'] = $viewId;
} }
$this->rewrittenUrl = null;
$this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView); $this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
if($this->search !== null) { if($this->search !== null) {
$this->rewrittenUrl = $this->search->getUrl(); $this->rewrittenUrl = $this->search->getUrl();

View File

@@ -37,7 +37,7 @@ use Thelia\Tools\URL;
* *
* @package Thelia\Tests\Action\ImageTest * @package Thelia\Tests\Action\ImageTest
*/ */
class ImageTest extends \PHPUnit_Framework_TestCase class ImageTest extends \Thelia\Tests\TestCaseWithURLToolSetup
{ {
protected $request; protected $request;
@@ -49,10 +49,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase
$dispatcher = $this->getMock("Symfony\Component\EventDispatcher\EventDispatcherInterface"); $dispatcher = $this->getMock("Symfony\Component\EventDispatcher\EventDispatcherInterface");
$url = new URL($container, 'dev');
$container->set("event_dispatcher", $dispatcher); $container->set("event_dispatcher", $dispatcher);
$container->set("thelia.url.manager", $dispatcher);
$request = new Request(); $request = new Request();
$request->setSession($this->session); $request->setSession($this->session);

View File

@@ -47,6 +47,7 @@ class CacheClearTest extends \PHPUnit_Framework_TestCase
$fs = new Filesystem(); $fs = new Filesystem();
$fs->mkdir($this->cache_dir); $fs->mkdir($this->cache_dir);
$fs->mkdir(THELIA_WEB_DIR . "/assets");
} }
public function testCacheClear() public function testCacheClear()

View File

@@ -23,7 +23,7 @@
namespace Thelia\Tests\Controller; namespace Thelia\Tests\Controller;
use Symfony\Component\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Request;
use Thelia\Controller\Front\DefaultController; use Thelia\Controller\Front\DefaultController;
/** /**

View File

@@ -34,7 +34,7 @@ use Thelia\Core\HttpFoundation\Session\Session;
* @author Etienne Roudeix <eroudeix@openstudio.fr> * @author Etienne Roudeix <eroudeix@openstudio.fr>
* *
*/ */
abstract class BaseLoopTestor extends \PHPUnit_Framework_TestCase abstract class BaseLoopTestor extends \Thelia\Tests\TestCaseWithURLToolSetup
{ {
protected $request; protected $request;
protected $dispatcher; protected $dispatcher;

View File

@@ -0,0 +1,64 @@
<?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\Tests;
/**
* This class provides URL Tool class initialisation
*
* @package Thelia\Tests\TestCaseWithURLSetup
*/
class TestCaseWithURLToolSetup extends \PHPUnit_Framework_TestCase {
public function __construct() {
$this->setupURLTool();
}
protected function setupURLTool() {
$container = new \Symfony\Component\DependencyInjection\ContainerBuilder();
$context = new \Symfony\Component\Routing\RequestContext(
'/thelia/index.php',
'GET',
'localhost',
'http',
80,
443,
'/path/to/action'
);
$router = $this->getMockBuilder("Symfony\Component\Routing\Router")
->disableOriginalConstructor()
->getMock();
$router->expects($this->any())
->method('getContext')
->will($this->returnValue($context));
$container->set("router.admin", $router);
new \Thelia\Tools\URL($container);
}
}

View File

@@ -28,10 +28,208 @@ use Thelia\Tools\URL;
/** /**
* *
* @author Etienne Roudeix <eroudeix@openstudio.fr> * @author Etienne Roudeix <eroudeix@openstudio.fr>
* @author Franck Allimant <eroudeix@openstudio.fr>
* *
*/ */
class URLTest extends \PHPUnit_Framework_TestCase class URLTest extends \PHPUnit_Framework_TestCase
{ {
protected $context;
public function setUp()
{
$container = new \Symfony\Component\DependencyInjection\ContainerBuilder();
$router = $this->getMockBuilder("Symfony\Component\Routing\Router")
->disableOriginalConstructor()
->getMock();
$this->context = new \Symfony\Component\Routing\RequestContext(
'/thelia/index.php',
'GET',
'localhost',
'http',
80,
443,
'/path/to/action'
);
$router->expects($this->any())
->method('getContext')
->will($this->returnValue($this->context));
$container->set("router.admin", $router);
new \Thelia\Tools\URL($container);
}
public function testGetIndexPage() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia/index.php', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia/', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/', $url);
}
public function testGetBaseUrl() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/thelia/index.php', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/thelia/', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/', $url);
}
public function testAbsoluteUrl() {
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/path/to/action', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/index.php/path/to/action', $url);
}
public function testAbsoluteUrlOnAbsolutePath() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
}
public function testAbsoluteUrlOnAbsolutePathWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlOnAbsolutePathWithParametersAddParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/index.php/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlPathOnly() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array(), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
}
public function testAbsoluteUrlPathOnlyWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlFromIndexWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/index.php/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlPathOnlyFromIndexWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/?p1=v1&p2=v2', $url);
}
public function testRetrieve() public function testRetrieve()
{ {

View File

@@ -20,62 +20,47 @@
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */ /* */
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Controller\Front;
use Thelia\Core\HttpFoundation\Request; namespace Thelia\Tools;
use Thelia\Exception\UrlRewritingException;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\URL;
class UrlRewritingController extends BaseFrontController use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
class DateTimeFormat
{ {
public function check(Request $request, $rewritten_url) protected $request;
public function __construct(Request $request)
{ {
if(ConfigQuery::isRewritingEnable()) { $this->request = $request;
try {
$rewrittenUrlData = URL::getInstance()->resolve($rewritten_url);
} catch(UrlRewritingException $e) {
switch($e->getCode()) {
case UrlRewritingException::URL_NOT_FOUND :
return $this->pageNotFound();
break;
default:
throw $e;
}
}
/* is the URL redirected ? */
if(null !== $rewrittenUrlData->redirectedToUrl) {
$this->redirect($rewrittenUrlData->redirectedToUrl, 301);
}
/* define GET arguments in request */
if(null !== $rewrittenUrlData->view) {
$request->query->set('view', $rewrittenUrlData->view);
if(null !== $rewrittenUrlData->viewId) {
$request->query->set($rewrittenUrlData->view . '_id', $rewrittenUrlData->viewId);
}
}
if(null !== $rewrittenUrlData->locale) {
$request->query->set('locale', $rewrittenUrlData->locale);
}
foreach($rewrittenUrlData->otherParameters as $parameter => $value) {
$request->query->set($parameter, $value);
}
}
if (! $view = $request->query->get('view')) {
$view = "index";
if ($request->request->has('view')) {
$view = $request->request->get('view');
}
}
$request->attributes->set('_view', $view);
} }
public static function getInstance(Request $request)
{
return new DateTimeFormat($request);
}
public function getFormat($output = null)
{
$lang = $this->request->getSession()->getLang();
$format = null;
if($lang) {
switch ($output) {
case "date" :
$format = $lang->getDateFormat();
break;
case "time" :
$format = $lang->getTimeFormat();
break;
default:
case "datetime" :
$format = $lang->getDateTimeFormat();
break;
}
}
return $format;
}
} }

View File

@@ -27,33 +27,30 @@ use Thelia\Model\ConfigQuery;
use Thelia\Rewriting\RewritingResolver; use Thelia\Rewriting\RewritingResolver;
use Thelia\Rewriting\RewritingRetriever; use Thelia\Rewriting\RewritingRetriever;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Thelia\Core\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RequestContext;
class URL class URL
{ {
protected $resolver = null; protected $resolver = null;
protected $retriever = null; protected $retriever = null;
protected $container; protected $requestContext;
protected $environment;
const PATH_TO_FILE = true; const PATH_TO_FILE = true;
const WITH_INDEX_PAGE = false; const WITH_INDEX_PAGE = false;
private static $instance = null; protected static $instance = null;
public function __construct(ContainerInterface $container, $environment) public function __construct(ContainerInterface $container)
{ {
// Allow singleton style calls once intanciated. // Allow singleton style calls once intanciated.
// For this to work, the URL service has to be instanciated very early. This is done manually // For this to work, the URL service has to be instanciated very early. This is done manually
// in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager'); // in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager');
self::$instance = $this; self::$instance = $this;
$this->container = $container; $this->requestContext = $container->get('router.admin')->getContext();
$this->environment = $environment;
$this->retriever = new RewritingRetriever(); $this->retriever = new RewritingRetriever();
$this->resolver = new RewritingResolver(); $this->resolver = new RewritingResolver();
@@ -79,49 +76,31 @@ class URL
*/ */
public function getBaseUrl() public function getBaseUrl()
{ {
$request = $this->container->get('request'); if ($host = $this->requestContext->getHost()) {
$lang = $request->getSession()->getLang();
// Check if we have a specific URL for each lang. $scheme = $this->requestContext->getScheme();
$one_domain_foreach_lang = ConfigQuery::read("one_domain_foreach_lang", false);
if ($one_domain_foreach_lang == true) { $port = '';
// If it's the case, get the current lang URL
$base_url = $lang->getUrl();
$err_msg_part = 'base_url'; if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) {
} $port = ':'.$this->requestContext->getHttpPort();
else { } elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) {
// Get the base URL $port = ':'.$this->requestContext->getHttpsPort();
$base_url = ConfigQuery::read('base_url', $request->getSchemeAndHttpHost()); }
$err_msg_part = sprintf('base_url for lang %s', $lang->getCode()); $schemeAuthority = "$scheme://$host"."$port";
} }
// Be sure that base-url starts with http, give up if it's not the case. return $schemeAuthority.$this->requestContext->getBaseUrl();
if (substr($base_url, 0, 4) != 'http') {
throw new \InvalidArgumentException(
sprintf("The %s configuration parameter shoud contains the URL of your shop, starting with http or https.", $err_msg_part));
}
// Normalize the base_url
return rtrim($base_url, '/').'/';
} }
/** /**
* @return string the index page, which is basically the base_url in prod environment. * @return string the index page, which is in fact the base URL.
*/ */
public function getIndexPage() public function getIndexPage()
{ {
// Get the base URL // The index page is the base URL :)
$base_url = $this->getBaseUrl(); return $this->getBaseUrl();
// For dev environment, add the proper page.
if ($this->environment == 'dev') {
$base_url .= "index_dev.php";
}
return $base_url;
} }
/** /**
@@ -140,14 +119,16 @@ class URL
// Already absolute ? // Already absolute ?
if (substr($path, 0, 4) != 'http') { if (substr($path, 0, 4) != 'http') {
/** $base_url = $this->getBaseUrl();
* @etienne : can't be done here for it's already done in ::viewUrl / ::adminViewUrl
* @franck : should be done, as absoluteUrl() is sometimes called directly (see UrlGenerator::generateUrlFunction())
*/
$root = $path_only == self::PATH_TO_FILE ? $this->getBaseUrl() : $this->getIndexPage();
// Normalize root path // If only a path is requested, be sure to remove the script name (index.php or index_dev.php), if any.
$base = rtrim($root, '/') . '/' . ltrim($path, '/'); if ($path_only == self::PATH_TO_FILE) {
// As the base_url always ends with '/', if we don't find / at the end, we have a script.
if (substr($base_url, -1) != '/') $base_url = dirname($base_url);
}
// Normalize the given path
$base = rtrim($base_url, '/') . '/' . ltrim($path, '/');
} else } else
$base = $path; $base = $path;
@@ -223,20 +204,20 @@ class URL
public function retrieveCurrent(Request $request) public function retrieveCurrent(Request $request)
{ {
if(ConfigQuery::isRewritingEnable()) { if(ConfigQuery::isRewritingEnable()) {
$view = $request->query->get('view', null); $view = $request->attributes->get('_view', null);
$viewLocale = $request->query->get('locale', null); $viewLocale = $request->query->get('locale', null);
$viewId = $view === null ? null : $request->query->get($view . '_id', null); $viewId = $view === null ? null : $request->query->get($view . '_id', null);
$allOtherParameters = $request->query->all(); $allOtherParameters = $request->query->all();
if($view !== null) { if($view !== null) {
unset($allOtherParameters['view']); unset($allOtherParameters['view']);
if($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
} }
if($viewLocale !== null) { if($viewLocale !== null) {
unset($allOtherParameters['locale']); unset($allOtherParameters['locale']);
} }
if($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
$this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters); $this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters);
} }

View File

@@ -212,9 +212,7 @@
{block name="before-javascript-include"}{/block} {block name="before-javascript-include"}{/block}
{javascripts file='assets/js/jquery.min.js'} <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="{$asset_url}"></script>
{/javascripts}
{block name="after-javascript-include"}{/block} {block name="after-javascript-include"}{/block}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,382 @@
/*! ============================================================
* bootstrapSwitch v1.8 by Larentis Mattia @SpiritualGuru
* http://www.larentis.eu/
*
* Enhanced for radiobuttons by Stein, Peter @BdMdesigN
* http://www.bdmdesign.org/
*
* Project site:
* http://www.larentis.eu/switch/
* ============================================================
* Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
* ============================================================ */
!function ($) {
"use strict";
$.fn['bootstrapSwitch'] = function (method) {
var inputSelector = 'input[type!="hidden"]';
var methods = {
init: function () {
return this.each(function () {
var $element = $(this)
, $div
, $switchLeft
, $switchRight
, $label
, $form = $element.closest('form')
, myClasses = ""
, classes = $element.attr('class')
, color
, moving
, onLabel = "ON"
, offLabel = "OFF"
, icon = false
, textLabel = false;
$.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
if (classes.indexOf(el) >= 0)
myClasses = el;
});
$element.addClass('has-switch');
if ($element.data('on') !== undefined)
color = "switch-" + $element.data('on');
if ($element.data('on-label') !== undefined)
onLabel = $element.data('on-label');
if ($element.data('off-label') !== undefined)
offLabel = $element.data('off-label');
if ($element.data('label-icon') !== undefined)
icon = $element.data('label-icon');
if ($element.data('text-label') !== undefined)
textLabel = $element.data('text-label');
$switchLeft = $('<span>')
.addClass("switch-left")
.addClass(myClasses)
.addClass(color)
.html(onLabel);
color = '';
if ($element.data('off') !== undefined)
color = "switch-" + $element.data('off');
$switchRight = $('<span>')
.addClass("switch-right")
.addClass(myClasses)
.addClass(color)
.html(offLabel);
$label = $('<label>')
.html("&nbsp;")
.addClass(myClasses)
.attr('for', $element.find(inputSelector).attr('id'));
if (icon) {
$label.html('<i class="icon ' + icon + '"></i>');
}
if (textLabel) {
$label.html('' + textLabel + '');
}
$div = $element.find(inputSelector).wrap($('<div>')).parent().data('animated', false);
if ($element.data('animated') !== false)
$div.addClass('switch-animate').data('animated', true);
$div
.append($switchLeft)
.append($label)
.append($switchRight);
$element.find('>div').addClass(
$element.find(inputSelector).is(':checked') ? 'switch-on' : 'switch-off'
);
if ($element.find(inputSelector).is(':disabled'))
$(this).addClass('deactivate');
var changeStatus = function ($this) {
if ($element.parent('label').is('.label-change-switch')) {
} else {
$this.siblings('label').trigger('mousedown').trigger('mouseup').trigger('click');
}
};
$element.on('keydown', function (e) {
if (e.keyCode === 32) {
e.stopImmediatePropagation();
e.preventDefault();
changeStatus($(e.target).find('span:first'));
}
});
$switchLeft.on('click', function (e) {
changeStatus($(this));
});
$switchRight.on('click', function (e) {
changeStatus($(this));
});
$element.find(inputSelector).on('change', function (e, skipOnChange) {
var $this = $(this)
, $element = $this.parent()
, thisState = $this.is(':checked')
, state = $element.is('.switch-off');
e.preventDefault();
$element.css('left', '');
if (state === thisState) {
if (thisState)
$element.removeClass('switch-off').addClass('switch-on');
else $element.removeClass('switch-on').addClass('switch-off');
if ($element.data('animated') !== false)
$element.addClass("switch-animate");
if (typeof skipOnChange === 'boolean' && skipOnChange)
return;
$element.parent().trigger('switch-change', {'el': $this, 'value': thisState})
}
});
$element.find('label').on('mousedown touchstart', function (e) {
var $this = $(this);
moving = false;
e.preventDefault();
e.stopImmediatePropagation();
$this.closest('div').removeClass('switch-animate');
if ($this.closest('.has-switch').is('.deactivate')) {
$this.unbind('click');
} else if ($this.closest('.switch-on').parent().is('.radio-no-uncheck')) {
$this.unbind('click');
} else {
$this.on('mousemove touchmove', function (e) {
var $element = $(this).closest('.make-switch')
, relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - $element.offset().left
, percent = (relativeX / $element.width()) * 100
, left = 25
, right = 75;
moving = true;
if (percent < left)
percent = left;
else if (percent > right)
percent = right;
$element.find('>div').css('left', (percent - right) + "%")
});
$this.on('click touchend', function (e) {
var $this = $(this)
, $myInputBox = $this.siblings('input');
e.stopImmediatePropagation();
e.preventDefault();
$this.unbind('mouseleave');
if (moving)
$myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25));
else
$myInputBox.prop("checked", !$myInputBox.is(":checked"));
moving = false;
$myInputBox.trigger('change');
});
$this.on('mouseleave', function (e) {
var $this = $(this)
, $myInputBox = $this.siblings('input');
e.preventDefault();
e.stopImmediatePropagation();
$this.unbind('mouseleave mousemove');
$this.trigger('mouseup');
$myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25)).trigger('change');
});
$this.on('mouseup', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
$(this).trigger('mouseleave');
});
}
});
if ($form.data('bootstrapSwitch') !== 'injected') {
$form.bind('reset', function () {
setTimeout(function () {
$form.find('.make-switch').each(function () {
var $input = $(this).find(inputSelector);
$input.prop('checked', $input.is(':checked')).trigger('change');
});
}, 1);
});
$form.data('bootstrapSwitch', 'injected');
}
}
);
},
toggleActivation: function () {
var $this = $(this);
$this.toggleClass('deactivate');
$this.find(inputSelector).prop('disabled', $this.is('.deactivate'));
},
isActive: function () {
return !$(this).hasClass('deactivate');
},
setActive: function (active) {
var $this = $(this);
if (active) {
$this.removeClass('deactivate');
$this.find(inputSelector).removeAttr('disabled');
}
else {
$this.addClass('deactivate');
$this.find(inputSelector).attr('disabled', 'disabled');
}
},
toggleState: function (skipOnChange) {
var $input = $(this).find(':checkbox');
$input.prop('checked', !$input.is(':checked')).trigger('change', skipOnChange);
},
toggleRadioState: function (skipOnChange) {
var $radioinput = $(this).find(':radio');
$radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
},
toggleRadioStateAllowUncheck: function (uncheck, skipOnChange) {
var $radioinput = $(this).find(':radio');
if (uncheck) {
$radioinput.not(':checked').trigger('change', skipOnChange);
}
else {
$radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
}
},
setState: function (value, skipOnChange) {
$(this).find(inputSelector).prop('checked', value).trigger('change', skipOnChange);
},
setOnLabel: function (value) {
var $switchLeft = $(this).find(".switch-left");
$switchLeft.html(value);
},
setOffLabel: function (value) {
var $switchRight = $(this).find(".switch-right");
$switchRight.html(value);
},
setOnClass: function (value) {
var $switchLeft = $(this).find(".switch-left");
var color = '';
if (value !== undefined) {
if ($(this).attr('data-on') !== undefined) {
color = "switch-" + $(this).attr('data-on')
}
$switchLeft.removeClass(color);
color = "switch-" + value;
$switchLeft.addClass(color);
}
},
setOffClass: function (value) {
var $switchRight = $(this).find(".switch-right");
var color = '';
if (value !== undefined) {
if ($(this).attr('data-off') !== undefined) {
color = "switch-" + $(this).attr('data-off')
}
$switchRight.removeClass(color);
color = "switch-" + value;
$switchRight.addClass(color);
}
},
setAnimated: function (value) {
var $element = $(this).find(inputSelector).parent();
if (value === undefined) value = false;
$element.data('animated', value);
$element.attr('data-animated', value);
if ($element.data('animated') !== false) {
$element.addClass("switch-animate");
} else {
$element.removeClass("switch-animate");
}
},
setSizeClass: function (value) {
var $element = $(this);
var $switchLeft = $element.find(".switch-left");
var $switchRight = $element.find(".switch-right");
var $label = $element.find("label");
$.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
if (el !== value) {
$switchLeft.removeClass(el);
$switchRight.removeClass(el);
$label.removeClass(el);
} else {
$switchLeft.addClass(el);
$switchRight.addClass(el);
$label.addClass(el);
}
});
},
status: function () {
return $(this).find(inputSelector).is(':checked');
},
destroy: function () {
var $element = $(this)
, $div = $element.find('div')
, $form = $element.closest('form')
, $inputbox;
$div.find(':not(input)').remove();
$inputbox = $div.children();
$inputbox.unwrap().unwrap();
$inputbox.unbind('change');
if ($form) {
$form.unbind('reset');
$form.removeData('bootstrapSwitch');
}
return $inputbox;
}
};
if (methods[method])
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
else if (typeof method === 'object' || !method)
return methods.init.apply(this, arguments);
else
$.error('Method ' + method + ' does not exist!');
};
}(jQuery);
(function ($) {
$(function () {
$('.make-switch')['bootstrapSwitch']();
});
})(jQuery);

View File

@@ -0,0 +1,160 @@
.has-switch {
display: inline-block;
cursor: pointer;
border-radius: @input-border-radius;
border: 1px solid;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
position: relative;
text-align: left;
overflow: hidden;
line-height: 8px;
.user-select(none);
vertical-align: middle;
min-width: 100px;
&.switch-mini {
min-width: 72px;
}
&.switch-mini i.switch-mini-icons {
height: 1.20em;
line-height: 9px;
vertical-align: text-top;
text-align: center;
transform: scale(0.6);
margin-top: -1px;
margin-bottom: -1px;
}
&.switch-small {
min-width: 80px;
}
&.switch-large {
min-width: 120px;
}
&.deactivate {
.opacity(50);
cursor: default !important;
label, span {
cursor: default !important;
}
}
> div {
display: inline-block;
width: 150%;
position: relative;
top: 0;
&.switch-animate {
.transition(left 0.5s);
}
&.switch-off {
left: -50%;
}
&.switch-on {
left: 0%;
}
}
input[type=radio],
input[type=checkbox] {
//debug
display: none;
//position: absolute;
//margin-left: 60%;
//z-index: 123;
}
span, label {
.box-sizing(border-box);
cursor: pointer;
position: relative;
display: inline-block;
height: 100%;
padding-bottom: 4px;
padding-top: 4px;
font-size: 14px;
line-height: 20px;
&.switch-mini {
padding-bottom: 4px;
padding-top: 4px;
font-size: 10px;
line-height: 9px;
}
&.switch-small {
padding-bottom: 3px;
padding-top: 3px;
font-size: 12px;
line-height: 18px;
}
&.switch-large {
padding-bottom: 9px;
padding-top: 9px;
font-size: 16px;
line-height: normal;
}
}
label {
text-align: center;
margin-top: -1px;
margin-bottom: -1px;
z-index: 100;
width: 34%;
border-left: 1px solid @btn-default-border;
border-right: 1px solid @btn-default-border;
.button-variant(@btn-default-color, @btn-default-bg, @btn-default-border);
i {
color: #000;
text-shadow: 0 1px 0 #fff;
line-height: 18px;
pointer-events: none;
}
}
span {
text-align: center;
z-index: 1;
width: 33%;
&.switch-left {
.border-left-radius(@input-border-radius);
}
&.switch-right {
.button-variant(@btn-default-color, @btn-default-bg, @btn-default-border);
.border-right-radius(@input-border-radius);
}
&.switch-primary, &.switch-left {
.button-variant(@btn-primary-color, @btn-primary-bg, @btn-primary-border);
}
&.switch-info {
.button-variant(@btn-info-color, @btn-info-bg, @btn-info-border);
}
&.switch-success {
.button-variant(@btn-success-color, @btn-success-bg, @btn-success-border);
}
&.switch-warning {
.button-variant(@btn-warning-color, @btn-warning-bg, @btn-warning-border);
}
&.switch-danger {
.button-variant(@btn-danger-color, @btn-danger-bg, @btn-danger-border);
}
&.switch-default {
.button-variant(@btn-default-color, @btn-default-bg, @btn-default-border);
}
}
}

View File

@@ -9,6 +9,7 @@
@import "tables.less"; @import "tables.less";
@import "tablesorter.less"; @import "tablesorter.less";
@import "bootstrap-editable.less"; @import "bootstrap-editable.less";
@import "bootstrap-switch.less";
// -- Base styling ------------------------------------------------------------ // -- Base styling ------------------------------------------------------------

View File

@@ -45,3 +45,9 @@
// Try to avoid customizing these :) // Try to avoid customizing these :)
@zindex-dropdown: 1005; @zindex-dropdown: 1005;
// Forms
// -------------------------
@input-border-focus: @link-color;

View File

@@ -4,12 +4,6 @@
{block name="check-permissions"}admin.catalog.view{/block} {block name="check-permissions"}admin.catalog.view{/block}
{block name="after-admin-css"}
{stylesheets file='assets/bootstrap-editable/css/bootstrap-editable.css' filters='cssembed'}
<link rel="stylesheet" href="{$asset_url}">
{/stylesheets}
{/block}
{block name="main-content"} {block name="main-content"}
<div class="catalog"> <div class="catalog">
<div id="wrapper" class="container"> <div id="wrapper" class="container">
@@ -80,7 +74,7 @@
} }
</th> </th>
<th>&nbsp;</th> <th>{intl l='Actions'}</th>
</tr> </tr>
</thead> </thead>
@@ -89,7 +83,7 @@
<tr> <tr>
<td> <td>
i={$ID} {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} i={$ID} {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
<a href="{url path='admin/catalog/category' id="$ID" action='browse'}" title="{intl l='Browse this category'}"><img src="#IMAGE_URL" alt="#TITLE" /></a> <a href="{url path='admin/catalog/category' id="$ID" action='browse'}" title="{intl l='Browse this category'}"><img class="img-thumbnail" src="#IMAGE_URL" alt="#TITLE" /></a>
{/loop} {/loop}
</td> </td>
@@ -103,11 +97,15 @@
<td> <td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.category.edit"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.category.edit"}
<input type="checkbox" data-id="{$ID}" class="categoryVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}> <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} {/loop}
{elseloop rel="can_change"} {elseloop rel="can_change"}
<input type="checkbox" class="disabled" disabled="disabled" {if $VISIBLE == 1}checked="checked"{/if}> <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} {/elseloop}
</td> </td>
@@ -123,15 +121,17 @@
</td> </td>
<td> <td>
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/catalog/category' id="$ID" action='browse'}"><i class="glyphicon glyphicon-folder-open"></i></a> <div class="btn-group">
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/catalog/category' id="$ID" action='browse'}"><i class="glyphicon glyphicon-folder-open"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.category.edit"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.category.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='admin/catalog/category' id="$ID" action='edit'}"><i class="glyphicon glyphicon-edit"></i></a> <a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='admin/catalog/category' id="$ID" action='edit'}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.category.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.category.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> <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} {/loop}
</div>
</td> </td>
</tr> </tr>
{/loop} {/loop}
@@ -235,7 +235,9 @@
{module_include location='product_list_row'} {module_include location='product_list_row'}
<td> <td>
<input type="checkbox" data-id="{$ID}" class="displayToggle" {if $VISIBLE == 1}checked="checked"{/if}> <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>
</td> </td>
<td> <td>
@@ -261,7 +263,7 @@
{elseloop rel="product_list"} {elseloop rel="product_list"}
<thead> <thead>
<tr> <tr>
<td class="message"><div class="alert alert-info">{intl l="This category doesn't have any products. To add a new product, click the + button above."}</div></td> <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>
</tr> </tr>
</thead> </thead>
{/elseloop} {/elseloop}
@@ -278,75 +280,78 @@
{include file="includes/delete-category-dialog.html"} {include file="includes/delete-category-dialog.html"}
{/block} {/block}
{block name="after-javascript-include"} {block name="javascript-initialization"}
{javascripts file='assets/bootstrap-editable/js/bootstrap-editable.js'}
{javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'}
<script src="{$asset_url}"></script> <script src="{$asset_url}"></script>
{/javascripts} {/javascripts}
{/block}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
{block name="javascript-initialization"} <script src="{$asset_url}"></script>
<script> {/javascripts}
$(function() {
<script>
{* display the form creation dialog if it contains errors *} $(function() {
{form name="thelia.admin.category.creation"} {* display the form creation dialog if it contains errors *}
{if #form_error}
$('#add_category_dialog').modal(); {form name="thelia.admin.category.creation"}
{/if} {if #form_error}
{/form} $('#add_category_dialog').modal();
{/if}
{* Always reset create dialog on close *} {/form}
$('#add_category_dialog').on('hidden',function() { {* Always reset create dialog on close *}
// Hide error message
$('#add_category_dialog_error').remove(); $('#add_category_dialog').on('hidden',function() {
// Hide error message
// Clear error status $('#add_category_dialog_error').remove();
$("#add_category_dialog .error").removeClass('error');
// Clear error status
// Empty field values $("#add_category_dialog .error").removeClass('error');
$("#add_category_dialog input[type=text]").val('');
}); // Empty field values
$("#add_category_dialog input[type=text]").val('');
{* Set the proper category ID in the delete confirmation dialog *} });
$(document).on("click", ".category-delete", function () { {* Set the proper category ID in the delete confirmation dialog *}
$('#'+'delete-category-id').val($(this).data('id'));
}); $(document).on("click", ".category-delete", function () {
$('#'+'delete-category-id').val($(this).data('id'));
// Toggle category visibility });
$(".categoryVisibleToggle").click(function() {
$.ajax({ // Toggle category visibility
url : "{url path='admin/catalog/category'}", $(".categoryVisibleToggle").change(function() {
data : { $.ajax({
category_id : $(this).data('id'), url : "{url path='admin/catalog/category'}",
action : 'visibilityToggle' data : {
} category_id : $(this).data('id'),
}); action : 'visibilityToggle'
}); }
});
{* Inline editing of object position using bootstrap-editable *} });
$('.categoryPositionChange').editable({ {* Inline editing of object position using bootstrap-editable *}
type : 'text',
title : '{intl l="Enter new category position"}', $('.categoryPositionChange').editable({
mode : 'popup', type : 'text',
inputclass : 'input-mini', title : '{intl l="Enter new category position"}',
placement : 'left', mode : 'popup',
success : function(response, newValue) { inputclass : 'input-mini',
// The URL template placement : 'left',
var url = "{url path='admin/catalog/category' action='changePosition' category_id='__ID__' position='__POS__'}"; success : function(response, newValue) {
// The URL template
// Perform subtitutions var url = "{url path='admin/catalog/category' action='changePosition' category_id='__ID__' position='__POS__'}";
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue); // Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
// Reload the page .replace('__POS__', newValue);
location.href = url;
} // Reload the page
}); location.href = url;
}
}) });
</script>
});
</script>
{/block} {/block}

View File

@@ -51,8 +51,8 @@
<th> <th>
{admin_sortable_header {admin_sortable_header
current_order=$order current_order=$order
order='alpha' order='name'
reverse_order='alpha_reverse' reverse_order='name_reverse'
path='/admin/configuration/currencies' path='/admin/configuration/currencies'
label="{intl l='Name'}" label="{intl l='Name'}"
} }
@@ -138,7 +138,7 @@
<td class="text-center"> <td class="text-center">
{admin_position_block {admin_position_block
permission="admin.currencies.edit" permission="admin.currencies.edit"
path="/admin/configuration/currencies" path="/admin/configuration/currencies/update-position"
url_parameter="currency_id" url_parameter="currency_id"
in_place_edit_class="currencyPositionChange" in_place_edit_class="currencyPositionChange"
position="$POSITION" position="$POSITION"
@@ -147,7 +147,9 @@
</td> </td>
<td class="text-center"> <td class="text-center">
<input class="change-default" type="radio" name="is_default" value="{$ID}" {if $IS_DEFAULT}checked="checked"{/if}/> <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 class="change-default" type="radio" name="is_default" value="{$ID}" {if $IS_DEFAULT}checked="checked"{/if}/>
</div>
</td> </td>
{module_include location='currencies_table_row'} {module_include location='currencies_table_row'}
@@ -186,6 +188,7 @@
</form> </form>
</div> </div>
</div> </div>
{module_include location='currencies_bottom'} {module_include location='currencies_bottom'}
@@ -216,18 +219,21 @@
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/currencies/update' currency_id='_ID_'}" /> <input type="hidden" name="{$name}" value="{url path='/admin/configuration/currencies/update' currency_id='_ID_'}" />
{/form_field} {/form_field}
{* We do not allow users to create secured currencies from here *}
<div class="modal-body"> <div class="modal-body">
{if $form_error}<div class="alert alert-block alert-error" id="add_currency_dialog_error">{$form_error_message}</div>{/if} {if $form_error}<div class="alert alert-block alert-error" id="add_currency_dialog_error">{$form_error_message}</div>{/if}
{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>{intl l='Name *'}</label>
{loop type="lang" name="default-lang" default_only="1"} {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="{intl l=$TITLE}" /></span>
</div>
<div class="help-block">{intl l="Enter here the currency name in the default language ($TITLE)"}</div>
{* Switch edition to the current locale *} {* Switch edition to the current locale *}
<input type="hidden" name="edit_language_id" value="{$ID}" /> <input type="hidden" name="edit_language_id" value="{$ID}" />
@@ -235,37 +241,29 @@
{form_field form=$form field='locale'} {form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" /> <input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field} {/form_field}
<div class="input-group">
<input type="text" 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="{intl l=$TITLE}" /></span>
</div>
<div class="help-block">{intl l="Enter here the currency name in the default language ($TITLE)"}</div>
{/loop} {/loop}
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='code'} {form_field form=$form field='code'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label">{intl l='ISO 4217 code *'}</label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='ISO 4217 code'}" placeholder="{intl l='Code'}"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='ISO 4217 code'}" placeholder="{intl l='Code'}">
<span class="help-block"><a href="http://fr.wikipedia.org/wiki/ISO_4217" target="_blank">{intl l='More information about ISO 4217'}</a></span> <span class="help-block"><a href="http://fr.wikipedia.org/wiki/ISO_4217" target="_blank">{intl l='More information about ISO 4217'}</a></span>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='symbol'} {form_field form=$form field='symbol'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label">{intl l='Symbol *'}</label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}">
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='rate'} {form_field form=$form field='rate'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label">{intl l='Rate *'}</label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency rate'}" placeholder="{intl l='Rate'}"> <input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency rate'}" placeholder="{intl l='Rate'}">
<span class="help-block">{intl l="The rate from Euro (Price in Euro * rate = Price in this currency)"}</span> <span class="help-block">{intl l="The rate from Euro (Price in Euro * rate = Price in this currency)"}</span>
</div> </div>
{/form_field} {/form_field}
@@ -315,6 +313,10 @@
{block name="javascript-initialization"} {block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'}
<script src="{$asset_url}"></script>
{/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}
@@ -359,7 +361,7 @@
placement : 'left', placement : 'left',
success : function(response, newValue) { success : function(response, newValue) {
// The URL template // The URL template
var url = "{url path='/admin/configuration/currencies/updatePosition' currency_id='__ID__' position='__POS__'}"; var url = "{url path='/admin/configuration/currencies/update-position' currency_id='__ID__' position='__POS__'}";
// Perform subtitutions // Perform subtitutions
url = url.replace('__ID__', $(this).data('id')) url = url.replace('__ID__', $(this).data('id'))
@@ -372,7 +374,7 @@
{* Change default status *} {* Change default status *}
$('.change-default').click(function(ev) { $('.change-default').change(function(ev) {
var url = "{url path='/admin/configuration/currencies/set-default' currency_id='__ID__'}"; var url = "{url path='/admin/configuration/currencies/set-default' currency_id='__ID__'}";
// Perform ID subtitutions // Perform ID subtitutions

View File

@@ -47,26 +47,27 @@
<input type="hidden" name="{$name}" value="{$edit_language_locale}" /> <input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field} {/form_field}
{if $form_error}<div class="alert alert-block alert-error">{$form_error_message}</div>{/if} {if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
<div class="col-md-6"> <div class="col-md-6">
{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>{intl l='Name *'}</label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" 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|htmlspecialchars}" title="{intl l='Currency name'}" placeholder="{intl l='Currency name'}" class="form-control">
<span class="help-block">&nbsp;</span>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='code'} {form_field form=$form field='code'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label> <label for="{$label_attr.for}" class="control-label">
{intl l='ISO 4217 Code *'} {intl l="{$label}"} :
<span class="label-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>
</span>
</label> </label>
<input type="text" 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|htmlspecialchars}" title="{intl l='Currency ISO 4217 Code'}" placeholder="{intl l='Code'}" class="form-control">
<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>
</span>
</div> </div>
{/form_field} {/form_field}
@@ -76,22 +77,21 @@
{form_field form=$form field='symbol'} {form_field form=$form field='symbol'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label> <label for="{$label_attr.for}" class="control-label">
{intl l='Symbol *'} {intl l="{$label}"} :
<span class="label-help-block">The symbol, sur as $, £, &euro;...</span>
</label> </label>
<input type="text" 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|htmlspecialchars}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}" class="form-control">
<span class="help-block">{intl l='The symbol, such as $, £, &euro;...'}</span>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='rate'} {form_field form=$form field='rate'}
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label> <label for="{$label_attr.for}" class="control-label">
{intl l='Rate from &euro; *'} {intl l="{$label}"} :
<span class="label-help-block">The rate from Euro</span> </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" required="required" name="{$name}" value="{$value|htmlspecialchars}" 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">Price in Euro x rate = Price in this currency</span>
</div> </div>
{/form_field} {/form_field}

View File

@@ -15,51 +15,50 @@
<form method="POST" action="{url path='/admin/catalog/category'}" {form_enctype form=$form}> <form method="POST" action="{url path='/admin/catalog/category'}" {form_enctype form=$form}>
{* the action processed by the controller *} {* the action processed by the controller *}
<input type="hidden" name="action" value="create" /> <input type="hidden" name="action" value="create" />
{form_hidden_fields form=$form} {form_hidden_fields form=$form}
{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="{$current_category_id}" />
{/form_field} {/form_field}
{form_field form=$form field='success_url'} {form_field form=$form field='success_url'}
{* on success, redirect to category change page. _ID_ is replaced with the ID of the created category (see Thelia\Action\Category.php) *} {* on success, redirect to category change page. _ID_ is replaced with the ID of the created category (see Thelia\Action\Category.php) *}
<input type="hidden" name="{$name}" value="{url path='admin/catalog/category' id="_ID_" action='edit'}" /> <input type="hidden" name="{$name}" value="{url path='admin/catalog/category' id="_ID_" action='edit'}" />
{/form_field} {/form_field}
<div class="modal-body"> <div class="modal-body">
{if #form_error}<div class="alert alert-block alert-error" id="add_category_dialog_error">#form_error_message</div>{/if} {if #form_error}<div class="alert alert-error" id="add_category_dialog_error">#form_error_message</div>{/if}
<div class="form-group"> {form_field form=$form field='title'}
<label class="control-label"> <div class="form-group {if $error}has-error{/if}">
{intl l='Category Title *'} <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
</label>
{loop type="lang" name="default-lang" default_only="1"} {loop type="lang" name="default-lang" default_only="1"}
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field}
<div class="input-group input-block-level"> <div class="input-group">
{form_field form=$form field='title'} <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Category title'}" placeholder="{intl l='Category title'}" class="form-control">
<span {if $error}class="error"{/if}> <span class="input-group-addon"><img src="{image file="../assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span>
<input type="text" required="required" name="{$name}" value="{$value}" title="{intl l='Category title'}" placeholder="{intl l='Category title'}" class="form-control input-block-level"> </div>
</span>
<div class="help-block">{intl l="Enter here the category title in the default language ($TITLE)"}</div>
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field} {/form_field}
<span class="input-group-addon"><img src="{image file="../assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span>
</div>
<div class="help-block">{intl l="Enter here the category title in the default language ($TITLE)"}</div> {/loop}
{/loop}
</div>
{/form_field}
</div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true">{intl l="Cancel"}</button> <button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="Cancel"}</button>
<button type="submit" class="btn btn-default btn-primary">{intl l="Create this category"}</button> <button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Create this category"}</button>
</div> </div>
</form> </form>

View File

@@ -1,42 +1,48 @@
{* Adding a new Category *} {* Adding a new Category *}
<div class="modal hide fade" id="delete_category_dialog" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="delete_category_dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-header"> <div class="modal-dialog">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <div class="modal-content">
<h3>{intl l="Delete a category"}</h3>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl l="Delete a category"}</h3>
</div>
{form name="thelia.admin.category.deletion"}
<form method="POST" action="{url path='/admin/catalog/category'}" {form_enctype form=$form}>
{* the action processed by the controller *}
<input type="hidden" name="action" value="delete" />
{form_hidden_fields form=$form}
{form_field form=$form field='category_id'}
<input type="hidden" name="{$name}" id="delete-category-id" value="" />
{/form_field}
{form_field form=$form field='success_url'}
{* on success, redirect to catalog. _ID_ is replaced with the ID of the deleted category parent id (see Thelia\Action\Category.php) *}
<input type="hidden" name="{$name}" value="{url path='admin/catalog/category' id="_ID_" action='browse'}" />
{/form_field}
<div class="modal-body">
{if #form_error}<div class="alert alert-block alert-error" id="add_category_dialog_error">#form_error_message</div>{/if}
<p>{intl l="Delete this category and all its contents ?"}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="No"}</button>
<button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Yes"}</button>
</div>
</form>
{/form}
</div>
</div> </div>
{form name="thelia.admin.category.deletion"}
<form method="POST" action="{url path='/admin/catalog/category'}" {form_enctype form=$form}>
{* the action processed by the controller *}
<input type="hidden" name="action" value="delete" />
{form_hidden_fields form=$form}
{form_field form=$form field='category_id'}
<input type="hidden" name="{$name}" id="delete-category-id" value="" />
{/form_field}
{form_field form=$form field='success_url'}
{* on success, redirect to catalog. _ID_ is replaced with the ID of the deleted category parent id (see Thelia\Action\Category.php) *}
<input type="hidden" name="{$name}" value="{url path='admin/catalog/category' id="_ID_" action='browse'}" />
{/form_field}
<div class="modal-body">
{if #form_error}<div class="alert alert-block alert-error" id="add_category_dialog_error">#form_error_message</div>{/if}
<p>{intl l="Delete this category and all its contents ?"}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn" data-dismiss="modal" aria-hidden="true">{intl l="No"}</button>
<button type="submit" class="btn btn-primary">{intl l="Yes"}</button>
</div>
</form>
{/form}
</div> </div>

View File

@@ -1,60 +1,41 @@
{* The standard description fields, used by many Thelia objects *} {* The standard description fields, used by many Thelia objects *}
{form_field form=$form field='title'} {form_field form=$form field='title'}
<div class="control-group"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
{intl l='Title *'} <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}">
</label>
<div class="controls">
<span {if $error}class="error"{/if}>
<input type="text" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="input-block-level" value="{$value|htmlspecialchars}">
</span>
</div>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='chapo'} {form_field form=$form field='chapo'}
<div class="control-group"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l='Summary'} {intl l="{$label}"} :
<span class="label-help-block">{intl l="A short description, used when a summary or an introduction is required"}</span> <span class="label-help-block">{intl l="A short description, used when a summary or an introduction is required"}</span>
</label> </label>
<div class="controls"> <textarea name="{$name}" id="{$label_attr.for}" rows="3" title="{intl l='Short description'}" placeholder="{intl l='Short description'}" class="form-control">{$value|htmlspecialchars}</textarea>
<span {if $error}class="error"{/if}>
<textarea name="{$name}" rows="3" title="{intl l='Short description'}" placeholder="{intl l='Short description'}" class="input-block-level">{$value|htmlspecialchars}</textarea>
</span>
</div>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='description'} {form_field form=$form field='description'}
<div class="control-group"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l='Detailed description'} {intl l="{$label}"} :
<span class="label-help-block">{intl l="The détailed description."}</span> <span class="label-help-block">{intl l="The détailed description."}</span>
</label> </label>
<div class="controls"> <textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea>
<span {if $error}class="error"{/if}>
<textarea name="{$name}" rows="10" class="input-block-level">{$value|htmlspecialchars}</textarea>
</span>
</div>
</div> </div>
{/form_field} {/form_field}
{form_field form=$form field='postscriptum'} {form_field form=$form field='postscriptum'}
<div class="control-group"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l='Conclusion'} {intl l="{$label}"} :
<span class="label-help-block">{intl l="A short post-description information"}</span> <span class="label-help-block">{intl l="A short post-description information"}</span>
</label> </label>
<div class="controls"> <textarea name="{$name}" id="{$label_attr.for}" rows="3" title="{intl l='Short conclusion'}" placeholder="{intl l='Short conclusion'}" class="form-control">{$value|htmlspecialchars}</textarea>
<span {if $error}class="error"{/if}>
<textarea name="{$name}" rows="3" title="{intl l='Short conclusion'}" placeholder="{intl l='Short conclusion'}" class="input-block-level">{$value|htmlspecialchars}</textarea>
</span>
</div>
</div> </div>
{/form_field} {/form_field}

View File

@@ -27,127 +27,85 @@
</div> </div>
<div class="form-container"> <div class="form-container">
<div class="form-horizontal col-md-12"> <div class="col-md-12">
{form name="thelia.admin.message.modification"} {form name="thelia.admin.message.modification"}
<form method="POST" action="{url path='/admin/configuration/messages/save'}" {form_enctype form=$form}> <form method="POST" action="{url path='/admin/configuration/messages/save'}" {form_enctype form=$form}>
<fieldset>
{* Be sure to get the message ID, even if the form could not be validated *}
<input type="hidden" name="message_id" value="{$message_id}" />
{include file="includes/inner-form-toolbar.html"} {* Be sure to get the message ID, even if the form could not be validated *}
<input type="hidden" name="message_id" value="{$message_id}" />
{form_hidden_fields form=$form} {include file="includes/inner-form-toolbar.html"}
{form_field form=$form field='success_url'} {form_hidden_fields form=$form}
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/messages'}" />
{/form_field}
{form_field form=$form field='id'} {form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" /> <input type="hidden" name="{$name}" value="{url path='/admin/configuration/messages'}" />
{/form_field} {/form_field}
{form_field form=$form field='locale'} {form_field form=$form field='id'}
<input type="hidden" name="{$name}" value="{{$edit_language_locale}}" /> <input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" />
{/form_field} {/form_field}
{if #form_error}<div class="alert alert-block alert-error">#form_error_message</div>{/if} {form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{{$edit_language_locale}}" />
{/form_field}
<div class="control-group"> {if #form_error}<div class="alert alert-danger">#form_error_message</div>{/if}
<label class="control-label"> {form_field form=$form field='name'}
{intl l='Name *'} <div class="form-group {if $error}has-error{/if}">
</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">
</div>
{/form_field}
<div class="controls"> {form_field form=$form field='secured'}
{form_field form=$form field='name'} <div class="checkbox {if $error}has-error{/if}">
<span {if $error}class="error"{/if}> <label>
<input type="text" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="input-block-level"> <input type="checkbox" name="{$name}" value="1" {if $value == 1}checked="checked"{/if}>
</span> {intl l="{$label}"}
{/form_field} </label>
</div> </div>
</div> {/form_field}
<div class="control-group"> {form_field form=$form field='title'}
<label class="control-label"> <div class="form-group {if $error}has-error{/if}">
{intl l='Secured'} <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </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}">
</div>
{/form_field}
<div class="controls"> {form_field form=$form field='subject'}
{form_field form=$form field='secured'} <div class="form-group {if $error}has-error{/if}">
<span {if $error}class="error"{/if}> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<label class="checkbox"> <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="checkbox" name="{$name}" value="1" {if $value == 1}checked="checked"{/if}> </div>
{intl l="Prevent mailing template modification or deletion, except for super-admin"} {/form_field}
</label>
</span>
{/form_field}
</div>
</div>
{form_field form=$form field='title'} {form_field form=$form field='html_message'}
<div class="control-group"> <div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">
{intl l='Title *'} {intl l="{$label}"} :
</label> <span class="label-help-block">{intl l="The mailing template in HTML format."}</span>
</label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea>
</div>
{/form_field}
<div class="controls"> {form_field form=$form field='text_message'}
<span {if $error}class="error"{/if}> <div class="form-group {if $error}has-error{/if}">
<input type="text" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="input-block-level" value="{$value|htmlspecialchars}"> <label for="{$label_attr.for}" class="control-label">
</span> {intl l="{$label}"} :
</div> <span class="label-help-block">{intl l="The mailing template in text-only format."}</span>
</div> </label>
{/form_field} <textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea>
</div>
{/form_field}
{form_field form=$form field='subject'} <div class="form-group">
<div class="control-group"> <p>{intl l='Message created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}}</p>
<label class="control-label"> </div>
{intl l='Message subject *'}
</label>
<div class="controls">
<span {if $error}class="error"{/if}>
<input type="text" name="{$name}" required="required" title="{intl l='Subject'}" placeholder="{intl l='Subject'}" class="input-block-level" value="{$value|htmlspecialchars}">
</span>
</div>
</div>
{/form_field}
{form_field form=$form field='html_message'}
<div class="control-group">
<label class="control-label">
{intl l='HTML Message'}
<span class="label-help-block">{intl l="The mailing template in HTML format."}</span>
</label>
<div class="controls">
<span {if $error}class="error"{/if}>
<textarea name="{$name}" rows="10" class="input-block-level">{$value|htmlspecialchars}</textarea>
</span>
</div>
</div>
{/form_field}
{form_field form=$form field='text_message'}
<div class="control-group">
<label class="control-label">
{intl l='Text Message'}
<span class="label-help-block">{intl l="The mailing template in text-only format."}</span>
</label>
<div class="controls">
<span {if $error}class="error"{/if}>
<textarea name="{$name}" rows="10" class="input-block-level">{$value|htmlspecialchars}</textarea>
</span>
</div>
</div>
{/form_field}
<div class="control-group">
<div class="controls">
<p>{intl l='Message 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>
</fieldset>
</form> </form>
{/form} {/form}
</div> </div>

View File

@@ -31,62 +31,65 @@
{/loop} {/loop}
</caption> </caption>
<tr> <thead>
<th>{intl l="Purpose"}</th> <tr>
<th>{intl l="Name"}</th> <th>{intl l="Purpose"}</th>
<th>{intl l="Name"}</th>
{module_include location='messages_table_header'} {module_include location='messages_table_header'}
<th>&nbsp;</th> <th>&nbsp;</th>
</tr> </tr>
</thead>
{loop name="mailing-templates" type="message" secured="*" backend_context="1" lang="$lang_id"} <tbody>
<tr> {loop name="mailing-templates" type="message" secured="*" backend_context="1" lang="$lang_id"}
<tr>
<td>{$TITLE}</td> <td>{$TITLE}</td>
<td> <td>
{if ! $SECURED} {if ! $SECURED}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"}
<a title="{intl l='Change this mailing template'}" href="{url path='/admin/configuration/messages/update' message_id="$ID"}">{$NAME}</a> <a title="{intl l='Change this mailing template'}" href="{url path='/admin/configuration/messages/update' message_id="$ID"}">{$NAME}</a>
{/loop} {/loop}
{elseloop rel="can_change"} {elseloop rel="can_change"}
{$NAME}
{/elseloop}
{else}
{$NAME} {$NAME}
{/elseloop} {/if}
{else} </td>
{$NAME}
{/if}
</td>
{module_include location='messages_table_row'} {module_include location='messages_table_row'}
<td class="actions"> <td class="actions">
{if ! $SECURED} {if ! $SECURED}
<div class="btn-group"> <div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"}
<a class="btn btn-default btn-xs message-change" title="{intl l='Change this mailing template'}" href="{url path='/admin/configuration/messages/update' message_id="$ID"}"><i class="glyphicon glyphicon-edit"></i></a> <a class="btn btn-default btn-xs message-change" title="{intl l='Change this mailing template'}" href="{url path='/admin/configuration/messages/update' message_id="$ID"}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.messages.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.messages.delete"}
<a class="btn btn-default btn-xs message-delete" title="{intl l='Delete this mailing template'}" href="#delete_message_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a> <a class="btn btn-default btn-xs message-delete" title="{intl l='Delete this mailing template'}" href="#delete_message_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop} {/loop}
</div> </div>
{else} {else}
<i title="{intl l='This mailing template could not be changed.'}" class="glyphicon glyphicon-ban-circle"></i> <i title="{intl l='This mailing template could not be changed.'}" class="glyphicon glyphicon-ban-circle"></i>
{/if} {/if}
</td> </td>
</tr> </tr>
{/loop} {/loop}
{elseloop rel="mailing-templates"}
{elseloop rel="mailing-templates"} <tr>
<tr> <td colspan="3">
<td colspan="3"> <div class="alert alert-info">
<div class="alert alert-info"> {intl l="No mailing template has been created yet. Click the + button to create one."}
{intl l="No mailing template has been created yet. Click the + button to create one."} </div>
</div> </td>
</td> </tr>
</tr> {/elseloop}
{/elseloop} </tbody>
</table> </table>
</div> </div>
</form> </form>
@@ -101,110 +104,107 @@
{* Adding a new message *} {* Adding a new message *}
<div class="modal hide fade" id="add_message_dialog" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="add_message_dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-header"> <div class="modal-dialog">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <div class="modal-content">
<h3>{intl l="Create a new mailing template"}</h3>
</div>
{form name="thelia.admin.message.creation"} <div class="modal-header">
<form method="POST" action="{url path='/admin/configuration/messages/create'}" {form_enctype form=$form}> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl l="Create a new mailing template"}</h3>
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
{* on success, redirect to the edition page, _ID_ is replaced with the created message ID, see controller *}
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/messages/update' message_id='_ID_'}" />
{/form_field}
{* We do not allow users to create secured messages from here *}
{form_field form=$form field='secured'}
<input type="hidden" name="{$name}" value="0" />
{/form_field}
<div class="modal-body">
{if #form_error}<div class="alert alert-block alert-error" id="add_message_dialog_error">#form_error_message</div>{/if}
<div class="control-group">
<label class="control-label">
{intl l='Name *'}
</label>
<div class="controls">
{form_field form=$form field='name'}
<span {if $error}class="error"{/if}>
<input type="text" required="required" name="{$name}" value="{$value}" title="{intl l='Mailing template name'}" placeholder="{intl l='Mailing template name'}" class="input-block-level">
</span>
{/form_field}
</div>
</div> </div>
<div class="control-group"> {form name="thelia.admin.message.creation"}
<label class="control-label"> <form method="POST" action="{url path='/admin/configuration/messages/create'}" {form_enctype form=$form}>
{intl l='Purpose *'}
</label>
<div class="controls"> {form_hidden_fields form=$form}
{loop type="lang" name="default-lang" default_only="1"}
{* Switch edition to the current locale *} {form_field form=$form field='success_url'}
<input type="hidden" name="edit_language_id" value="{$ID}" /> {* on success, redirect to the edition page, _ID_ is replaced with the created message ID, see controller *}
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/messages/update' message_id='_ID_'}" />
{/form_field}
{form_field form=$form field='locale'} {* We do not allow users to create secured messages from here *}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field}
<div class="input-group input-block-level"> {form_field form=$form field='secured'}
{form_field form=$form field='title'} <input type="hidden" name="{$name}" value="0" />
<span {if $error}class="error"{/if}> {/form_field}
<input type="text" required="required" name="{$name}" value="{$value}" title="{intl l='Mailing template purpose'}" placeholder="{intl l='Mailing template purpose'}" class="input-block-level">
</span> <div class="modal-body">
{if #form_error}<div class="alert alert-danger" id="add_message_dialog_error">#form_error_message</div>{/if}
{form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<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}" title="{intl l='Mailing template name'}" placeholder="{intl l='Mailing template name'}" class="form-control">
</div>
{/form_field}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
{loop type="lang" name="default-lang" default_only="1"}
{* Switch edition to the current locale *}
<input type="hidden" name="edit_language_id" value="{$ID}" />
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Mailing template purpose'}" placeholder="{intl l='Mailing template purpose'}" class="form-control">
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span>
</div>
<div class="help-block">{intl l="Enter here the mailing template purpose in the default language ($TITLE)"}</div>
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field} {/form_field}
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span> {/loop}
</div>
</div>
{/form_field}
<div class="help-block">{intl l="Enter here the mailing template purpose in the default language ($TITLE)"}</div>
{/loop}
</div> </div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="Cancel"}</button>
<button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Create this mailing template"}</button>
</div>
</form>
{/form}
</div> </div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default btn-primary">{intl l="Create this mailing template"}</button>
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true">{intl l="Cancel"}</button>
</div>
</form>
{/form}
</div> </div>
{* Delete confirmation dialog *} {* Delete confirmation dialog *}
<div class="modal hide fade" id="delete_message_dialog" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="delete_message_dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl l="Delete a mailing template"}</h3> <h3>{intl l="Delete a mailing template"}</h3>
</div>
<div class="modal-body">
<p>{intl l="Do you really want to delete this mailing template ?"}</p>
</div>
<form method="post" action="{url path='/admin/configuration/messages/delete'}">
<input type="hidden" name="message_id" id="message_delete_id" value="" />
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="No"}</button>
<button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Yes"}</button>
</div>
</form>
</div>
</div> </div>
<div class="modal-body">
<p>{intl l="Do you really want to delete this mailing template ?"}</p>
</div>
<form method="post" action="{url path='/admin/configuration/messages/delete'}">
<input type="hidden" name="message_id" id="message_delete_id" value="" />
<div class="modal-footer">
<button type="submit" class="btn btn-default btn-primary">{intl l="Yes"}</button>
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true">{intl l="No"}</button>
</div>
</form>
</div> </div>
{/block} {/block}

View File

@@ -27,7 +27,7 @@
</div> </div>
<div class="form-container"> <div class="form-container">
<div class="form-horizontal col-md-12"> <div class="col-md-12">
{form name="thelia.admin.config.modification"} {form name="thelia.admin.config.modification"}
<form method="POST" action="{url path='/admin/configuration/variables/save'}" {form_enctype form=$form}> <form method="POST" action="{url path='/admin/configuration/variables/save'}" {form_enctype form=$form}>
<fieldset> <fieldset>
@@ -56,53 +56,30 @@
<input type="hidden" name="{$name}" value="{$edit_language_locale}" /> <input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field} {/form_field}
{if #form_error}<div class="alert alert-block alert-error">#form_error_message</div>{/if} {if #form_error}<div class="alert alert-danger">#form_error_message</div>{/if}
<div class="control-group"> {form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<label class="control-label"> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
{intl l='Name *'} <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">
</label>
<div class="controls">
{form_field form=$form field='name'}
<span {if $error}class="error"{/if}>
<input type="text" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="input-block-level">
</span>
{/form_field}
</div>
</div> </div>
{/form_field}
<div class="control-group"> {form_field form=$form field='value'}
<label class="control-label"> <div class="form-group {if $error}has-error{/if}">
{intl l='Value'} <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </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">
<div class="controls">
{form_field form=$form field='value'}
<span {if $error}class="error"{/if}>
<input type="text" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="input-block-level">
</span>
{/form_field}
</div>
</div> </div>
{/form_field}
<div class="control-group"> {form_field form=$form field='secured'}
<label class="control-label"> <div class="checkbox {if $error}has-error{/if}">
{intl l='Secured'} <label>
</label> <input type="checkbox" name="{$name}" value="1" {if $value == 1}checked="checked"{/if}>
{intl l="{$label}"}
<div class="controls"> </label>
{form_field form=$form field='secured'}
<span {if $error}class="error"{/if}>
<label class="checkbox">
<input type="checkbox" name="{$name}" value="1" {if $value == 1}checked="checked"{/if}>
{intl l="Prevent variable modification or deletion, except for super-admin"}
</label>
</span>
{/form_field}
</div>
</div> </div>
{/form_field}
{include file="includes/standard-description-form-fields.html"} {include file="includes/standard-description-form-fields.html"}

View File

@@ -22,99 +22,105 @@
<form action="{url path='/admin/configuration/variables/update-values'}" method="post"> <form action="{url path='/admin/configuration/variables/update-values'}" method="post">
<div class="general-block-decorator"> <div class="general-block-decorator">
<table class="table table-striped table-condensed table-left-aligned"> <table class="table table-striped table-condensed table-left-aligned">
<caption> <caption class="clearfix">
{intl l='Thelia system variables'} {intl l='Thelia system variables'}
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.variables.create"} {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.variables.create"}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new variable'}" href="#add_variable_dialog" data-toggle="modal"> <div class="pull-right">
<span class="glyphicon glyphicon-plus-sign"></span> <a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new variable'}" href="#add_variable_dialog" data-toggle="modal">
</a> <span class="glyphicon glyphicon-plus-sign"></span>
<button class="btn btn-default btn-primary action-btn" title="{intl l='Save chages'}">{intl l='Save changes'} <span class="glyphicon glyphicon-ok"></span></button> </a>
<button class="btn btn-default btn-primary" title="{intl l='Save chages'}"><span class="glyphicon glyphicon-ok"></span> {intl l='Save changes'}</button>
</div>
{/loop} {/loop}
</caption> </caption>
<tr>
<th>
{admin_sortable_header
current_order=$order
order='title'
reverse_order='title_reverse'
path={url path='/admin/configuration/variables'}
label={intl l='Purpose'}
}
</th>
<th> <thead>
{admin_sortable_header <tr>
current_order=$order <th>
order='name' {admin_sortable_header
reverse_order='name_reverse' current_order=$order
path={url path='/admin/configuration/variables'} order='title'
label={intl l='Name'} reverse_order='title_reverse'
} path={url path='/admin/configuration/variables'}
</th> label={intl l='Purpose'}
}
</th>
<th> <th>
{admin_sortable_header {admin_sortable_header
current_order=$order current_order=$order
order='value' order='name'
reverse_order='value_reverse' reverse_order='name_reverse'
path={url path='/admin/configuration/variables'} path={url path='/admin/configuration/variables'}
label={intl l='Value'} label={intl l='Name'}
} }
</th> </th>
{module_include location='variables_table_header'} <th>
{admin_sortable_header
current_order=$order
order='value'
reverse_order='value_reverse'
path={url path='/admin/configuration/variables'}
label={intl l='Value'}
}
</th>
<th>&nbsp;</th> {module_include location='variables_table_header'}
</tr>
{loop name="config" type="config" hidden="0" secured="*" backend_context="1" lang="$lang_id" order="$order"} <th>{intl l='Action'}</th>
<tr> </tr>
</thead>
<tbody>
{loop name="config" type="config" hidden="0" secured="*" backend_context="1" lang="$lang_id" order="$order"}
<tr>
<td>{$TITLE}</td> <td>{$TITLE}</td>
<td> <td>
{if ! $SECURED} {if ! $SECURED}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"}
<a title="{intl l='Change this variable'}" href="{url path='/admin/configuration/variables/update' variable_id="$ID"}">{$NAME}</a> <a title="{intl l='Change this variable'}" href="{url path='/admin/configuration/variables/update' variable_id="$ID"}">{$NAME}</a>
{/loop} {/loop}
{elseloop rel="can_change"} {elseloop rel="can_change"}
{$NAME} {$NAME}
{/elseloop} {/elseloop}
{else} {else}
{$NAME} {$NAME}
{/if} {/if}
</td> </td>
<td> <td>
{if $SECURED} {if $SECURED}
{$VALUE} {$VALUE}
{else} {else}
<input id="cancelable_edit_{$ID}" class="js-edit" 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|htmlspecialchars}" />
{/if} {/if}
</td> </td>
{module_include location='variables_table_row'} {module_include location='variables_table_row'}
<td class="actions"> <td class="actions">
{if ! $SECURED} {if ! $SECURED}
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-default btn-xs cancel-edit" id="cancel_edit_btn_{$ID}" data-id="{$ID}" title="{intl l='Cancel changes and revert to original value'}" href="#"><i class="glyphicon glyphicon-remove"></i></a> <a class="btn btn-default btn-xs cancel-edit" id="cancel_edit_btn_{$ID}" data-id="{$ID}" title="{intl l='Cancel changes and revert to original value'}" href="#"><i class="glyphicon glyphicon-remove"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"}
<a class="btn btn-default btn-xs config-change" title="{intl l='Change this variable'}" href="{url path='/admin/configuration/variables/update' variable_id="$ID"}"><i class="glyphicon glyphicon-edit"></i></a> <a class="btn btn-default btn-xs config-change" title="{intl l='Change this variable'}" href="{url path='/admin/configuration/variables/update' variable_id="$ID"}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop} {/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.variables.delete"} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.variables.delete"}
<a class="btn btn-default btn-xs config-delete" title="{intl l='Delete this variable'}" href="#delete_variable_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a> <a class="btn btn-default btn-xs config-delete" title="{intl l='Delete this variable'}" href="#delete_variable_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop} {/loop}
</div> </div>
{else} {else}
<i title="{intl l='This variable could not be changed.'}" class="glyphicon glyphicon-ban-circle"></i> <i title="{intl l='This variable could not be changed.'}" class="glyphicon glyphicon-ban-circle"></i>
{/if} {/if}
</td> </td>
</tr> </tr>
{/loop} {/loop}
</tbody>
</table> </table>
</div> </div>
</form> </form>
@@ -129,129 +135,115 @@
{* Adding a new variable *} {* Adding a new variable *}
<div class="modal hide fade" id="add_variable_dialog" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="add_variable_dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl l="Create a new variable"}</h3> <h3>{intl l="Create a new variable"}</h3>
</div> </div>
{form name="thelia.admin.config.creation"} {form name="thelia.admin.config.creation"}
<form method="POST" action="{url path='/admin/configuration/variables/create'}" {form_enctype form=$form}> <form method="POST" action="{url path='/admin/configuration/variables/create'}" {form_enctype form=$form}>
{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 variable ID, see controller *} {* on success, redirect to the edition page, _ID_ is replaced with the created variable ID, see controller *}
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/variables/update' variable_id='_ID_'}" /> <input type="hidden" name="{$name}" value="{url path='/admin/configuration/variables/update' variable_id='_ID_'}" />
{/form_field} {/form_field}
{* We do not allow users to create hidden or secured variables from here *} {* We do not allow users to create hidden or secured variables from here *}
{form_field form=$form field='hidden'} {form_field form=$form field='hidden'}
<input type="hidden" name="{$name}" value="0" /> <input type="hidden" name="{$name}" value="0" />
{/form_field} {/form_field}
{form_field form=$form field='secured'} {form_field form=$form field='secured'}
<input type="hidden" name="{$name}" value="0" /> <input type="hidden" name="{$name}" value="0" />
{/form_field} {/form_field}
<div class="modal-body"> <div class="modal-body">
{if #form_error}<div class="alert alert-block alert-error" id="add_variable_dialog_error">#form_error_message</div>{/if} {if #form_error}<div class="alert alert-error" id="add_variable_dialog_error">#form_error_message</div>{/if}
<div class="control-group"> {form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<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}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
</div>
{/form_field}
<label class="control-label"> {form_field form=$form field='value'}
{intl l='Name *'} <div class="form-group {if $error}has-error{/if}">
</label> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<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>
{/form_field}
<div class="controls"> {form_field form=$form field='title'}
{form_field form=$form field='name'} <div class="form-group {if $error}has-error{/if}">
<span {if $error}class="error"{/if}> <label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" required="required" name="{$name}" value="{$value}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="input-block-level">
</span>
{/form_field}
</div>
</div>
<div class="control-group"> {loop type="lang" name="default-lang" default_only="1"}
<label class="control-label"> {* Switch edition to the current locale *}
{intl l='Value'} <input type="hidden" name="edit_language_id" value="{$ID}" />
</label>
<div class="controls"> <div class="input-group">
{form_field form=$form field='value'} <input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Variable purpose'}" placeholder="{intl l='Variable purpose'}" class="form-control">
<span {if $error}class="error"{/if}> <span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span>
<input type="text" name="{$name}" value="{$value}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="input-block-level"> </div>
</span>
{/form_field}
</div>
</div>
<div class="control-group"> <div class="help-block">{intl l="Enter here the variable purpose in the default language ($TITLE)"}</div>
<label class="control-label">
{intl l='Purpose *'}
</label>
<div class="controls"> {form_field form=$form field='locale'}
{loop type="lang" name="default-lang" default_only="1"}
{* Switch edition to the current locale *}
<input type="hidden" name="edit_language_id" value="{$ID}" />
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" /> <input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field} {/form_field}
{/loop}
</div>
{/form_field}
<div class="input-group input-block-level"> </div>
{form_field form=$form field='title'}
<span {if $error}class="error"{/if}>
<input type="text" required="required" name="{$name}" value="{$value}" title="{intl l='Variable purpose'}" placeholder="{intl l='Variable purpose'}" class="input-block-level">
</span>
{/form_field}
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" /></span>
</div>
<div class="help-block">{intl l="Enter here the variable purpose in the default language ($TITLE)"}</div> <div class="modal-footer">
{/loop} <button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="Cancel"}</button>
</div> <button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Create this variable"}</button>
</div> </div>
</div> </form>
{/form}
<div class="modal-footer"> </div>
<button type="submit" class="btn btn-default btn-primary">{intl l="Create this variable"}</button> </div>
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true">{intl l="Cancel"}</button>
</div>
</form>
{/form}
</div> </div>
{* Delete confirmation dialog *} {* Delete confirmation dialog *}
<div class="modal hide fade" id="delete_variable_dialog" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="delete_variable_dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>{intl l="Delete a variable"}</h3> <h3>{intl l="Delete a variable"}</h3>
</div>
<div class="modal-body">
<p>{intl l="Do you really want to delete this variable ?"}</p>
</div>
<form method="post" action="{url path='/admin/configuration/variables/delete'}">
<input type="hidden" name="variable_id" id="variable_delete_id" value="" />
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {intl l="No"}</button>
<button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {intl l="Yes"}</button>
</div>
</form>
</div> </div>
</div>
<div class="modal-body">
<p>{intl l="Do you really want to delete this variable ?"}</p>
</div>
<form method="post" action="{url path='/admin/configuration/variables/delete'}">
<input type="hidden" name="variable_id" id="variable_delete_id" value="" />
<div class="modal-footer">
<button type="submit" class="btn btn-default btn-primary">{intl l="Yes"}</button>
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true">{intl l="No"}</button>
</div>
</form>
</div> </div>
{/block} {/block}

View File

@@ -1,11 +1,5 @@
<h2>ALL ATTRIBUTES</h2> {*loop type="product" name="fsdq"}
{format_date date=$CREATE_DATE}
{/loop*}
<ul> ::{product attr="createdAt" output="time" format='i'};;<br />
{loop name="attr" type="attribute"}
<li>
#TITLE - (#LOOP_COUNT / #LOOP_TOTAL)<br />
created at {format_date date=$CREATE_DATE} - updated at {format_date date=$UPDATE_DATE}
<hr />
</li>
{/loop}
</ul>