diff --git a/composer.phar b/composer.phar new file mode 100755 index 000000000..c076f78da Binary files /dev/null and b/composer.phar differ diff --git a/core/lib/Thelia/Action/Tax.php b/core/lib/Thelia/Action/Tax.php new file mode 100644 index 000000000..c35d87bbe --- /dev/null +++ b/core/lib/Thelia/Action/Tax.php @@ -0,0 +1,104 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Action; + +use Propel\Runtime\ActiveQuery\Criteria; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Core\Event\Tax\TaxEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\Tax as TaxModel; +use Thelia\Model\TaxQuery; + +class Tax extends BaseAction implements EventSubscriberInterface +{ + /** + * @param TaxEvent $event + */ + public function create(TaxEvent $event) + { + $tax = new TaxModel(); + + $tax + ->setDispatcher($this->getDispatcher()) + ->setRequirements($event->getRequirements()) + ->setType($event->getType()) + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + ->setDescription($event->getDescription()) + ; + + $tax->save(); + + $event->setTax($tax); + } + + /** + * @param TaxEvent $event + */ + public function update(TaxEvent $event) + { + if (null !== $tax = TaxQuery::create()->findPk($event->getId())) { + + $tax + ->setDispatcher($this->getDispatcher()) + ->setRequirements($event->getRequirements()) + ->setType($event->getType()) + ->setLocale($event->getLocale()) + ->setTitle($event->getTitle()) + ->setDescription($event->getDescription()) + ; + + $tax->save(); + + $event->setTax($tax); + } + } + + /** + * @param TaxEvent $event + */ + public function delete(TaxEvent $event) + { + if (null !== $tax = TaxQuery::create()->findPk($event->getId())) { + + $tax + ->delete() + ; + + $event->setTax($tax); + } + } + + /** + * {@inheritDoc} + */ + public static function getSubscribedEvents() + { + return array( + TheliaEvents::TAX_CREATE => array("create", 128), + TheliaEvents::TAX_UPDATE => array("update", 128), + TheliaEvents::TAX_DELETE => array("delete", 128), + ); + } +} diff --git a/core/lib/Thelia/Action/TaxRule.php b/core/lib/Thelia/Action/TaxRule.php index f9f9fb412..e6d42976e 100644 --- a/core/lib/Thelia/Action/TaxRule.php +++ b/core/lib/Thelia/Action/TaxRule.php @@ -27,6 +27,7 @@ use Propel\Runtime\ActiveQuery\Criteria; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\Tax\TaxRuleEvent; use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\Map\TaxRuleTableMap; use Thelia\Model\TaxRuleCountry; use Thelia\Model\TaxRuleCountryQuery; use Thelia\Model\TaxRule as TaxRuleModel; @@ -132,6 +133,23 @@ class TaxRule extends BaseAction implements EventSubscriberInterface } } + /** + * @param TaxRuleEvent $event + */ + public function setDefault(TaxRuleEvent $event) + { + if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) { + + TaxRuleQuery::create()->update(array( + "IsDefault" => 0 + )); + + $taxRule->setIsDefault(1)->save(); + + $event->setTaxRule($taxRule); + } + } + /** * {@inheritDoc} */ @@ -142,7 +160,7 @@ class TaxRule extends BaseAction implements EventSubscriberInterface TheliaEvents::TAX_RULE_UPDATE => array("update", 128), TheliaEvents::TAX_RULE_TAXES_UPDATE => array("updateTaxes", 128), TheliaEvents::TAX_RULE_DELETE => array("delete", 128), - + TheliaEvents::TAX_RULE_SET_DEFAULT => array("setDefault", 128), ); } } diff --git a/core/lib/Thelia/Config/Resources/action.xml b/core/lib/Thelia/Config/Resources/action.xml index 9088d1a50..a25f9b630 100755 --- a/core/lib/Thelia/Config/Resources/action.xml +++ b/core/lib/Thelia/Config/Resources/action.xml @@ -111,6 +111,11 @@ + + + + + diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 88675d5b8..baee3b2f4 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -55,6 +55,7 @@
+ @@ -118,6 +119,10 @@ + + + + @@ -125,6 +130,10 @@ + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index a3a350365..7cc0c0f9f 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -4,22 +4,22 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + Thelia\Controller\Admin\AdminController::indexAction - + Thelia\Controller\Admin\SessionController::showLoginAction - + Thelia\Controller\Admin\SessionController::checkLogoutAction - + Thelia\Controller\Admin\SessionController::checkLoginAction @@ -31,7 +31,7 @@ - + Thelia\Controller\Admin\CategoryController::defaultAction @@ -827,7 +827,28 @@ - + + + + Thelia\Controller\Admin\TaxController::updateAction + \d+ + + + + Thelia\Controller\Admin\TaxController::createAction + + + + Thelia\Controller\Admin\TaxController::processUpdateAction + + + + Thelia\Controller\Admin\TaxController::deleteAction + + + + + Thelia\Controller\Admin\TaxRuleController::defaultAction @@ -854,10 +875,15 @@ Thelia\Controller\Admin\TaxRuleController::deleteAction + + Thelia\Controller\Admin\TaxRuleController::setDefaultAction + \d+ + + - + Thelia\Controller\Admin\AdminController::processTemplateAction diff --git a/core/lib/Thelia/Config/Resources/routing/front.xml b/core/lib/Thelia/Config/Resources/routing/front.xml index 53a0408a0..351ba2ab4 100755 --- a/core/lib/Thelia/Config/Resources/routing/front.xml +++ b/core/lib/Thelia/Config/Resources/routing/front.xml @@ -4,56 +4,75 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + Thelia\Controller\Front\DefaultController::noAction index - + + + + Thelia\Controller\Front\DefaultController::noAction + search + + + + Thelia\Controller\Front\DefaultController::noAction + view_all + + + + + Thelia\Controller\Front\CustomerController::createAction + register + + Thelia\Controller\Front\DefaultController::noAction register + + + Thelia\Controller\Front\CustomerController::loginAction + login + Thelia\Controller\Front\DefaultController::noAction login + Thelia\Controller\Front\CustomerController::logoutAction - + + Thelia\Controller\Front\DefaultController::noAction account - - Thelia\Controller\Front\CustomerController::createAction - register + + Thelia\Controller\Front\CustomerController::viewAction + account-update - - + Thelia\Controller\Front\CustomerController::updateAction - - - - Thelia\Controller\Front\CustomerController::loginAction - login + account-update - - Thelia\Controller\Front\DefaultController::noAction - password - - - + Thelia\Controller\Front\CustomerController::newPasswordAction - password + account-password + + + + Thelia\Controller\Front\DefaultController::noAction + account-password diff --git a/core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php b/core/lib/Thelia/Controller/Admin/AdminProfileController.php old mode 100755 new mode 100644 similarity index 77% rename from core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php rename to core/lib/Thelia/Controller/Admin/AdminProfileController.php index 311a83272..91f3f2031 --- a/core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php +++ b/core/lib/Thelia/Controller/Admin/AdminProfileController.php @@ -20,33 +20,20 @@ /* along with this program. If not, see . */ /* */ /*************************************************************************************/ -namespace Thelia\TaxEngine\TaxType; -use Thelia\Type\FloatToFloatArrayType; -use Thelia\Type\ModelValidIdType; +namespace Thelia\Controller\Admin; /** - * - * @author Etienne Roudeix - * + * Class AdminProfileController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud */ -class featureSlicePercentTaxType extends BaseTaxType +class AdminProfileController extends BaseAdminController { - public function pricePercentRetriever() + public function defaultAction() { - + if (null !== $response = $this->checkAuth("admin.admin-profile.view")) return $response; + return $this->render("admin-profiles", array("display_admin_profile" => 20)); } - - public function fixAmountRetriever(\Thelia\Model\Product $product) - { - - } - - public function getRequirementsList() - { - return array( - 'featureId' => new ModelValidIdType('Currency'), - 'slices' => new FloatToFloatArrayType(), - ); - } -} + +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/LanguageController.php b/core/lib/Thelia/Controller/Admin/LanguageController.php new file mode 100644 index 000000000..aa818daad --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/LanguageController.php @@ -0,0 +1,39 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +/** + * Class LanguageController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud + */ +class LanguageController extends BaseAdminController +{ + public function defaultAction() + { + if (null !== $response = $this->checkAuth("admin.configuration.languages.view")) return $response; + return $this->render("languages"); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/MailingSystemController.php b/core/lib/Thelia/Controller/Admin/MailingSystemController.php new file mode 100644 index 000000000..89defe01d --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/MailingSystemController.php @@ -0,0 +1,39 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +/** + * Class MailingSystemController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud + */ +class MailingSystemController extends BaseAdminController +{ + public function defaultAction() + { + if (null !== $response = $this->checkAuth("admin.configuration.mailing-system.view")) return $response; + return $this->render("mailing-system"); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/TaxController.php b/core/lib/Thelia/Controller/Admin/TaxController.php new file mode 100644 index 000000000..fd81e4d6c --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/TaxController.php @@ -0,0 +1,227 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +use Thelia\Core\Event\Tax\TaxEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Form\TaxCreationForm; +use Thelia\Form\TaxModificationForm; +use Thelia\Form\TaxTaxListUpdateForm; +use Thelia\Model\TaxQuery; + +class TaxController extends AbstractCrudController +{ + public function __construct() + { + parent::__construct( + 'tax', + 'manual', + 'order', + + 'admin.configuration.tax.view', + 'admin.configuration.tax.create', + 'admin.configuration.tax.update', + 'admin.configuration.tax.delete', + + TheliaEvents::TAX_CREATE, + TheliaEvents::TAX_UPDATE, + TheliaEvents::TAX_DELETE + ); + } + + protected function getCreationForm() + { + return new TaxCreationForm($this->getRequest()); + } + + protected function getUpdateForm() + { + return new TaxModificationForm($this->getRequest()); + } + + protected function getCreationEvent($formData) + { + $event = new TaxEvent(); + + $event->setLocale($formData['locale']); + $event->setTitle($formData['title']); + $event->setDescription($formData['description']); + $event->setType($formData['type']); + $event->setRequirements($this->getRequirements($formData['type'], $formData)); + + return $event; + } + + protected function getUpdateEvent($formData) + { + $event = new TaxEvent(); + + $event->setLocale($formData['locale']); + $event->setId($formData['id']); + $event->setTitle($formData['title']); + $event->setDescription($formData['description']); + $event->setType($formData['type']); + $event->setRequirements($this->getRequirements($formData['type'], $formData)); + + return $event; + } + + protected function getDeleteEvent() + { + $event = new TaxEvent(); + + $event->setId( + $this->getRequest()->get('tax_id', 0) + ); + + return $event; + } + + protected function eventContainsObject($event) + { + return $event->hasTax(); + } + + protected function hydrateObjectForm($object) + { + $data = array( + 'id' => $object->getId(), + 'locale' => $object->getLocale(), + 'title' => $object->getTitle(), + 'description' => $object->getDescription(), + 'type' => $object->getType(), + ); + + // Setup the object form + return new TaxModificationForm($this->getRequest(), "form", $data); + } + + protected function getObjectFromEvent($event) + { + return $event->hasTax() ? $event->getTax() : null; + } + + protected function getExistingObject() + { + return TaxQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->findOneById($this->getRequest()->get('tax_id')); + } + + protected function getObjectLabel($object) + { + return $object->getTitle(); + } + + protected function getObjectId($object) + { + return $object->getId(); + } + + protected function getViewArguments() + { + return array(); + } + + protected function getRouteArguments($tax_id = null) + { + return array( + 'tax_id' => $tax_id === null ? $this->getRequest()->get('tax_id') : $tax_id, + ); + } + + protected function renderListTemplate($currentOrder) + { + // We always return to the feature edition form + return $this->render( + 'taxes-rules', + array() + ); + } + + protected function renderEditionTemplate() + { + // We always return to the feature edition form + return $this->render('tax-edit', array_merge($this->getViewArguments(), $this->getRouteArguments())); + } + + protected function redirectToEditionTemplate($request = null, $country = null) + { + // We always return to the feature edition form + $this->redirectToRoute( + "admin.configuration.taxes.update", + $this->getViewArguments($country), + $this->getRouteArguments() + ); + } + + /** + * Put in this method post object creation processing if required. + * + * @param TaxEvent $createEvent the create event + * @return Response a response, or null to continue normal processing + */ + protected function performAdditionalCreateAction($createEvent) + { + $this->redirectToRoute( + "admin.configuration.taxes.update", + $this->getViewArguments(), + $this->getRouteArguments($createEvent->getTax()->getId()) + ); + } + + protected function redirectToListTemplate() + { + $this->redirectToRoute( + "admin.configuration.taxes-rules.list" + ); + } + + protected function checkRequirements($formData) + { + $type = $formData['type']; + + + } + + protected function getRequirements($type, $formData) + { + $requirements = array(); + foreach($formData as $data => $value) { + if(!strstr($data, ':')) { + continue; + } + + $couple = explode(':', $data); + + if(count($couple) != 2 || $couple[0] != $type) { + continue; + } + + $requirements[$couple[1]] = $value; + } + + return $requirements; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/TaxRuleController.php b/core/lib/Thelia/Controller/Admin/TaxRuleController.php index cfa5af1ff..fc4a5933a 100644 --- a/core/lib/Thelia/Controller/Admin/TaxRuleController.php +++ b/core/lib/Thelia/Controller/Admin/TaxRuleController.php @@ -236,6 +236,23 @@ class TaxRuleController extends AbstractCrudController return parent::updateAction(); } + public function setDefaultAction() + { + if (null !== $response = $this->checkAuth($this->updatePermissionIdentifier)) return $response; + + $setDefaultEvent = new TaxRuleEvent(); + + $taxRuleId = $this->getRequest()->attributes->get('tax_rule_id'); + + $setDefaultEvent->setId( + $taxRuleId + ); + + $this->dispatch(TheliaEvents::TAX_RULE_SET_DEFAULT, $setDefaultEvent); + + $this->redirectToListTemplate(); + } + public function processUpdateTaxesAction() { // Check current user authorization diff --git a/core/lib/Thelia/Controller/Front/CustomerController.php b/core/lib/Thelia/Controller/Front/CustomerController.php index f322d3fe1..857666a37 100755 --- a/core/lib/Thelia/Controller/Front/CustomerController.php +++ b/core/lib/Thelia/Controller/Front/CustomerController.php @@ -31,10 +31,11 @@ use Thelia\Core\Security\Exception\UsernameNotFoundException; use Thelia\Form\CustomerCreation; use Thelia\Form\CustomerLogin; use Thelia\Form\CustomerLostPasswordForm; -use Thelia\Form\CustomerModification; +use Thelia\Form\CustomerUpdateForm; use Thelia\Form\Exception\FormValidationException; use Thelia\Model\Customer; use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\CustomerQuery; use Thelia\Tools\URL; use Thelia\Log\Tlog; use Thelia\Core\Security\Exception\WrongPasswordException; @@ -128,32 +129,56 @@ class CustomerController extends BaseFrontController } } + protected function getExistingCustomer($customer_id) + { + return CustomerQuery::create() + ->findOneById($customer_id); + } + /** * Update customer data. On success, redirect to success_url if exists. * Otherwise, display the same view again. */ + public function viewAction() + { + $this->checkAuth(); + + $customer = $this->getSecurityContext()->getCustomerUser(); + $data = array( + 'id' => $customer->getId(), + 'title' => $customer->getTitleId(), + 'firstname' => $customer->getFirstName(), + 'lastname' => $customer->getLastName(), + 'email' => $customer->getEmail(), + ); + + $customerUpdateForm = new CustomerUpdateForm($this->getRequest(), 'form', $data); + + // Pass it to the parser + $this->getParserContext()->addForm($customerUpdateForm); + } + public function updateAction() { if ($this->getSecurityContext()->hasCustomerUser()) { $message = false; - $customerModification = new CustomerModification($this->getRequest()); + $customerUpdateForm = new CustomerUpdateForm($this->getRequest()); try { $customer = $this->getSecurityContext()->getCustomerUser(); - $form = $this->validateForm($customerModification, "post"); + $form = $this->validateForm($customerUpdateForm, "post"); $customerChangeEvent = $this->createEventInstance($form->getData()); $customerChangeEvent->setCustomer($customer); - $this->dispatch(TheliaEvents::CUSTOMER_UPDATEACCOUNT, $customerChangeEvent); $this->processLogin($customerChangeEvent->getCustomer()); - $this->redirectSuccess($customerModification); + $this->redirectSuccess($customerUpdateForm); } catch (FormValidationException $e) { $message = sprintf("Please check your input: %s", $e->getMessage()); @@ -164,10 +189,10 @@ class CustomerController extends BaseFrontController if ($message !== false) { Tlog::getInstance()->error(sprintf("Error during customer modification process : %s.", $message)); - $customerModification->setErrorMessage($message); + $customerUpdateForm->setErrorMessage($message); $this->getParserContext() - ->addForm($customerModification) + ->addForm($customerUpdateForm) ->setGeneralError($message) ; } @@ -193,31 +218,33 @@ class CustomerController extends BaseFrontController $form = $this->validateForm($customerLoginForm, "post"); - $authenticator = new CustomerUsernamePasswordFormAuthenticator($request, $customerLoginForm); + // If User is a new customer + if ($form->get('account')->getData() == 0 && !$form->get("email")->getErrors()) { + $this->redirectToRoute("customer.create.view", array("email" => $form->get("email")->getData())); + } else { - $customer = $authenticator->getAuthentifiedUser(); + try { - $this->processLogin($customer); + $authenticator = new CustomerUsernamePasswordFormAuthenticator($request, $customerLoginForm); - $this->redirectSuccess($customerLoginForm); + $customer = $authenticator->getAuthentifiedUser(); - } catch (FormValidationException $e) { + $this->processLogin($customer); - if ($request->request->has("account")) { - $account = $request->request->get("account"); - $form = $customerLoginForm->getForm(); - if ($account == 0 && $form->get("email")->getData() !== null) { - $this->redirectToRoute("customer.create.view", array("email" => $form->get("email")->getData())); + $this->redirectSuccess($customerLoginForm); + + } catch (UsernameNotFoundException $e) { + $message = "Wrong email or password. Please try again"; + } catch (WrongPasswordException $e) { + $message = "Wrong email or password. Please try again"; + } catch (AuthenticationException $e) { + $message = "Wrong email or password. Please try again"; } + } + } catch (FormValidationException $e) { $message = sprintf("Please check your input: %s", $e->getMessage()); - } catch (UsernameNotFoundException $e) { - $message = "Wrong email or password. Please try again"; - } catch (WrongPasswordException $e) { - $message = "Wrong email or password. Please try again"; - } catch (AuthenticationException $e) { - $message = "Wrong email or password. Please try again"; } catch (\Exception $e) { $message = sprintf("Sorry, an error occured: %s", $e->getMessage()); } @@ -265,14 +292,14 @@ class CustomerController extends BaseFrontController $data["title"], $data["firstname"], $data["lastname"], - $data["address1"], - $data["address2"], - $data["address3"], - $data["phone"], - $data["cellphone"], - $data["zipcode"], - $data["city"], - $data["country"], + isset($data["address1"])?$data["address1"]:null, + isset($data["address2"])?$data["address2"]:null, + isset($data["address3"])?$data["address3"]:null, + isset($data["phone"])?$data["phone"]:null, + isset($data["cellphone"])?$data["cellphone"]:null, + isset($data["zipcode"])?$data["zipcode"]:null, + isset($data["city"])?$data["city"]:null, + isset($data["country"])?$data["country"]:null, isset($data["email"])?$data["email"]:null, isset($data["password"]) ? $data["password"]:null, $this->getRequest()->getSession()->getLang()->getId(), diff --git a/core/lib/Thelia/Core/Event/Tax/TaxEvent.php b/core/lib/Thelia/Core/Event/Tax/TaxEvent.php new file mode 100644 index 000000000..2c6636c06 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Tax/TaxEvent.php @@ -0,0 +1,120 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event\Tax; +use Thelia\Core\Event\ActionEvent; +use Thelia\Model\Tax; + +class TaxEvent extends ActionEvent +{ + protected $tax = null; + + protected $locale; + protected $id; + protected $title; + protected $description; + protected $type; + protected $requirements; + + public function __construct(Tax $tax = null) + { + $this->tax = $tax; + } + + public function hasTax() + { + return ! is_null($this->tax); + } + + public function getTax() + { + return $this->tax; + } + + public function setTax(Tax $tax) + { + $this->tax = $tax; + + return $this; + } + + public function setDescription($description) + { + $this->description = $description; + } + + public function getDescription() + { + return $this->description; + } + + public function setId($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + public function setTitle($title) + { + $this->title = $title; + } + + public function getTitle() + { + return $this->title; + } + + public function setLocale($locale) + { + $this->locale = $locale; + } + + public function getLocale() + { + return $this->locale; + } + + public function setType($type) + { + $this->type = $type; + } + + public function getType() + { + return $this->type; + } + + public function setRequirements($requirements) + { + $this->requirements = $requirements; + } + + public function getRequirements() + { + return $this->requirements; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 860b63e27..a28c7ffb7 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -540,6 +540,12 @@ final class TheliaEvents const CHANGE_DEFAULT_CURRENCY = 'action.changeDefaultCurrency'; + // -- Tax management --------------------------------------------- + + const TAX_CREATE = "action.createTax"; + const TAX_UPDATE = "action.updateTax"; + const TAX_DELETE = "action.deleteTax"; + // -- Tax Rules management --------------------------------------------- const TAX_RULE_CREATE = "action.createTaxRule"; diff --git a/core/lib/Thelia/Core/Form/Type/TheliaType.php b/core/lib/Thelia/Core/Form/Type/TheliaType.php new file mode 100644 index 000000000..550760098 --- /dev/null +++ b/core/lib/Thelia/Core/Form/Type/TheliaType.php @@ -0,0 +1,49 @@ +setDefaults(array( + //'instance' => false, + 'type' => false, + 'options' => false, + )); + + $resolver->setAllowedTypes(array( + //'instance' => array('Thelia\Type\TypeInterface'), + )); + + $resolver->setAllowedValues(array( + 'type' => array('text', 'choice'), + )); + } + + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars = array_replace($view->vars, array( + //'instance' => $options['instance'], + 'type' => $options['type'], + 'options' => $options['options'], + )); + } + + public function getParent() + { + return 'text'; + } + + public function getName() + { + return 'thelia_type'; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Template/Element/BaseLoop.php b/core/lib/Thelia/Core/Template/Element/BaseLoop.php index 5ac23142d..7e803c43a 100755 --- a/core/lib/Thelia/Core/Template/Element/BaseLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseLoop.php @@ -254,7 +254,7 @@ abstract class BaseLoop * * @param $pagination * - * @return mixed + * @return LoopResult */ abstract public function exec(&$pagination); diff --git a/core/lib/Thelia/Core/Template/Loop/Cart.php b/core/lib/Thelia/Core/Template/Loop/Cart.php index 5c08b2896..5dc40218b 100755 --- a/core/lib/Thelia/Core/Template/Loop/Cart.php +++ b/core/lib/Thelia/Core/Template/Loop/Cart.php @@ -102,6 +102,7 @@ class Cart extends BaseLoop ->set("TAXED_PRICE", $cartItem->getTaxedPrice($taxCountry)) ->set("PROMO_TAXED_PRICE", $cartItem->getTaxedPromoPrice($taxCountry)) ->set("IS_PROMO", $cartItem->getPromo() === 1 ? 1 : 0); + $loopResultRow->set("PRODUCT_SALE_ELEMENTS_ID", $productSaleElement->getId()); $result->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Loop/CategoryTree.php b/core/lib/Thelia/Core/Template/Loop/CategoryTree.php index 009e2204f..b7c262649 100755 --- a/core/lib/Thelia/Core/Template/Loop/CategoryTree.php +++ b/core/lib/Thelia/Core/Template/Loop/CategoryTree.php @@ -84,10 +84,14 @@ class CategoryTree extends BaseI18nLoop $loopResultRow = new LoopResultRow(); $loopResultRow - ->set("ID", $result->getId())->set("TITLE", $result->getVirtualColumn('i18n_TITLE')) - ->set("PARENT", $result->getParent())->set("URL", $result->getUrl($locale)) - ->set("VISIBLE", $result->getVisible() ? "1" : "0")->set("LEVEL", $level) - ->set('CHILD_COUNT', $result->countChild())->set('PREV_LEVEL', $previousLevel) + ->set("ID", $result->getId()) + ->set("TITLE", $result->getVirtualColumn('i18n_TITLE')) + ->set("PARENT", $result->getParent()) + ->set("URL", $result->getUrl($locale)) + ->set("VISIBLE", $result->getVisible() ? "1" : "0") + ->set("LEVEL", $level) + ->set('CHILD_COUNT', $result->countChild()) + ->set('PREV_LEVEL', $previousLevel) ; $loopResult->addRow($loopResultRow); diff --git a/core/lib/Thelia/Core/Template/Loop/Content.php b/core/lib/Thelia/Core/Template/Loop/Content.php index ce966bf5c..696d8c6cd 100755 --- a/core/lib/Thelia/Core/Template/Loop/Content.php +++ b/core/lib/Thelia/Core/Template/Loop/Content.php @@ -86,6 +86,7 @@ class Content extends BaseI18nLoop */ public function exec(&$pagination) { + $search = ContentQuery::create(); /* manage translations */ @@ -138,27 +139,15 @@ class Content extends BaseI18nLoop $current_folder = $this->getCurrent_folder(); if ($current_folder === true) { - $search->filterByFolder( - FolderQuery::create()->filterByContent( - ContentFolderQuery::create()->filterByContentId( - $this->request->get("content_id"), - Criteria::EQUAL - )->find(), - Criteria::IN - )->find(), - Criteria::IN - ); + $current = ContentQuery::create()->findPk($this->request->get("content_id")); + + $search->filterByFolder($current->getFolders(), Criteria::IN); + } elseif ($current_folder === false) { - $search->filterByFolder( - FolderQuery::create()->filterByContent( - ContentFolderQuery::create()->filterByContentId( - $this->request->get("content_id"), - Criteria::EQUAL - )->find(), - Criteria::IN - )->find(), - Criteria::NOT_IN - ); + + $current = ContentQuery::create()->findPk($this->request->get("content_id")); + + $search->filterByFolder($current->getFolders(), Criteria::NOT_IN); } $visible = $this->getVisible(); diff --git a/core/lib/Thelia/Core/Template/Loop/Product.php b/core/lib/Thelia/Core/Template/Loop/Product.php index f0bb95249..2d6125a37 100755 --- a/core/lib/Thelia/Core/Template/Loop/Product.php +++ b/core/lib/Thelia/Core/Template/Loop/Product.php @@ -87,6 +87,7 @@ class Product extends BaseI18nLoop Argument::createIntTypeArgument('depth', 1), Argument::createBooleanOrBothTypeArgument('visible', 1), Argument::createIntTypeArgument('currency'), + Argument::createAnyTypeArgument('title'), new Argument( 'order', new TypeCollection( @@ -171,6 +172,17 @@ class Product extends BaseI18nLoop $search->filterByRef($ref, Criteria::IN); } + + $title = $this->getTitle(); + + if(!is_null($title)){ + + $search->where(" CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".Criteria::LIKE." ?", "%".$title."%", \PDO::PARAM_STR); + } + + + + $category = $this->getCategory(); $categoryDefault = $this->getCategoryDefault(); @@ -461,7 +473,7 @@ class Product extends BaseI18nLoop $visible = $this->getVisible(); - if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible ? 1 : 0); + if ($visible !== BooleanOrBothType::ANY) $search->filterByVisible($visible ? 1 : 0); $exclude = $this->getExclude(); diff --git a/core/lib/Thelia/Core/Template/Loop/Tax.php b/core/lib/Thelia/Core/Template/Loop/Tax.php index 18fb5e0dc..e97b9c7d5 100644 --- a/core/lib/Thelia/Core/Template/Loop/Tax.php +++ b/core/lib/Thelia/Core/Template/Loop/Tax.php @@ -152,11 +152,13 @@ class Tax extends BaseI18nLoop $loopResultRow = new LoopResultRow($loopResult, $tax, $this->versionable, $this->timestampable, $this->countable); $loopResultRow - ->set("ID" , $tax->getId()) - ->set("IS_TRANSLATED" , $tax->getVirtualColumn('IS_TRANSLATED')) - ->set("LOCALE" , $locale) - ->set("TITLE" , $tax->getVirtualColumn('i18n_TITLE')) - ->set("DESCRIPTION" , $tax->getVirtualColumn('i18n_DESCRIPTION')) + ->set("ID" , $tax->getId()) + ->set("TYPE" , $tax->getType()) + ->set("REQUIREMENTS" , $tax->getRequirements()) + ->set("IS_TRANSLATED" , $tax->getVirtualColumn('IS_TRANSLATED')) + ->set("LOCALE" , $locale) + ->set("TITLE" , $tax->getVirtualColumn('i18n_TITLE')) + ->set("DESCRIPTION" , $tax->getVirtualColumn('i18n_DESCRIPTION')) ; $loopResult->addRow($loopResultRow); diff --git a/core/lib/Thelia/Core/Template/Loop/TaxRuleCountry.php b/core/lib/Thelia/Core/Template/Loop/TaxRuleCountry.php index c4c165192..ee20a3d20 100644 --- a/core/lib/Thelia/Core/Template/Loop/TaxRuleCountry.php +++ b/core/lib/Thelia/Core/Template/Loop/TaxRuleCountry.php @@ -32,9 +32,12 @@ use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Loop\Argument\ArgumentCollection; use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Model\CountryQuery; use Thelia\Model\Map\CountryTableMap; use Thelia\Model\Map\TaxRuleCountryTableMap; use Thelia\Model\Map\TaxTableMap; +use Thelia\Type\TypeCollection; +use Thelia\Type; use Thelia\Model\TaxRuleCountryQuery; /** @@ -56,8 +59,14 @@ class TaxRuleCountry extends BaseI18nLoop protected function getArgDefinitions() { return new ArgumentCollection( - Argument::createIntTypeArgument('country'), - Argument::createIntListTypeArgument('taxes'), + Argument::createIntTypeArgument('country', null, true), + new Argument( + 'ask', + new TypeCollection( + new Type\EnumType(array('taxes', 'countries')) + ), + 'taxes' + ), Argument::createIntTypeArgument('tax_rule', null, true) ); } @@ -71,40 +80,54 @@ class TaxRuleCountry extends BaseI18nLoop { $search = TaxRuleCountryQuery::create(); + $ask = $this->getAsk(); + $country = $this->getCountry(); - $taxes = $this->getTaxes(); + $taxRule = $this->getTax_rule(); - if ((null === $country && null === $taxes)) { - throw new \InvalidArgumentException('You must provide either `country` or `taxes` parameter in tax-rule-country loop'); - } + if($ask === 'countries') { + $taxCountForOriginCountry = TaxRuleCountryQuery::create()->filterByCountryId($country)->count(); - if ((null === $country && null !== $taxes)) { - throw new \InvalidArgumentException('You must provide `country` parameter with `taxes` parameter in tax-rule-country loop'); - } + if($taxCountForOriginCountry > 0) { + $search->groupByCountryId(); - if (null !== $taxes) { - $search->groupByCountryId(); + $originalCountryJoin = new Join(); + $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', 'origin'); + $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', 'origin'); + $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', null, TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', 'origin'); + $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', 'origin', Criteria::NOT_EQUAL); + $originalCountryJoin->setJoinType(Criteria::LEFT_JOIN); - $originalCountryJoin = new Join(); - $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_RULE_ID', 'origin'); - $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'TAX_ID', 'origin'); - $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', null, TaxRuleCountryTableMap::TABLE_NAME, 'POSITION', 'origin'); - $originalCountryJoin->addExplicitCondition(TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', null, TaxRuleCountryTableMap::TABLE_NAME, 'COUNTRY_ID', 'origin', Criteria::NOT_EQUAL); - $originalCountryJoin->setJoinType(Criteria::LEFT_JOIN); + $search->addJoinObject($originalCountryJoin, 's_to_o'); + $search->where('`origin`.`COUNTRY_ID`' . Criteria::EQUAL . '?', $country, \PDO::PARAM_INT); - $search->addJoinObject($originalCountryJoin, 's_to_o'); - $search->where('`origin`.`COUNTRY_ID`' . Criteria::EQUAL . '?', $country, \PDO::PARAM_INT); + $search->having('COUNT(*)=?', $taxCountForOriginCountry, \PDO::PARAM_INT); - $search->having('COUNT(*)=?', count($taxes), \PDO::PARAM_INT); + $search->filterByTaxRuleId($taxRule); - /* manage tax translation */ - $this->configureI18nProcessing( - $search, - array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), - CountryTableMap::TABLE_NAME, - 'COUNTRY_ID' - ); - } elseif (null !== $country) { + /* manage tax translation */ + $this->configureI18nProcessing( + $search, + array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), + CountryTableMap::TABLE_NAME, + 'COUNTRY_ID' + ); + + $search->addAscendingOrderByColumn('`' . CountryTableMap::TABLE_NAME . '_i18n_TITLE`'); + } else { + $search = CountryQuery::create() + ->joinTaxRuleCountry('trc', Criteria::LEFT_JOIN); + + /* manage tax translation */ + $this->configureI18nProcessing( + $search + ); + + $search->where('ISNULL(`trc`.`COUNTRY_ID`)'); + + $search->addAscendingOrderByColumn('i18n_TITLE'); + } + } elseif($ask === 'taxes') { $search->filterByCountryId($country); /* manage tax translation */ @@ -114,13 +137,11 @@ class TaxRuleCountry extends BaseI18nLoop TaxTableMap::TABLE_NAME, 'TAX_ID' ); + + $search->filterByTaxRuleId($taxRule); + $search->orderByPosition(Criteria::ASC); } - $taxRule = $this->getTax_rule(); - $search->filterByTaxRuleId($taxRule); - - $search->orderByPosition(Criteria::ASC); - /* perform search */ $taxRuleCountries = $this->search($search, $pagination); @@ -130,16 +151,23 @@ class TaxRuleCountry extends BaseI18nLoop $loopResultRow = new LoopResultRow($loopResult, $taxRuleCountry, $this->versionable, $this->timestampable, $this->countable); - if (null !== $taxes) { - $loopResultRow - ->set("TAX_RULE" , $taxRuleCountry->getTaxRuleId()) - ->set("COUNTRY" , $taxRuleCountry->getCountryId()) - ->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_TITLE')) - ->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_CHAPO')) - ->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_DESCRIPTION')) - ->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM')) - ; - } elseif (null !== $country) { + if($ask === 'countries') { + if($taxCountForOriginCountry > 0) { + $loopResultRow + ->set("COUNTRY" , $taxRuleCountry->getCountryId()) + ->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_TITLE')) + ->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_CHAPO')) + ->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_DESCRIPTION')) + ->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn(CountryTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM')); + } else { + $loopResultRow + ->set("COUNTRY" , $taxRuleCountry->getId()) + ->set("COUNTRY_TITLE" , $taxRuleCountry->getVirtualColumn('i18n_TITLE')) + ->set("COUNTRY_CHAPO" , $taxRuleCountry->getVirtualColumn('i18n_CHAPO')) + ->set("COUNTRY_DESCRIPTION" , $taxRuleCountry->getVirtualColumn('i18n_DESCRIPTION')) + ->set("COUNTRY_POSTSCRIPTUM" , $taxRuleCountry->getVirtualColumn('i18n_POSTSCRIPTUM')); + } + } elseif($ask === 'taxes') { $loopResultRow ->set("TAX_RULE" , $taxRuleCountry->getTaxRuleId()) ->set("COUNTRY" , $taxRuleCountry->getCountryId()) @@ -150,6 +178,8 @@ class TaxRuleCountry extends BaseI18nLoop ; } + + $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php index b86f160dc..3727ed6c5 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php @@ -22,7 +22,11 @@ /*************************************************************************************/ namespace Thelia\Core\Template\Smarty\Plugins; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; +use Symfony\Component\Form\Extension\Core\View\ChoiceView; use Symfony\Component\Form\FormView; +use Thelia\Core\Form\Type\TheliaType; use Thelia\Form\BaseForm; use Thelia\Core\Template\Element\Exception\ElementNotFoundException; use Symfony\Component\HttpFoundation\Request; @@ -56,6 +60,8 @@ use Thelia\Core\Template\ParserContext; */ class Form extends AbstractSmartyPlugin { + static private $taggedFieldsStack = null; + static private $taggedFieldsStackPosition = null; protected $request; protected $parserContext; @@ -118,14 +124,17 @@ class Form extends AbstractSmartyPlugin $template->assign("value", $fieldValue); - // If Checkbox input type - if ($fieldVars['checked'] !== null) { - $this->renderFormFieldCheckBox($template, $formFieldView['checked']); - } + $template->assign("checked", isset($fieldVars['checked']) ? $fieldVars['checked'] : false); + + + //data + $template->assign("data", $fieldVars['data']); $template->assign("label", $fieldVars["label"]); $template->assign("label_attr", $fieldVars["label_attr"]); + $template->assign('required', isset($fieldVars['required']) ? $fieldVars['required'] : false); + $errors = $fieldVars["errors"]; $template->assign("error", empty($errors) ? false : true); @@ -141,20 +150,59 @@ class Form extends AbstractSmartyPlugin } $template->assign("attr", implode(" ", $attr)); + $template->assign("attr_list", $fieldVars["attr"]); + } + + protected function assignFormTypeValues($template, $formFieldConfig, $formFieldView) + { + $formFieldType = $formFieldConfig->getType()->getInnerType(); + + /* access to choices */ + if($formFieldType instanceof ChoiceType) { + $template->assign("choices", $formFieldView->vars['choices']); + } + + /* access to collections */ + if($formFieldType instanceof CollectionType) { + if( true === $formFieldConfig->getOption('prototype') ) { + + } else { + /* access to choices */ + if (isset($formFieldView->vars['choices'])) { + $template->assign("choices", $formFieldView->vars['choices']); + + } + } + } + + /* access to thelia type */ + if($formFieldType instanceof TheliaType) { + $template->assign("formType", $formFieldView->vars['type']); + + + switch($formFieldView->vars['type']) { + case "choice": + if(!isset($formFieldView->vars['options']['choices']) || !is_array($formFieldView->vars['options']['choices'])) { + //throw new + } + $choices = array(); + foreach($formFieldView->vars['options']['choices'] as $value => $choice) { + $choices[] = new ChoiceView($value, $value, $choice); + } + $template->assign("choices", $choices); + break; + } + } } public function renderFormField($params, $content, \Smarty_Internal_Template $template, &$repeat) { - if ($repeat) { + if ($repeat) { - $formFieldView = $this->getFormFieldView($params); + $formFieldView = $this->getFormFieldView($params); + $formFieldConfig = $this->getFormFieldConfig($params); - $template->assign("options", $formFieldView->vars); - - /* access to choices */ - if (isset($formFieldView->vars['choices'])) { - $template->assign("choices", $formFieldView->vars['choices']); - } + $this->assignFormTypeValues($template, $formFieldConfig, $formFieldView); $value = $formFieldView->vars["value"]; /* FIXME: doesnt work. We got "This form should not contain extra fields." error. @@ -185,6 +233,38 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar } } + public function renderTaggedFormFields($params, $content, \Smarty_Internal_Template $template, &$repeat) + { + if(null === $content) { + self::$taggedFieldsStack = $this->getFormFieldsFromTag($params); + self::$taggedFieldsStackPosition = 0; + } else { + self::$taggedFieldsStackPosition++; + } + + if(isset(self::$taggedFieldsStack[self::$taggedFieldsStackPosition])) { + $this->assignFieldValues( + $template, + self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars["full_name"], + self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars["value"], + self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->vars + ); + + $this->assignFormTypeValues($template, self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['config'], self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']); + + self::$taggedFieldsStack[self::$taggedFieldsStackPosition]['view']->setRendered(); + + $repeat = true; + } + + if (! $repeat) { + self::$taggedFieldsStack = null; + self::$taggedFieldsStackPosition = null; + } + + return $content; + } + public function renderHiddenFormField($params, \Smarty_Internal_Template $template) { $attrFormat = '%s="%s"'; @@ -266,6 +346,48 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar return $instance->getView()[$fieldName]; } + protected function getFormFieldsFromTag($params) + { + $instance = $this->getInstanceFromParams($params); + + $tag = $this->getParam($params, 'tag'); + + if (null == $tag) + throw new \InvalidArgumentException("'tag' parameter is missing"); + + $viewList = array(); + foreach($instance->getView() as $view) { + if(isset($view->vars['attr']['tag']) && $tag == $view->vars['attr']['tag']) { + $fieldData = $instance->getForm()->all()[$view->vars['name']]; + $viewList[] = array( + 'view' => $view, + 'config' => $fieldData->getConfig(), + ); + } + } + + return $viewList; + } + + protected function getFormFieldConfig($params) + { + $instance = $this->getInstanceFromParams($params); + + $fieldName = $this->getParam($params, 'field'); + + if (null == $fieldName) { + throw new \InvalidArgumentException("'field' parameter is missing"); + } + + $fieldData = $instance->getForm()->all()[$fieldName]; + + if (empty( $fieldData )) { + throw new \InvalidArgumentException(sprintf("Field name '%s' not found in form %s children", $fieldName, $instance->getName())); + } + + return $fieldData->getConfig(); + } + protected function getInstanceFromParams($params) { $instance = $this->getParam($params, 'form'); @@ -304,22 +426,10 @@ $this->assignFieldValues($template, $formFieldView->vars["full_name"], $fieldVar return array( new SmartyPluginDescriptor("block", "form", $this, "generateForm"), new SmartyPluginDescriptor("block", "form_field", $this, "renderFormField"), + new SmartyPluginDescriptor("block", "form_tagged_fields", $this, "renderTaggedFormFields"), new SmartyPluginDescriptor("function", "form_hidden_fields", $this, "renderHiddenFormField"), new SmartyPluginDescriptor("function", "form_enctype", $this, "formEnctype"), new SmartyPluginDescriptor("block", "form_error", $this, "formError") ); } - - /** - * @param \Smarty_Internal_Template $template - * @param $formFieldView - */ - public function renderFormFieldCheckBox(\Smarty_Internal_Template $template, $isChecked) - { - $template->assign("value", 0); - if ($isChecked) { - $template->assign("value", 1); - } - $template->assign("value", $isChecked); - } } diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index a076c808a..f7b6fc559 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -300,7 +300,7 @@ class TheliaLoop extends AbstractSmartyPlugin /** * @param $smartyParams * - * @return object + * @return BaseLoop * @throws \Thelia\Core\Template\Element\Exception\InvalidElementException * @throws \Thelia\Core\Template\Element\Exception\ElementNotFoundException */ diff --git a/core/lib/Thelia/Form/AdminProfileCreationForm.php b/core/lib/Thelia/Form/AdminProfileCreationForm.php new file mode 100644 index 000000000..34ce7556b --- /dev/null +++ b/core/lib/Thelia/Form/AdminProfileCreationForm.php @@ -0,0 +1,65 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class AdminProfileCreationForm extends BaseForm +{ + protected function buildForm() + { + $this->formBuilder + ->add("wording" , "text" , array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Wording *"), + "label_attr" => array( + "for" => "wording" + )) + ) + ->add("name" , "text" , array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Name *"), + "label_attr" => array( + "for" => "name" + )) + ) + ->add("description" , "text" , array( + "label" => Translator::getInstance()->trans("Description"), + "label_attr" => array( + "for" => "description" + )) + ) + ; + } + + public function getName() + { + return "thelia_admin_profile_creation"; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Form/CustomerCreation.php b/core/lib/Thelia/Form/CustomerCreation.php index cc74585e7..d728a515d 100755 --- a/core/lib/Thelia/Form/CustomerCreation.php +++ b/core/lib/Thelia/Form/CustomerCreation.php @@ -40,6 +40,16 @@ class CustomerCreation extends BaseForm { $this->formBuilder ->add("auto_login", "integer") + // Personal Informations + ->add("title", "text", array( + "constraints" => array( + new Constraints\NotBlank() + ), + "label" => Translator::getInstance()->trans("Title"), + "label_attr" => array( + "for" => "title" + ) + )) ->add("firstname", "text", array( "constraints" => array( new Constraints\NotBlank() @@ -58,84 +68,6 @@ class CustomerCreation extends BaseForm "for" => "lastname" ) )) - ->add("address1", "text", array( - "constraints" => array( - new Constraints\NotBlank() - ), - "label_attr" => array( - "for" => "address" - ), - "label" => Translator::getInstance()->trans("Street Address"), - "label_attr" => array( - "for" => "address1" - ) - )) - ->add("address2", "text", array( - "label" => Translator::getInstance()->trans("Address Line 2"), - "label_attr" => array( - "for" => "address2" - ) - )) - ->add("address3", "text", array( - "label" => Translator::getInstance()->trans("Address Line 3"), - "label_attr" => array( - "for" => "address3" - ) - )) - ->add("company", "text", array( - "label" => Translator::getInstance()->trans("Company Name"), - "label_attr" => array( - "for" => "company" - ) - )) - ->add("phone", "text", array( - "label" => Translator::getInstance()->trans("Phone"), - "label_attr" => array( - "for" => "phone" - ) - )) - ->add("cellphone", "text", array( - "label" => Translator::getInstance()->trans("Cellphone"), - "label_attr" => array( - "for" => "cellphone" - ) - )) - ->add("zipcode", "text", array( - "constraints" => array( - new Constraints\NotBlank() - ), - "label" => Translator::getInstance()->trans("Zip code"), - "label_attr" => array( - "for" => "zipcode" - ) - )) - ->add("city", "text", array( - "constraints" => array( - new Constraints\NotBlank() - ), - "label" => Translator::getInstance()->trans("City"), - "label_attr" => array( - "for" => "city" - ) - )) - ->add("country", "text", array( - "constraints" => array( - new Constraints\NotBlank() - ), - "label" => Translator::getInstance()->trans("Country"), - "label_attr" => array( - "for" => "country" - ) - )) - ->add("title", "text", array( - "constraints" => array( - new Constraints\NotBlank() - ), - "label" => Translator::getInstance()->trans("Title"), - "label_attr" => array( - "for" => "title" - ) - )) ->add("email", "email", array( "constraints" => array( new Constraints\NotBlank(), @@ -143,7 +75,7 @@ class CustomerCreation extends BaseForm new Constraints\Callback(array( "methods" => array( array($this, - "verifyExistingEmail") + "verifyExistingEmail") ) )) ), @@ -163,6 +95,79 @@ class CustomerCreation extends BaseForm ), "label" => "email confirmation" ))*/ + ->add("phone", "text", array( + "label" => Translator::getInstance()->trans("Phone"), + "label_attr" => array( + "for" => "phone" + ), + "required" => false + )) + ->add("cellphone", "text", array( + "label" => Translator::getInstance()->trans("Cellphone"), + "label_attr" => array( + "for" => "cellphone" + ), + "required" => false + )) + // Delivery Informations + ->add("company", "text", array( + "label" => Translator::getInstance()->trans("Company Name"), + "label_attr" => array( + "for" => "company" + ), + "required" => false + )) + ->add("address1", "text", array( + "constraints" => array( + new Constraints\NotBlank() + ), + "label" => Translator::getInstance()->trans("Street Address"), + "label_attr" => array( + "for" => "address1" + ) + )) + ->add("address2", "text", array( + "label" => Translator::getInstance()->trans("Address Line 2"), + "label_attr" => array( + "for" => "address2" + ), + "required" => false + )) + ->add("address3", "text", array( + "label" => Translator::getInstance()->trans("Address Line 3"), + "label_attr" => array( + "for" => "address3" + ), + "required" => false + )) + ->add("city", "text", array( + "constraints" => array( + new Constraints\NotBlank() + ), + "label" => Translator::getInstance()->trans("City"), + "label_attr" => array( + "for" => "city" + ) + )) + ->add("zipcode", "text", array( + "constraints" => array( + new Constraints\NotBlank() + ), + "label" => Translator::getInstance()->trans("Zip code"), + "label_attr" => array( + "for" => "zipcode" + ) + )) + ->add("country", "text", array( + "constraints" => array( + new Constraints\NotBlank() + ), + "label" => Translator::getInstance()->trans("Country"), + "label_attr" => array( + "for" => "country" + ) + )) + // Login Information ->add("password", "password", array( "constraints" => array( new Constraints\NotBlank(), @@ -186,8 +191,14 @@ class CustomerCreation extends BaseForm "for" => "password_confirmation" ) )) - - ; + ->add("agreed", "checkbox", array( + "constraints" => array( + new Constraints\True(array("message" => "Please accept the Terms and conditions in order to register.")) + ), + "label_attr" => array( + "for" => "agreed" + ) + )); } public function verifyPasswordField($value, ExecutionContextInterface $context) diff --git a/core/lib/Thelia/Form/CustomerLogin.php b/core/lib/Thelia/Form/CustomerLogin.php index 63dc186aa..78f4c3d33 100755 --- a/core/lib/Thelia/Form/CustomerLogin.php +++ b/core/lib/Thelia/Form/CustomerLogin.php @@ -22,10 +22,19 @@ /*************************************************************************************/ namespace Thelia\Form; +use Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Validator\ConstraintViolation; +use Symfony\Component\Validator\ExecutionContextInterface; use Thelia\Core\Translation\Translator; +use Thelia\Model\Base\CustomerQuery; +/** + * Class CustomerLogin + * @package Thelia\Form + * @author Manuel Raynaud + */ class CustomerLogin extends BaseForm { protected function buildForm() @@ -33,27 +42,82 @@ class CustomerLogin extends BaseForm $this->formBuilder ->add("email", "email", array( "constraints" => array( - new NotBlank(), - new Email() + new Constraints\NotBlank(), + new Constraints\Email(), + new Constraints\Callback(array( + "methods" => array( + array($this, "verifyExistingEmail") + ) + )) ), "label" => Translator::getInstance()->trans("Please enter your email address"), "label_attr" => array( "for" => "email" + ) + )) + ->add("account", "choice", array( + "constraints" => array( + new Constraints\Callback(array( + "methods" => array( + array($this, "verifyAccount") + ) + )) ), - "required" => true + "choices" => array( + 0 => Translator::getInstance()->trans("No, I am a new customer."), + 1 => Translator::getInstance()->trans("Yes, I have a password :") + ), + "label_attr" => array( + "for" => "account" + ), + "data" => 0 )) ->add("password", "password", array( - "constraints" => array( - new NotBlank() - ), + /*"constraints" => array( + new Constraints\NotBlank() + ),*/ "label" => Translator::getInstance()->trans("Please enter your password"), "label_attr" => array( "for" => "password" ), - "required" => true - )) - ->add("remember_me", "checkbox") - ; + "required" => false + )); + } + + /** + * If the user select "Yes, I have a password", we check the password. + */ + public function verifyAccount($value, ExecutionContextInterface $context) + { + if ($value == 1) { + $data = $context->getRoot()->getData(); + if (false === $data['password'] || (empty($data['password']) && '0' != $data['password'])) { + + $context->getViolations()->add(new ConstraintViolation( + 'This value should not be blank.', + 'account_password', + array(), + $context->getRoot(), + 'children[password].data', + 'propertyPath' + )); + + } + } + } + + /** + * If the user select "I'am a new customer", we make sure is email address does not exit in the database. + */ + public function verifyExistingEmail($value, ExecutionContextInterface $context) + { + $data = $context->getRoot()->getData(); + if ($data["account"] == 0) { + $customer = CustomerQuery::create()->findOneByEmail($value); + if ($customer) { + $context->addViolation("A user already exists with this email address. Please login or if you've forgotten your password, go to Reset Your Password."); + } + } } public function getName() diff --git a/core/lib/Thelia/Form/CustomerLostPasswordForm.php b/core/lib/Thelia/Form/CustomerLostPasswordForm.php index 83ff1f3d6..5fdb8af60 100644 --- a/core/lib/Thelia/Form/CustomerLostPasswordForm.php +++ b/core/lib/Thelia/Form/CustomerLostPasswordForm.php @@ -82,7 +82,7 @@ class CustomerLostPasswordForm extends BaseForm { $customer = CustomerQuery::create()->findOneByEmail($value); if (null === $customer) { - $context->addViolation("This email does not exists exists"); + $context->addViolation("This email does not exists"); } } diff --git a/core/lib/Thelia/Form/CustomerUpdateForm.php b/core/lib/Thelia/Form/CustomerUpdateForm.php new file mode 100755 index 000000000..b02c7e31e --- /dev/null +++ b/core/lib/Thelia/Form/CustomerUpdateForm.php @@ -0,0 +1,75 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Thelia\Model\ConfigQuery; +use Thelia\Core\Translation\Translator; + +/** + * Class CustomerUpdateForm + * @package Thelia\Form + * @author Christophe Laffont + */ +class CustomerUpdateForm extends CustomerCreation +{ + + protected function buildForm() + { + parent::buildForm(); + + + $this->formBuilder + ->remove("auto_login") + // Remove From Personal Informations + ->remove("phone") + ->remove("cellphone") + // Remove Delivery Informations + ->remove("company") + ->remove("address1") + ->remove("address2") + ->remove("address3") + ->remove("city") + ->remove("zipcode") + ->remove("country") + // Remove Login Information + ->remove("password") + ->remove("password_confirm") + // Remove Terms & conditions + ->remove("agreed") + + // Add Newsletter + ->add("newsletter", "checkbox", array( + "label" => "I would like to receive the newsletter our the latest news.", + "label_attr" => array( + "for" => "newsletter" + ), + "required" => false + )); + } + + public function getName() + { + return "thelia_customer_update"; + } +} diff --git a/core/lib/Thelia/Form/LanguageCreationForm.php b/core/lib/Thelia/Form/LanguageCreationForm.php new file mode 100644 index 000000000..713cafcd9 --- /dev/null +++ b/core/lib/Thelia/Form/LanguageCreationForm.php @@ -0,0 +1,58 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class LanguageCreationForm extends BaseForm +{ + protected function buildForm() + { + $this->formBuilder + ->add("title", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Language title *"), + "label_attr" => array( + "for" => "title" + ) + )) + ->add("isocode", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("ISO Code *"), + "label_attr" => array( + "for" => "isocode" + ) + )) + ; + } + + public function getName() + { + return "thelia_language_creation"; + } +} diff --git a/core/lib/Thelia/Form/TaxCreationForm.php b/core/lib/Thelia/Form/TaxCreationForm.php new file mode 100644 index 000000000..37cc80a92 --- /dev/null +++ b/core/lib/Thelia/Form/TaxCreationForm.php @@ -0,0 +1,97 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\ExecutionContextInterface; +use Thelia\Core\Form\Type\TheliaType; +use Thelia\Core\Translation\Translator; +use Thelia\TaxEngine\TaxEngine; +use Thelia\TaxEngine\TaxType; + +class TaxCreationForm extends BaseForm +{ + use StandardDescriptionFieldsTrait; + + protected function buildForm($change_mode = false) + { + $types = TaxEngine::getInstance()->getTaxTypeList(); + $typeList = array(); + $requirementList = array(); + foreach($types as $type) { + $classPath = "\\Thelia\\TaxEngine\\TaxType\\$type"; + $instance = new $classPath(); + $typeList[$type] = $instance->getTitle(); + $requirementList[$type] = $instance->getRequirementsList(); + } + + $this->formBuilder + ->add("locale", "text", array( + "constraints" => array(new NotBlank()) + )) + ->add("type", "choice", array( + "choices" => $typeList, + "required" => true, + "constraints" => array( + new Constraints\NotBlank(), + ), + "label" => Translator::getInstance()->trans("Type"), + "label_attr" => array("for" => "type_field"), + )) + ; + + foreach($requirementList as $type => $requirements) { + foreach($requirements as $name => $requirementType) { + $this->formBuilder + ->add($type . ':' . $name, new TheliaType(), array( + //"instance" => $requirementType, + "constraints" => array( + new Constraints\Callback( + array( + "methods" => array( + array($requirementType, "verifyForm"), + ), + ) + ), + ), + "attr" => array( + "tag" => "requirements", + "tax_type" => $type, + ), + "label" => Translator::getInstance()->trans($name), + "type" => $requirementType->getFormType(), + "options" => $requirementType->getFormOptions(), + )) + ; + } + } + + $this->addStandardDescFields(array('postscriptum', 'chapo', 'locale')); + } + + public function getName() + { + return "thelia_tax_creation"; + } +} diff --git a/core/lib/Thelia/Form/TaxModificationForm.php b/core/lib/Thelia/Form/TaxModificationForm.php new file mode 100644 index 000000000..1c496440e --- /dev/null +++ b/core/lib/Thelia/Form/TaxModificationForm.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints; +use Symfony\Component\Validator\ExecutionContextInterface; +use Thelia\Model\TaxQuery; + +class TaxModificationForm extends TaxCreationForm +{ + protected function buildForm() + { + parent::buildForm(true); + + $this->formBuilder + ->add("id", "hidden", array( + "required" => true, + "constraints" => array( + new Constraints\NotBlank(), + new Constraints\Callback( + array( + "methods" => array( + array($this, "verifyTaxId"), + ), + ) + ), + ) + )) + ; + } + + public function getName() + { + return "thelia_tax_modification"; + } + + public function verifyTaxId($value, ExecutionContextInterface $context) + { + $tax = TaxQuery::create() + ->findPk($value); + + if (null === $tax) { + $context->addViolation("Tax ID not found"); + } + } +} diff --git a/core/lib/Thelia/Model/Tax.php b/core/lib/Thelia/Model/Tax.php index 7b9b22b6f..6752129a2 100755 --- a/core/lib/Thelia/Model/Tax.php +++ b/core/lib/Thelia/Model/Tax.php @@ -4,10 +4,13 @@ namespace Thelia\Model; use Thelia\Exception\TaxEngineException; use Thelia\Model\Base\Tax as BaseTax; +use Thelia\Model\Tools\ModelEventDispatcherTrait; use Thelia\TaxEngine\TaxType\BaseTaxType; class Tax extends BaseTax { + use ModelEventDispatcherTrait; + public function calculateTax($amount) { if(false === filter_var($amount, FILTER_VALIDATE_FLOAT)) { diff --git a/core/lib/Thelia/Model/Tools/ModelEventDispatcherTrait.php b/core/lib/Thelia/Model/Tools/ModelEventDispatcherTrait.php index 17af1e44d..e96e2f84c 100644 --- a/core/lib/Thelia/Model/Tools/ModelEventDispatcherTrait.php +++ b/core/lib/Thelia/Model/Tools/ModelEventDispatcherTrait.php @@ -36,7 +36,11 @@ trait ModelEventDispatcherTrait { */ protected $dispatcher = null; - + /** + * @param EventDispatcherInterface $dispatcher + * + * @return $this + */ public function setDispatcher(EventDispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; diff --git a/core/lib/Thelia/Rewriting/RewritingResolver.php b/core/lib/Thelia/Rewriting/RewritingResolver.php index 4c8bcba40..8edd0ebba 100755 --- a/core/lib/Thelia/Rewriting/RewritingResolver.php +++ b/core/lib/Thelia/Rewriting/RewritingResolver.php @@ -59,7 +59,7 @@ class RewritingResolver public function load($rewrittenUrl) { $rewrittenUrl = ltrim($rewrittenUrl, '/'); - + $rewrittenUrl = urldecode($rewrittenUrl); $this->search = $this->rewritingUrlQuery->getResolverSearch($rewrittenUrl); if($this->search->count() == 0) { diff --git a/core/lib/Thelia/TaxEngine/TaxEngine.php b/core/lib/Thelia/TaxEngine/TaxEngine.php new file mode 100755 index 000000000..8e5a5695a --- /dev/null +++ b/core/lib/Thelia/TaxEngine/TaxEngine.php @@ -0,0 +1,71 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\TaxEngine; + +/** + * Class TaxEngine + * @package Thelia\TaxEngine + * @author Etienne Roudeix + */ +class TaxEngine +{ + static public function getInstance() + { + return new TaxEngine(); + } + + private function getTaxTypeDirectory() + { + return __DIR__ . "/TaxType"; + } + + public function getTaxTypeList() + { + $typeList = array(); + + try { + $directoryBrowser = new \DirectoryIterator($this->getTaxTypeDirectory($this->getTaxTypeDirectory())); + } catch (\UnexpectedValueException $e) { + return $typeList; + } + + /* browse the directory */ + foreach ($directoryBrowser as $directoryContent) { + /* is it a file ? */ + if (!$directoryContent->isFile()) { + continue; + } + + $fileName = $directoryContent->getFilename(); + $className = substr($fileName, 0, (1+strlen($directoryContent->getExtension())) * -1); + + if($className == "BaseTaxType") { + continue; + } + + $typeList[] = $className; + } + + return $typeList; + } +} diff --git a/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php index 1e0a11ca7..f8bdd8647 100755 --- a/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php +++ b/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php @@ -41,6 +41,8 @@ abstract class BaseTaxType public abstract function getRequirementsList(); + public abstract function getTitle(); + public function calculate(Product $product, $untaxedPrice) { return $untaxedPrice * $this->pricePercentRetriever() + $this->fixAmountRetriever($product); diff --git a/core/lib/Thelia/TaxEngine/TaxType/FeatureFixAmountTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/FeatureFixAmountTaxType.php index 32c78c1ac..e623528c2 100755 --- a/core/lib/Thelia/TaxEngine/TaxType/FeatureFixAmountTaxType.php +++ b/core/lib/Thelia/TaxEngine/TaxType/FeatureFixAmountTaxType.php @@ -65,4 +65,9 @@ class FeatureFixAmountTaxType extends BaseTaxType 'feature' => new ModelValidIdType('Feature'), ); } + + public function getTitle() + { + return "Fix amount Tax depending on a feature"; + } } diff --git a/core/lib/Thelia/TaxEngine/TaxType/FixAmountTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/FixAmountTaxType.php index e62136d99..c93715571 100755 --- a/core/lib/Thelia/TaxEngine/TaxType/FixAmountTaxType.php +++ b/core/lib/Thelia/TaxEngine/TaxType/FixAmountTaxType.php @@ -47,4 +47,9 @@ class FixAmountTaxType extends BaseTaxType 'amount' => new FloatType(), ); } + + public function getTitle() + { + return "Fix amount Tax"; + } } diff --git a/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php index 342f51a6d..6881b0288 100755 --- a/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php +++ b/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php @@ -47,6 +47,9 @@ class PricePercentTaxType extends BaseTaxType 'percent' => new FloatType(), ); } -} -//600 / (1 + 0,10 + 0,10) =/= 600 / (1 + 0,10 ) + 600 / (1 + 0,10 ) \ No newline at end of file + public function getTitle() + { + return "Price % Tax"; + } +} diff --git a/core/lib/Thelia/Type/AlphaNumStringListType.php b/core/lib/Thelia/Type/AlphaNumStringListType.php index d8e53cd95..ccf21606d 100755 --- a/core/lib/Thelia/Type/AlphaNumStringListType.php +++ b/core/lib/Thelia/Type/AlphaNumStringListType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class AlphaNumStringListType implements TypeInterface +class AlphaNumStringListType extends BaseType { public function getType() { @@ -50,4 +50,14 @@ class AlphaNumStringListType implements TypeInterface { return $this->isValid($values) ? explode(',', $values) : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/AlphaNumStringType.php b/core/lib/Thelia/Type/AlphaNumStringType.php index 726e6eb67..ad9595f20 100755 --- a/core/lib/Thelia/Type/AlphaNumStringType.php +++ b/core/lib/Thelia/Type/AlphaNumStringType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class AlphaNumStringType implements TypeInterface +class AlphaNumStringType extends BaseType { public function getType() { @@ -44,4 +44,14 @@ class AlphaNumStringType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/AnyType.php b/core/lib/Thelia/Type/AnyType.php index 5cdbb1272..4e844c6e9 100755 --- a/core/lib/Thelia/Type/AnyType.php +++ b/core/lib/Thelia/Type/AnyType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class AnyType implements TypeInterface +class AnyType extends BaseType { public function getType() { @@ -44,4 +44,14 @@ class AnyType implements TypeInterface { return $value; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/BaseType.php b/core/lib/Thelia/Type/BaseType.php new file mode 100644 index 000000000..9beb180e7 --- /dev/null +++ b/core/lib/Thelia/Type/BaseType.php @@ -0,0 +1,46 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +use Symfony\Component\Validator\ExecutionContextInterface; + +/** + * + * @author Etienne Roudeix + * + */ +abstract class BaseType implements TypeInterface +{ + abstract public function getType(); + abstract public function isValid($value); + abstract public function getFormattedValue($value); + abstract public function getFormType(); + abstract public function getFormOptions(); + + public function verifyForm($value, ExecutionContextInterface $context) + { + if( ! $this->isValid($value) ) { + $context->addViolation(sprintf("received value `%s` does not match `%s` type", $value, $this->getType())); + } + } +} diff --git a/core/lib/Thelia/Type/BooleanOrBothType.php b/core/lib/Thelia/Type/BooleanOrBothType.php index 210201e26..25f3d9994 100755 --- a/core/lib/Thelia/Type/BooleanOrBothType.php +++ b/core/lib/Thelia/Type/BooleanOrBothType.php @@ -29,7 +29,7 @@ namespace Thelia\Type; * */ -class BooleanOrBothType implements TypeInterface +class BooleanOrBothType extends BaseType { const ANY = '*'; @@ -49,4 +49,14 @@ class BooleanOrBothType implements TypeInterface if ($value === self::ANY) return $value; return $value === null ? null : filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/BooleanType.php b/core/lib/Thelia/Type/BooleanType.php index 69cba66ac..5f36453de 100755 --- a/core/lib/Thelia/Type/BooleanType.php +++ b/core/lib/Thelia/Type/BooleanType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class BooleanType implements TypeInterface +class BooleanType extends BaseType { public function getType() { @@ -44,4 +44,14 @@ class BooleanType implements TypeInterface { return $value === null ? null : filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/EnumListType.php b/core/lib/Thelia/Type/EnumListType.php index 2c37929a8..5b54c48bf 100755 --- a/core/lib/Thelia/Type/EnumListType.php +++ b/core/lib/Thelia/Type/EnumListType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class EnumListType implements TypeInterface +class EnumListType extends BaseType { protected $values = array(); @@ -69,4 +69,14 @@ class EnumListType implements TypeInterface { return in_array($value, $this->values); } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/EnumType.php b/core/lib/Thelia/Type/EnumType.php index 416f9714a..1283acde0 100755 --- a/core/lib/Thelia/Type/EnumType.php +++ b/core/lib/Thelia/Type/EnumType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class EnumType implements TypeInterface +class EnumType extends BaseType { protected $values = array(); @@ -52,4 +52,14 @@ class EnumType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/FloatToFloatArrayType.php b/core/lib/Thelia/Type/FloatToFloatArrayType.php index 682ddebdd..f55997f55 100755 --- a/core/lib/Thelia/Type/FloatToFloatArrayType.php +++ b/core/lib/Thelia/Type/FloatToFloatArrayType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class FloatToFloatArrayType implements TypeInterface +class FloatToFloatArrayType extends BaseType { public function getType() { @@ -54,4 +54,14 @@ class FloatToFloatArrayType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/FloatType.php b/core/lib/Thelia/Type/FloatType.php index f82f34b58..830622a86 100755 --- a/core/lib/Thelia/Type/FloatType.php +++ b/core/lib/Thelia/Type/FloatType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class FloatType implements TypeInterface +class FloatType extends BaseType { public function getType() { @@ -44,4 +44,14 @@ class FloatType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/IntListType.php b/core/lib/Thelia/Type/IntListType.php index 28590472e..5fe31aa3c 100755 --- a/core/lib/Thelia/Type/IntListType.php +++ b/core/lib/Thelia/Type/IntListType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class IntListType implements TypeInterface +class IntListType extends BaseType { public function getType() { @@ -50,4 +50,14 @@ class IntListType implements TypeInterface { return $this->isValid($values) ? explode(',', $values) : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/IntToCombinedIntsListType.php b/core/lib/Thelia/Type/IntToCombinedIntsListType.php index b2dc6b068..562e160dd 100755 --- a/core/lib/Thelia/Type/IntToCombinedIntsListType.php +++ b/core/lib/Thelia/Type/IntToCombinedIntsListType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class IntToCombinedIntsListType implements TypeInterface +class IntToCombinedIntsListType extends BaseType { public function getType() { @@ -124,4 +124,14 @@ class IntToCombinedIntsListType implements TypeInterface return true; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/IntToCombinedStringsListType.php b/core/lib/Thelia/Type/IntToCombinedStringsListType.php index 5863feb97..5c4327dc8 100755 --- a/core/lib/Thelia/Type/IntToCombinedStringsListType.php +++ b/core/lib/Thelia/Type/IntToCombinedStringsListType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class IntToCombinedStringsListType implements TypeInterface +class IntToCombinedStringsListType extends BaseType { public function getType() { @@ -124,4 +124,14 @@ class IntToCombinedStringsListType implements TypeInterface return true; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/IntType.php b/core/lib/Thelia/Type/IntType.php index 8e2ec4fd8..5aa146e60 100755 --- a/core/lib/Thelia/Type/IntType.php +++ b/core/lib/Thelia/Type/IntType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class IntType implements TypeInterface +class IntType extends BaseType { public function getType() { @@ -44,4 +44,14 @@ class IntType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/JsonType.php b/core/lib/Thelia/Type/JsonType.php index 5c92182a8..502a43953 100755 --- a/core/lib/Thelia/Type/JsonType.php +++ b/core/lib/Thelia/Type/JsonType.php @@ -28,7 +28,7 @@ namespace Thelia\Type; * */ -class JsonType implements TypeInterface +class JsonType extends BaseType { public function getType() { @@ -46,4 +46,14 @@ class JsonType implements TypeInterface { return $this->isValid($value) ? json_decode($value, true) : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/ModelType.php b/core/lib/Thelia/Type/ModelType.php index 9eacef094..a8ab8c553 100755 --- a/core/lib/Thelia/Type/ModelType.php +++ b/core/lib/Thelia/Type/ModelType.php @@ -30,7 +30,7 @@ use Thelia\Exception\TypeException; * @author Etienne Roudeix * */ -class ModelType implements TypeInterface +class ModelType extends BaseType { protected $expectedModelActiveRecord = null; @@ -63,4 +63,14 @@ class ModelType implements TypeInterface { return $this->isValid($value) ? $value : null; } + + public function getFormType() + { + return 'text'; + } + + public function getFormOptions() + { + return array(); + } } diff --git a/core/lib/Thelia/Type/ModelValidIdType.php b/core/lib/Thelia/Type/ModelValidIdType.php index 9ae94e497..a9bfec7b5 100755 --- a/core/lib/Thelia/Type/ModelValidIdType.php +++ b/core/lib/Thelia/Type/ModelValidIdType.php @@ -30,7 +30,7 @@ use Thelia\Exception\TypeException; * @author Etienne Roudeix * */ -class ModelValidIdType implements TypeInterface +class ModelValidIdType extends BaseType { protected $expectedModelActiveRecordQuery = null; @@ -67,4 +67,23 @@ class ModelValidIdType implements TypeInterface return $this->isValid($value) ? $queryClass::create()->findPk($value) : null; } + + public function getFormType() + { + return 'choice'; + } + + public function getFormOptions() + { + $queryClass = $this->expectedModelActiveRecordQuery; + + $choices = array(); + foreach($queryClass::create()->find() as $item) { + $choices[$item->getId()] = method_exists($item, "getTitle") ? $item->getTitle() : $item->getId(); + } + + return array( + "choices" => $choices, + ); + } } diff --git a/core/lib/Thelia/Type/TypeInterface.php b/core/lib/Thelia/Type/TypeInterface.php index b293b1783..99e2f77e0 100755 --- a/core/lib/Thelia/Type/TypeInterface.php +++ b/core/lib/Thelia/Type/TypeInterface.php @@ -22,12 +22,13 @@ /*************************************************************************************/ namespace Thelia\Type; +use Symfony\Component\Validator\ExecutionContextInterface; + /** * * @author Etienne Roudeix * */ - interface TypeInterface { public function getType(); @@ -35,4 +36,8 @@ interface TypeInterface public function isValid($value); public function getFormattedValue($value); + + public function getFormType(); + public function getFormOptions(); + public function verifyForm($value, ExecutionContextInterface $context); } diff --git a/local/modules/TheliaDebugBar/Listeners/DebugBarListeners.php b/local/modules/TheliaDebugBar/Listeners/DebugBarListeners.php index c7b9d015c..5ea75a1df 100755 --- a/local/modules/TheliaDebugBar/Listeners/DebugBarListeners.php +++ b/local/modules/TheliaDebugBar/Listeners/DebugBarListeners.php @@ -45,13 +45,17 @@ class DebugBarListeners extends BaseAction implements EventSubscriberInterface { { $debugBar = $this->container->get("debugBar"); + $alternativelogger = null; + if($this->container->getParameter('kernel.debug')) { + $alternativelogger = \Thelia\Log\Tlog::getInstance(); + } $debugBar->addCollector(new PhpInfoCollector()); //$debugBar->addCollector(new MessagesCollector()); //$debugBar->addCollector(new RequestDataCollector()); $debugBar->addCollector(new TimeDataCollector()); $debugBar->addCollector(new MemoryCollector()); - $debugBar->addCollector(new PropelCollector(\Thelia\Log\Tlog::getInstance())); + $debugBar->addCollector(new PropelCollector($alternativelogger)); } /** diff --git a/templates/admin/default/admin-layout.tpl b/templates/admin/default/admin-layout.tpl index 592e47d28..f66cc17e1 100644 --- a/templates/admin/default/admin-layout.tpl +++ b/templates/admin/default/admin-layout.tpl @@ -56,7 +56,7 @@
{intl l='Version %ver' ver="{$THELIA_VERSION}"}
- +
@@ -89,7 +89,7 @@
- - + {module_include location='configuration_bottom'} + + + {/block} \ No newline at end of file diff --git a/templates/admin/default/languages.html b/templates/admin/default/languages.html new file mode 100644 index 000000000..499e903d7 --- /dev/null +++ b/templates/admin/default/languages.html @@ -0,0 +1,272 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Thelia Languages'}{/block} + +{block name="check-permissions"}admin.configuration.languages.view{/block} + +{block name="main-content"} +
+ +
+ + + + {module_include location='languages_top'} + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {intl l="Languages management"} + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.languages.create"} + + + + {/loop} + +
{intl l="Language name"}{intl l="ISO 639 Code"}{intl l="Default"}{intl l="Actions"}
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
{intl l="Parameters"}
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+
+
+ +
{intl l="Association language/URL"}
+ +
+
+
+ + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
{intl l="France"}
{intl l="English"}
{intl l="Spanish"}
+ +
+
+
+ +
+
+
+ + {module_include location='languages_bottom'} + +
+
+ +{form name="thelia.admin.language.creation"} + + {* Capture the dialog body, to pass it to the generic dialog *} + {capture "creation_dialog"} + + {form_hidden_fields form=$form} + + {* Be sure to get the language_id, even if the form could not be validated *} + + + {form_field form=$form field='success_url'} + {* on success, redirect to the edition page, _ID_ is replaced with the created object ID, see controller *} + + {/form_field} + + {form_field form=$form field='title'} +
+ + +
+ {/form_field} + + {form_field form=$form field='isocode'} +
+ + +
+ {/form_field} + + {module_include location='language_create_form'} + + {/capture} + + {include + file = "includes/generic-create-dialog.html" + + dialog_id = "creation_dialog" + dialog_title = {intl l="Create a new language"} + dialog_body = {$smarty.capture.creation_dialog nofilter} + + dialog_ok_label = {intl l="Create this language"} + + form_action = {url path='/admin/configuration/languages/create'} + form_enctype = {form_enctype form=$form} + form_error_message = $form_error_message + } +{/form} + +{* Delete confirmation dialog *} + +{capture "delete_dialog"} + + + {module_include location='languages_delete_form'} + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_dialog" + dialog_title = {intl l="Delete language"} + dialog_message = {intl l="Do you really want to delete this language ?"} + + form_action = {url path='/admin/configuration/languages/delete'} + form_content = {$smarty.capture.delete_dialog nofilter} +} + +{/block} + +{block name="javascript-initialization"} + {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} + + + + {/javascripts} + + {javascripts file='assets/js/main.js'} + + {/javascripts} + + {javascripts file='assets/js/bootstrap-select/bootstrap-select.js'} + + {/javascripts} +{/block} \ No newline at end of file diff --git a/templates/admin/default/mailing-system.html b/templates/admin/default/mailing-system.html new file mode 100644 index 000000000..4f826e954 --- /dev/null +++ b/templates/admin/default/mailing-system.html @@ -0,0 +1,102 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Thelia Mailing System'}{/block} + +{block name="check-permissions"}admin.configuration.mailing-system.view{/block} + +{block name="main-content"} +
+ +
+ + + + {module_include location='mailing_system_top'} + +
+
+
+ +
{intl l="Configuration variables"}
+ +
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ +
+ + +
+ +
+
+ +
+ +
+
+
+ + {module_include location='mailing_system_bottom'} + +
+
+{/block} + +{block name="javascript-initialization"} + {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} + + {/javascripts} +{/block} \ No newline at end of file diff --git a/templates/admin/default/tax-edit.html b/templates/admin/default/tax-edit.html new file mode 100644 index 000000000..1237d6344 --- /dev/null +++ b/templates/admin/default/tax-edit.html @@ -0,0 +1,157 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Edit a tax'}{/block} + +{block name="check-permissions"}admin.configuration.taxes.edit{/block} + +{block name="main-content"} + +
+ +
+ + + + {loop type="tax" name="tax" id=$tax_id backend_context="1" lang=$edit_language_id} + +
+
+ +
+ + {form name="thelia.admin.tax.modification"} + +
+ + {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = false + + page_url = {url path="/admin/configuration/taxes/update/$tax_id"} + close_url = {url path="/admin/configuration/taxes_rules"} + } + + {* Be sure to get the product ID, even if the form could not be validated *} + + + {form_hidden_fields form=$form} + + {form_field form=$form field='success_url'} + + {/form_field} + + {form_field form=$form field='locale'} + + {/form_field} + + {if $form_error}
{$form_error_message}
{/if} + + {form_field form=$form field='title'} +
+ + +
+ {/form_field} + + {form_field form=$form field='description'} +
+ + + +
+ {/form_field} + + {form_field form=$form field='type'} +
+ + +
+ +
+
+ + {$typeValue = $value} + {/form_field} + + {form_tagged_fields form=$form tag='requirements'} +
+ + {if $formType == 'choice'} + + {/if} + {if $formType == 'text'} + + {/if} +
+ {/form_tagged_fields} + +
+
+
+ +
+

{intl l='Tax created on %date_create. Last modification: %date_change' date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE}}

+
+
+
+
+ +
+ {/form} +
+ +
+
+ + {/loop} + +
+ +{/block} + +{block name="javascript-initialization"} + + {javascripts file='assets/js/bootstrap-select/bootstrap-select.js'} + + {/javascripts} + + {javascripts file='assets/js/main.js'} + + {/javascripts} + + + + + +{/block} \ No newline at end of file diff --git a/templates/admin/default/tax-rule-edit.html b/templates/admin/default/tax-rule-edit.html index c236e7bc4..f769a601c 100644 --- a/templates/admin/default/tax-rule-edit.html +++ b/templates/admin/default/tax-rule-edit.html @@ -6,10 +6,10 @@ {block name="main-content"} -{assign oder_tab {$smarty.get.tab|default:$smarty.post.tab|default:'data'}} -{assign asked_country {$smarty.get.country|default:{country ask="default" attr="id"}}} + {assign oder_tab {$smarty.get.tab|default:$smarty.post.tab|default:'data'}} + {assign asked_country {$smarty.get.country|default:{country ask="default" attr="id"}}} -
+
@@ -35,63 +35,63 @@
- {form name="thelia.admin.taxrule.modification"} + {form name="thelia.admin.taxrule.modification"} -
+ - {include - file = "includes/inner-form-toolbar.html" - hide_submit_buttons = false + {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = false - page_url = {url path="/admin/configuration/taxes_rules/update/$tax_rule_id" tab=data} - close_url = {url path="/admin/configuration/taxes_rules"} - } + page_url = {url path="/admin/configuration/taxes_rules/update/$tax_rule_id" tab=data} + close_url = {url path="/admin/configuration/taxes_rules"} + } - {* Be sure to get the product ID, even if the form could not be validated *} - + {* Be sure to get the product ID, even if the form could not be validated *} + - {form_hidden_fields form=$form} + {form_hidden_fields form=$form} - {form_field form=$form field='success_url'} - - {/form_field} + {form_field form=$form field='success_url'} + + {/form_field} - {form_field form=$form field='locale'} - - {/form_field} + {form_field form=$form field='locale'} + + {/form_field} - {if $form_error}
{$form_error_message}
{/if} + {if $form_error}
{$form_error_message}
{/if} - {form_field form=$form field='title'} -
- - -
- {/form_field} - - {form_field form=$form field='description'} -
- - - -
- {/form_field} - -
-
-
- -
-

{intl l='Tax rule created on %date_create. Last modification: %date_change' date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE}}

+ {form_field form=$form field='title'} +
+ +
-
-
-
+ {/form_field} - + {form_field form=$form field='description'} +
+ + + +
+ {/form_field} + +
+
+
+ +
+

{intl l='Tax rule created on %date_create. Last modification: %date_change' date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE}}

+
+
+
+
+ + {/form}
@@ -116,12 +116,12 @@

{intl l="Countries that have the same tax rule"} :

-

+

{$matchedCountries.first=$asked_country} - {loop type="tax-rule-country" name="same-country-list" tax_rule=$ID taxes="1,2,3" country=$asked_country} - {$matchedCountries[]=$COUNTRY} + {loop type="tax-rule-country" name="same-country-list" tax_rule=$ID ask="countries" country=$asked_country} + {$matchedCountries[]=$COUNTRY} {$COUNTRY_TITLE} {/loop} @@ -129,6 +129,7 @@ {intl l="NONE"} {/elseloop}

+
@@ -140,125 +141,130 @@
{assign lastPosition 0} {loop type="tax-rule-country" name="existing-tax-list" tax_rule=$ID country=$asked_country} - {if $POSITION != $lastPosition} - {assign lastPosition $POSITION} - {if $LOOP_COUNT > 1} -
- {/if} -
-

- - {intl l="Add tax to this group"} -

- {/if} - -
{$TAX_TITLE}
- - {if $LOOP_COUNT == $LOOP_TOTAL} -
- {/if} - {/loop} - - {elseloop rel="existing-tax-list"} -
-

- - {intl l="Add tax to this group"} -

-
- - {/elseloop} - + {if $POSITION != $lastPosition} + {assign lastPosition $POSITION} + {if $LOOP_COUNT > 1}
- - - {intl l="Apply"} - -
-
- -
-
-

Available taxes

-
-
- {loop type="tax" name="tax-list" exclude_tax_rule=$ID country=$asked_country} -
{$TITLE}
- {/loop} -
- + -
+ + {intl l="Apply"} +
+
+
+
+

Available taxes

+
+
+ {loop type="tax" name="tax-list" exclude_tax_rule=$ID country=$asked_country} +
{$TITLE}
+ {/loop} +
+ +
+ +
+
-
-
- {/loop} + + + + {/loop} - - {* Confirmation dialog *} + +{* Confirmation dialog *} {form name="thelia.admin.taxrule.taxlistupdate"} - {if $form_error_message} - {$taxUpdateError = true} - {else} - {$taxUpdateError = false} - {/if} + {if $form_error_message} + {$taxUpdateError = true} + {else} + {$taxUpdateError = false} + {/if} - {* Capture the dialog body, to pass it to the generic dialog *} - {capture "tax_list_update_dialog"} + {* Capture the dialog body, to pass it to the generic dialog *} + {capture "tax_list_update_dialog"} - - + + - {form_hidden_fields form=$form} + {form_hidden_fields form=$form} - {form_field form=$form field='country_list'} + {form_field form=$form field='country_list'}

{intl l="Tax rule taxes will be update for the following countries :"}

- +
+ + + + +
- {/form_field} + {/form_field} - {/capture} + {/capture} {include - file = "includes/generic-create-dialog.html" + file = "includes/generic-create-dialog.html" - dialog_id = "tax_list_update_dialog" - dialog_title = {intl l="Update tax rule taxes"} - dialog_body = {$smarty.capture.tax_list_update_dialog nofilter} + dialog_id = "tax_list_update_dialog" + dialog_title = {intl l="Update tax rule taxes"} + dialog_body = {$smarty.capture.tax_list_update_dialog nofilter} - dialog_ok_label = {intl l="Edit tax rule taxes"} - dialog_cancel_label = {intl l="Cancel"} + dialog_ok_label = {intl l="Edit tax rule taxes"} + dialog_cancel_label = {intl l="Cancel"} - form_action = {url path="/admin/configuration/taxes_rules/saveTaxes"} - form_enctype = {form_enctype form=$form} - form_error_message = $form_error_message - } + form_action = {url path="/admin/configuration/taxes_rules/saveTaxes"} + form_enctype = {form_enctype form=$form} + form_error_message = $form_error_message + } {/form} @@ -279,11 +285,34 @@ + {/javascripts} -{if $taxCreateError == true} - $('#tax_rule_create_dialog').modal(); -{/if} + {javascripts file='assets/js/main.js'} + + {/javascripts} - $(".js-delete-tax-rule").click(function(e){ - $('#tax_rule_delete_id').val($(this).data('id')) - }); - + {/block} \ No newline at end of file diff --git a/templates/default/account-update.html b/templates/default/account-update.html new file mode 100644 index 000000000..d14db6681 --- /dev/null +++ b/templates/default/account-update.html @@ -0,0 +1,131 @@ +{extends file="layout.tpl"} + +{* Body Class *} +{block name="body-class"}page-account-update{/block} + +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [['title' => {intl l="Account"}, 'url'=>{url path="/account"}]]} + {$breadcrumbs = [ + ['title' => {intl l="Account"}, 'url'=>{url path="/account"}], + ['title' => {intl l="Update Profil"}, 'url'=>{url path="/account/update"}] + ]} +{/block} + +{block name="main-content"} +
+ +
+ +

{intl l="Update Profil"}

+ + {form name="thelia.customer.update"} + {assign var="isPost" value="{$smarty.post|count}"} +
+ {form_field form=$form field='success_url'} + + {/form_field} + + {form_hidden_fields form=$form} + + {if $form_error}
{$form_error_message}
{/if} + +
+
+ {intl l="Personal Informations"} +
+ +
+ {form_field form=$form field="title"} +
+ +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {elseif !$value} + {assign var="error_focus" value="true"} + {elseif $isPost && $value != "" && !$error} + + {/if} +
+
+ {/form_field} + {form_field form=$form field="firstname"} +
+ +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {elseif $isPost && $value != "" && !$error} + + {/if} +
+
+ {/form_field} + {form_field form=$form field="lastname"} +
+ +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {elseif $isPost && $value != "" && !$error} + + {/if} +
+
+ {/form_field} + {form_field form=$form field="email"} +
+ + +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {elseif $isPost && $value != "" && !$error} + + {/if} +
+
+ {/form_field} +
+
+ + {form_field form=$form field="newsletter"} +
+
+
+ + {if $error } + {$message} + {/if} +
+
+
+ {/form_field} + +
+
+ +
+
+
+ {/form} +
+ +
+{/block} \ No newline at end of file diff --git a/templates/default/account.html b/templates/default/account.html index 187847ced..adbb4bf9e 100644 --- a/templates/default/account.html +++ b/templates/default/account.html @@ -1,19 +1,18 @@ {extends file="layout.tpl"} -{block name="no-return-functions"} +{block name="no-return-functions" prepend} {check_auth context="front" roles="CUSTOMER" login_tpl="login"} {/block} -{block name="breadcrumb"} - +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [ + ['title' => {intl l="Account"}, 'url'=>{url path="/account"}] + ]} {/block} +{block name="body-class"}page-account{/block} + {block name="main-content"}
@@ -40,13 +39,13 @@
{$ADDRESS1}
{if $ADDRESS2 != ""} - {$ADDRESS2}
+ {$ADDRESS2}
{/if} {if $ADDRESS3 != ""} - {$ADDRESS3}
+ {$ADDRESS3}
{/if} {$ZIPCODE} - {$CITY}, {loop type="country" name="customer.country.info" id=$COUNTRY}{$TITLE}{/loop} + {$CITY}
{loop type="country" name="customer.country.info" id=$COUNTRY}{$TITLE}{/loop}
  • @@ -56,11 +55,11 @@ {if $PHONE != ""} {$PHONE} {/if} - +
  • - - Change my password + + {intl l="Change my password"}
  • {/loop} @@ -83,7 +82,7 @@ {loop type="address" name="customer.addresses" customer="current"} - {$LABEL} + {$LABEL|default:"{intl l='Address %nb' nb={$LOOP_COUNT}}"}
    + {ifloop rel="customer.orders"} @@ -163,9 +163,10 @@
    + {/ifloop} {elseloop rel="customer.orders"}
    - {intl l="Warning"}! {intl l="You don't have orders yet"} + {intl l="Warning"}! {intl l="You don't have orders yet."}
    {/elseloop}
    @@ -175,38 +176,6 @@
    - - - {/block} -{block name="after-javascript-include"} - - - -{/block} \ No newline at end of file +{block name="after-javascript-include"}{/block} \ No newline at end of file diff --git a/templates/default/address-update.html b/templates/default/address-update.html index 9e58e19ac..cd64ade1d 100644 --- a/templates/default/address-update.html +++ b/templates/default/address-update.html @@ -4,15 +4,15 @@ {check_auth context="front" roles="CUSTOMER" login_tpl="login"} {/block} -{block name="breadcrumb"} - +{* Body Class *} +{block name="body-class"}page-address{/block} + +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [ + ['title' => {intl l="Account"}, 'url'=>{url path="/account"}], + ['title' => {intl l="Address Update"}, 'url'=>{url path="/address"}] + ]} {/block} {block name="main-content"} @@ -25,7 +25,7 @@ {loop name="customer.update" type="address" customer="current" id="{$address_id}"}
    {form_field form=$form field='success_url'} - {* the url the user is redirected to on login success *} + {* the url the user is redirected to on login success *} {/form_field} {form_field form=$form field='error_message'} diff --git a/templates/default/address.html b/templates/default/address.html index b400fe87b..6b0245956 100644 --- a/templates/default/address.html +++ b/templates/default/address.html @@ -4,15 +4,15 @@ {check_auth context="front" roles="CUSTOMER" login_tpl="login"} {/block} -{block name="breadcrumb"} - +{* Body Class *} +{block name="body-class"}page-address{/block} + +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [ + ['title' => {intl l="Account"}, 'url'=>{url path="/account"}], + ['title' => {intl l="Address"}, 'url'=>{url path="/address"}] + ]} {/block} {block name="main-content"} @@ -24,7 +24,7 @@ {form name="thelia.address.create"} {form_field form=$form field='success_url'} - {* the url the user is redirected to on login success *} + {* the url the user is redirected to on login success *} {/form_field} {form_field form=$form field='error_message'} diff --git a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css deleted file mode 100755 index a24a8e142..000000000 --- a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css +++ /dev/null @@ -1,19 +0,0 @@ -.magnify { - position: relative; - cursor: none -} - -.magnify-large { - position: absolute; - display: none; - width: 175px; - height: 175px; - - -webkit-box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); - -moz-box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); - box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); - - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100% -} \ No newline at end of file diff --git a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css deleted file mode 100755 index 15b9cc170..000000000 --- a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css +++ /dev/null @@ -1 +0,0 @@ -.magnify{position:relative;cursor:none}.magnify-large{position:absolute;display:none;width:175px;height:175px;-webkit-box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);-moz-box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%} \ No newline at end of file diff --git a/templates/default/assets/img/ajax-loader.gif b/templates/default/assets/img/ajax-loader.gif new file mode 100644 index 000000000..948fa9bdb Binary files /dev/null and b/templates/default/assets/img/ajax-loader.gif differ diff --git a/templates/default/assets/js/bootstrap/affix.js b/templates/default/assets/js/bootstrap/affix.js deleted file mode 100755 index c7be96e1d..000000000 --- a/templates/default/assets/js/bootstrap/affix.js +++ /dev/null @@ -1,126 +0,0 @@ -/* ======================================================================== - * Bootstrap: affix.js v3.0.0 - * http://twbs.github.com/bootstrap/javascript.html#affix - * ======================================================================== - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // AFFIX CLASS DEFINITION - // ====================== - - var Affix = function (element, options) { - this.options = $.extend({}, Affix.DEFAULTS, options) - this.$window = $(window) - .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) - .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) - - this.$element = $(element) - this.affixed = - this.unpin = null - - this.checkPosition() - } - - Affix.RESET = 'affix affix-top affix-bottom' - - Affix.DEFAULTS = { - offset: 0 - } - - Affix.prototype.checkPositionWithEventLoop = function () { - setTimeout($.proxy(this.checkPosition, this), 1) - } - - Affix.prototype.checkPosition = function () { - if (!this.$element.is(':visible')) return - - var scrollHeight = $(document).height() - var scrollTop = this.$window.scrollTop() - var position = this.$element.offset() - var offset = this.options.offset - var offsetTop = offset.top - var offsetBottom = offset.bottom - - if (typeof offset != 'object') offsetBottom = offsetTop = offset - if (typeof offsetTop == 'function') offsetTop = offset.top() - if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() - - var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : - offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : - offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false - - if (this.affixed === affix) return - if (this.unpin) this.$element.css('top', '') - - this.affixed = affix - this.unpin = affix == 'bottom' ? position.top - scrollTop : null - - this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : '')) - - if (affix == 'bottom') { - this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() }) - } - } - - - // AFFIX PLUGIN DEFINITION - // ======================= - - var old = $.fn.affix - - $.fn.affix = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.affix') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.affix', (data = new Affix(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - $.fn.affix.Constructor = Affix - - - // AFFIX NO CONFLICT - // ================= - - $.fn.affix.noConflict = function () { - $.fn.affix = old - return this - } - - - // AFFIX DATA-API - // ============== - - $(window).on('load', function () { - $('[data-spy="affix"]').each(function () { - var $spy = $(this) - var data = $spy.data() - - data.offset = data.offset || {} - - if (data.offsetBottom) data.offset.bottom = data.offsetBottom - if (data.offsetTop) data.offset.top = data.offsetTop - - $spy.affix(data) - }) - }) - -}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/alert.js b/templates/default/assets/js/bootstrap/alert.js deleted file mode 100755 index 663029ed8..000000000 --- a/templates/default/assets/js/bootstrap/alert.js +++ /dev/null @@ -1,98 +0,0 @@ -/* ======================================================================== - * Bootstrap: alert.js v3.0.0 - * http://twbs.github.com/bootstrap/javascript.html#alerts - * ======================================================================== - * Copyright 2013 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== */ - - -+function ($) { "use strict"; - - // ALERT CLASS DEFINITION - // ====================== - - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = $(selector) - - if (e) e.preventDefault() - - if (!$parent.length) { - $parent = $this.hasClass('alert') ? $this : $this.parent() - } - - $parent.trigger(e = $.Event('close.bs.alert')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - $parent.trigger('closed.bs.alert').remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent - .one($.support.transition.end, removeElement) - .emulateTransitionEnd(150) : - removeElement() - } - - - // ALERT PLUGIN DEFINITION - // ======================= - - var old = $.fn.alert - - $.fn.alert = function (option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.alert.Constructor = Alert - - - // ALERT NO CONFLICT - // ================= - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - // ALERT DATA-API - // ============== - - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) - -}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/bootstrap.js b/templates/default/assets/js/bootstrap/bootstrap.js new file mode 100755 index 000000000..2c6425714 --- /dev/null +++ b/templates/default/assets/js/bootstrap/bootstrap.js @@ -0,0 +1,1999 @@ +/** +* bootstrap.js v3.0.0 by @fat and @mdo +* Copyright 2013 Twitter Inc. +* http://www.apache.org/licenses/LICENSE-2.0 +*/ +if (!jQuery) { throw new Error("Bootstrap requires jQuery") } + +/* ======================================================================== + * Bootstrap: transition.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#transitions + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#alerts + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#buttons + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d); + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + .prop('checked', !this.$element.hasClass('active')) + .trigger('change') + if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active') + } + + this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#carousel + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000 + , pause: 'hover' + , wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + this.sliding = true + + isCycling && this.pause() + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + .emulateTransitionEnd(600) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#collapse + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(window.jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#dropdowns + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + var $el = $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we we use a backdrop because click events don't delegate + $('