From 4eac17fe850c0842c2f5f39233d661ff7e612342 Mon Sep 17 00:00:00 2001 From: franck Date: Wed, 4 Sep 2013 10:32:37 +0200 Subject: [PATCH 01/39] Typo (sorry Etienne) --- core/lib/Thelia/Core/Template/Loop/Product.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Loop/Product.php b/core/lib/Thelia/Core/Template/Loop/Product.php index 17ecd3212..65a2d4346 100755 --- a/core/lib/Thelia/Core/Template/Loop/Product.php +++ b/core/lib/Thelia/Core/Template/Loop/Product.php @@ -520,11 +520,11 @@ class Product extends BaseI18nLoop ->set("IS_NEW", $product->getVirtualColumn('main_product_is_new')) ->set("POSITION", $product->getPosition()) - ->set("CREATE_DATE", $category->getCreatedAt()) - ->set("UPDATE_DATE", $category->getUpdatedAt()) - ->set("VERSION", $category->getVersion()) - ->set("VERSION_DATE", $category->getVersionCreatedAt()) - ->set("VERSION_AUTHOR", $category->getVersionCreatedBy()) + ->set("CREATE_DATE", $product->getCreatedAt()) + ->set("UPDATE_DATE", $product->getUpdatedAt()) + ->set("VERSION", $product->getVersion()) + ->set("VERSION_DATE", $product->getVersionCreatedAt()) + ->set("VERSION_AUTHOR", $product->getVersionCreatedBy()) ; $loopResult->addRow($loopResultRow); From 1105990a41d4e602f95ff0a9df6c429f5cb112a5 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Wed, 4 Sep 2013 11:33:24 +0200 Subject: [PATCH 02/39] event classes must extends ActionEvent --- .../Thelia/Config/Resources/routing/front.xml | 2 +- .../Core/Event/AddressCreateOrUpdateEvent.php | 2 +- core/lib/Thelia/Core/Event/CartEvent.php | 2 +- .../Event/CustomerCreateOrUpdateEvent.php | 2 +- core/lib/Thelia/Model/Address.php | 58 +++++++++++++++++++ 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/core/lib/Thelia/Config/Resources/routing/front.xml b/core/lib/Thelia/Config/Resources/routing/front.xml index 500fe7427..3d6078f58 100755 --- a/core/lib/Thelia/Config/Resources/routing/front.xml +++ b/core/lib/Thelia/Config/Resources/routing/front.xml @@ -29,7 +29,7 @@ - + Thelia\Controller\Front\CustomerAddressController::createAction diff --git a/core/lib/Thelia/Core/Event/AddressCreateOrUpdateEvent.php b/core/lib/Thelia/Core/Event/AddressCreateOrUpdateEvent.php index 1eee2acc8..d6dd6e3ed 100644 --- a/core/lib/Thelia/Core/Event/AddressCreateOrUpdateEvent.php +++ b/core/lib/Thelia/Core/Event/AddressCreateOrUpdateEvent.php @@ -32,7 +32,7 @@ use Thelia\Model\Customer; * @package Thelia\Core\Event * @author Manuel Raynaud */ -class AddressCreateOrUpdateEvent extends Event +class AddressCreateOrUpdateEvent extends ActionEvent { /** * @var string address label diff --git a/core/lib/Thelia/Core/Event/CartEvent.php b/core/lib/Thelia/Core/Event/CartEvent.php index 59e67e2bf..61d58e9d2 100755 --- a/core/lib/Thelia/Core/Event/CartEvent.php +++ b/core/lib/Thelia/Core/Event/CartEvent.php @@ -26,7 +26,7 @@ namespace Thelia\Core\Event; use Symfony\Component\EventDispatcher\Event; use Thelia\Model\Cart; -class CartEvent extends Event +class CartEvent extends ActionEvent { protected $cart; protected $quantity; diff --git a/core/lib/Thelia/Core/Event/CustomerCreateOrUpdateEvent.php b/core/lib/Thelia/Core/Event/CustomerCreateOrUpdateEvent.php index e7cf83b5c..9bee163ae 100755 --- a/core/lib/Thelia/Core/Event/CustomerCreateOrUpdateEvent.php +++ b/core/lib/Thelia/Core/Event/CustomerCreateOrUpdateEvent.php @@ -13,7 +13,7 @@ namespace Thelia\Core\Event; use Symfony\Component\EventDispatcher\Event; use Thelia\Model\Customer; -class CustomerCreateOrUpdateEvent extends Event { +class CustomerCreateOrUpdateEvent extends ActionEvent { //base parameters for creating new customer protected $title; diff --git a/core/lib/Thelia/Model/Address.php b/core/lib/Thelia/Model/Address.php index 58e6285ca..2501d5d1f 100755 --- a/core/lib/Thelia/Model/Address.php +++ b/core/lib/Thelia/Model/Address.php @@ -2,6 +2,7 @@ namespace Thelia\Model; +use Propel\Runtime\Connection\ConnectionInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Thelia\Model\Base\Address as BaseAddress; @@ -19,4 +20,61 @@ class Address extends BaseAddress { return $this->dispatcher; } + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + + } + } From 3cb4e6ff2ed5d76c7f6517d63db4bf52387bd7c7 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Wed, 4 Sep 2013 11:42:18 +0200 Subject: [PATCH 03/39] create Address::update method in controller --- .../Controller/Front/CustomerAddressController.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/lib/Thelia/Controller/Front/CustomerAddressController.php b/core/lib/Thelia/Controller/Front/CustomerAddressController.php index 4f44ce1d1..a2c426dac 100644 --- a/core/lib/Thelia/Controller/Front/CustomerAddressController.php +++ b/core/lib/Thelia/Controller/Front/CustomerAddressController.php @@ -50,7 +50,8 @@ class CustomerAddressController extends BaseFrontController $customer = $this->getSecurityContext()->getCustomerUser(); $form = $this->validateForm($addressCreate, "post"); - $event = $this->createAddressEvent($form->getData(), $customer); + $event = $this->createAddressEvent($form->getData()); + $event->setCustomer($customer); $this->dispatch(TheliaEvents::ADDRESS_CREATE, $event); $this->redirectSuccess($addressCreate); @@ -74,7 +75,12 @@ class CustomerAddressController extends BaseFrontController } } - protected function createAddressEvent($data, Customer $customer) + public function updateAction() + { + + } + + protected function createAddressEvent($data) { return new AddressCreateOrUpdateEvent( $data["label"], @@ -89,8 +95,7 @@ class CustomerAddressController extends BaseFrontController $data["country"], $data["cellpone"], $data["phone"], - $data["company"], - $customer + $data["company"] ); } } \ No newline at end of file From 02a1b5c6552a1f5d5f7e16f1131b1afa5170148e Mon Sep 17 00:00:00 2001 From: franck Date: Wed, 4 Sep 2013 15:45:46 +0200 Subject: [PATCH 04/39] Event harmonization with MRA --- core/lib/Thelia/Action/Cart.php | 2 +- core/lib/Thelia/Action/Category.php | 6 +- core/lib/Thelia/Action/Config.php | 10 +- core/lib/Thelia/Action/Currency.php | 40 +++++--- core/lib/Thelia/Action/Message.php | 6 +- core/lib/Thelia/Config/Resources/config.xml | 6 ++ .../Thelia/Config/Resources/routing/admin.xml | 12 ++- .../Thelia/Config/Resources/routing/front.xml | 2 +- .../Controller/Admin/BaseAdminController.php | 48 ++++----- .../Controller/Admin/ConfigController.php | 14 +-- .../Controller/Admin/CurrencyController.php | 56 ++++++++--- .../Controller/Admin/MessageController.php | 10 +- .../Event/CategoryChangePositionEvent.php | 61 +----------- ...hangeEvent.php => CategoryUpdateEvent.php} | 2 +- ...gChangeEvent.php => ConfigUpdateEvent.php} | 2 +- ...hangeEvent.php => CurrencyUpdateEvent.php} | 2 +- ...ChangeEvent.php => MessageUpdateEvent.php} | 2 +- core/lib/Thelia/Core/Event/TheliaEvents.php | 16 +-- .../Core/HttpFoundation/Session/Session.php | 60 ++++------- .../Core/Template/Element/BaseI18nLoop.php | 2 +- .../Thelia/Core/Template/Element/BaseLoop.php | 25 ----- core/lib/Thelia/Core/Template/Loop/Config.php | 3 - core/lib/Thelia/Model/Category.php | 14 +-- core/lib/Thelia/Model/Currency.php | 2 + core/lib/Thelia/Tools/URL.php | 99 +++++++++++++++---- templates/admin/default/assets/css/admin.less | 4 + templates/admin/default/currencies.html | 8 +- templates/admin/default/general_error.html | 2 +- templates/admin/default/messages.html | 8 +- templates/admin/default/variables.html | 8 +- 30 files changed, 271 insertions(+), 261 deletions(-) rename core/lib/Thelia/Core/Event/{CategoryChangeEvent.php => CategoryUpdateEvent.php} (97%) rename core/lib/Thelia/Core/Event/{ConfigChangeEvent.php => ConfigUpdateEvent.php} (98%) rename core/lib/Thelia/Core/Event/{CurrencyChangeEvent.php => CurrencyUpdateEvent.php} (97%) rename core/lib/Thelia/Core/Event/{MessageChangeEvent.php => MessageUpdateEvent.php} (98%) diff --git a/core/lib/Thelia/Action/Cart.php b/core/lib/Thelia/Action/Cart.php index 019911265..9203dc00d 100755 --- a/core/lib/Thelia/Action/Cart.php +++ b/core/lib/Thelia/Action/Cart.php @@ -143,7 +143,7 @@ class Cart extends BaseAction implements EventSubscriberInterface return array( "action.addArticle" => array("addItem", 128), "action.deleteArticle" => array("deleteItem", 128), - "action.changeArticle" => array("changeItem", 128), + "action.updateArticle" => array("changeItem", 128), ); } diff --git a/core/lib/Thelia/Action/Category.php b/core/lib/Thelia/Action/Category.php index 28ca2fc9e..1b0568cbe 100755 --- a/core/lib/Thelia/Action/Category.php +++ b/core/lib/Thelia/Action/Category.php @@ -248,9 +248,9 @@ class Category extends BaseAction implements EventSubscriberInterface TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128), TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128), - "action.changeCategoryPositionU" => array("changePositionUp", 128), - "action.changeCategoryPositionDown" => array("changePositionDown", 128), - "action.changeCategoryPosition" => array("changePosition", 128), + "action.updateCategoryPositionU" => array("changePositionUp", 128), + "action.updateCategoryPositionDown" => array("changePositionDown", 128), + "action.updateCategoryPosition" => array("changePosition", 128), ); } } diff --git a/core/lib/Thelia/Action/Config.php b/core/lib/Thelia/Action/Config.php index c7b016c63..e0a62f69d 100644 --- a/core/lib/Thelia/Action/Config.php +++ b/core/lib/Thelia/Action/Config.php @@ -31,7 +31,7 @@ use Thelia\Model\Config as ConfigModel; use Thelia\Core\Event\TheliaEvents; -use Thelia\Core\Event\ConfigChangeEvent; +use Thelia\Core\Event\ConfigUpdateEvent; use Thelia\Core\Event\ConfigCreateEvent; use Thelia\Core\Event\ConfigDeleteEvent; @@ -65,9 +65,9 @@ class Config extends BaseAction implements EventSubscriberInterface /** * Change a configuration entry value * - * @param ConfigChangeEvent $event + * @param ConfigUpdateEvent $event */ - public function setValue(ConfigChangeEvent $event) + public function setValue(ConfigUpdateEvent $event) { $search = ConfigQuery::create(); @@ -90,9 +90,9 @@ class Config extends BaseAction implements EventSubscriberInterface /** * Change a configuration entry * - * @param ConfigChangeEvent $event + * @param ConfigUpdateEvent $event */ - public function modify(ConfigChangeEvent $event) + public function modify(ConfigUpdateEvent $event) { $search = ConfigQuery::create(); diff --git a/core/lib/Thelia/Action/Currency.php b/core/lib/Thelia/Action/Currency.php index c0ca41d60..68cc5904a 100644 --- a/core/lib/Thelia/Action/Currency.php +++ b/core/lib/Thelia/Action/Currency.php @@ -31,11 +31,11 @@ use Thelia\Model\Currency as CurrencyModel; use Thelia\Core\Event\TheliaEvents; -use Thelia\Core\Event\CurrencyChangeEvent; +use Thelia\Core\Event\CurrencyUpdateEvent; use Thelia\Core\Event\CurrencyCreateEvent; use Thelia\Core\Event\CurrencyDeleteEvent; -use Thelia\Model\Map\CurrencyTableMap; use Thelia\Model\ConfigQuery; +use Thelia\Core\Event\CurrencyUpdatePositionEvent; class Currency extends BaseAction implements EventSubscriberInterface { @@ -67,9 +67,9 @@ class Currency extends BaseAction implements EventSubscriberInterface /** * Change a currency * - * @param CurrencyChangeEvent $event + * @param CurrencyUpdateEvent $event */ - public function update(CurrencyChangeEvent $event) + public function update(CurrencyUpdateEvent $event) { $search = CurrencyQuery::create(); @@ -93,9 +93,9 @@ class Currency extends BaseAction implements EventSubscriberInterface /** * Set the default currency * - * @param CurrencyChangeEvent $event + * @param CurrencyUpdateEvent $event */ - public function setDefault(CurrencyChangeEvent $event) + public function setDefault(CurrencyUpdateEvent $event) { $search = CurrencyQuery::create(); @@ -158,18 +158,34 @@ class Currency extends BaseAction implements EventSubscriberInterface } } + /** + * Changes position, selecting absolute ou relative change. + * + * @param CategoryChangePositionEvent $event + */ + public function updatePosition(CurrencyUpdatePositionEvent $event) + { + if (null !== $category = CurrencyQuery::create()->findOneById($event->getObjectId())) { + + if ($event->getMode() == BaseChangePositionEvent::POSITION_ABSOLUTE) + return $category->changeAbsolutePosition($event->getPosition()); + else + return $this->exchangePosition($event->getMode()); + } + } + /** * {@inheritDoc} */ public static function getSubscribedEvents() { return array( - TheliaEvents::CURRENCY_CREATE => array("create", 128), - TheliaEvents::CURRENCY_UPDATE => array("update", 128), - TheliaEvents::CURRENCY_DELETE => array("delete", 128), - TheliaEvents::CURRENCY_SET_DEFAULT => array("setDefault", 128), - TheliaEvents::CURRENCY_UPDATE_RATES => array("updateRates", 128), - + TheliaEvents::CURRENCY_CREATE => array("create", 128), + TheliaEvents::CURRENCY_UPDATE => array("update", 128), + TheliaEvents::CURRENCY_DELETE => array("delete", 128), + TheliaEvents::CURRENCY_SET_DEFAULT => array("setDefault", 128), + TheliaEvents::CURRENCY_UPDATE_RATES => array("updateRates", 128), + TheliaEvents::CURRENCY_UPDATE_POSITION => array("updatePosition", 128) ); } } diff --git a/core/lib/Thelia/Action/Message.php b/core/lib/Thelia/Action/Message.php index f2335bd82..5299efc99 100644 --- a/core/lib/Thelia/Action/Message.php +++ b/core/lib/Thelia/Action/Message.php @@ -31,7 +31,7 @@ use Thelia\Model\Message as MessageModel; use Thelia\Core\Event\TheliaEvents; -use Thelia\Core\Event\MessageChangeEvent; +use Thelia\Core\Event\MessageUpdateEvent; use Thelia\Core\Event\MessageCreateEvent; use Thelia\Core\Event\MessageDeleteEvent; @@ -65,9 +65,9 @@ class Message extends BaseAction implements EventSubscriberInterface /** * Change a message * - * @param MessageChangeEvent $event + * @param MessageUpdateEvent $event */ - public function modify(MessageChangeEvent $event) + public function modify(MessageUpdateEvent $event) { $search = MessageQuery::create(); diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index eda938f2b..58b6e53c2 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -85,6 +85,12 @@ + + + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 58645d531..9f56548ed 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -41,7 +41,7 @@ Thelia\Controller\Admin\ConfigController::defaultAction - + Thelia\Controller\Admin\ConfigController::changeValuesAction @@ -49,7 +49,7 @@ Thelia\Controller\Admin\ConfigController::createAction - + Thelia\Controller\Admin\ConfigController::changeAction @@ -71,7 +71,7 @@ Thelia\Controller\Admin\MessageController::createAction - + Thelia\Controller\Admin\MessageController::changeAction @@ -93,7 +93,7 @@ Thelia\Controller\Admin\CurrencyController::createAction - + Thelia\Controller\Admin\CurrencyController::changeAction @@ -113,6 +113,10 @@ Thelia\Controller\Admin\CurrencyController::deleteAction + + Thelia\Controller\Admin\CurrencyController::updatePositionAction + + diff --git a/core/lib/Thelia/Config/Resources/routing/front.xml b/core/lib/Thelia/Config/Resources/routing/front.xml index 500fe7427..0ab559873 100755 --- a/core/lib/Thelia/Config/Resources/routing/front.xml +++ b/core/lib/Thelia/Config/Resources/routing/front.xml @@ -40,7 +40,7 @@ cart - + Thelia\Controller\Front\CartController::deleteItem cart diff --git a/core/lib/Thelia/Controller/Admin/BaseAdminController.php b/core/lib/Thelia/Controller/Admin/BaseAdminController.php index 949344685..d5a09a709 100755 --- a/core/lib/Thelia/Controller/Admin/BaseAdminController.php +++ b/core/lib/Thelia/Controller/Admin/BaseAdminController.php @@ -85,10 +85,16 @@ class BaseAdminController extends BaseController /** * Return a general error page * + * @param mixed $message a message string, or an exception instance + * * @return \Symfony\Component\HttpFoundation\Response */ protected function errorPage($message) { + if ($message instanceof \Exception) { + $message = sprintf("Sorry, an error occured: %s", $message->getMessage()); + } + return $this->render('general_error', array( "error_message" => $message) ); @@ -172,20 +178,27 @@ class BaseAdminController extends BaseController } /** - * Get the current edition lang ID, checking if a change was requested in the current request + * Get the current edition lang ID, checking if a change was requested in the current request. */ - protected function getCurrentEditionLangId() { - return $this->getRequest()->get( - 'edit_language_id', - $this->getSession()->getAdminEditionLangId() - ); + protected function getCurrentEditionLang() { + + // Return the new language if a change is required. + if (null !== $edit_language_id = $this->getRequest()->get('edit_language_id', null)) { + + if (null !== $edit_language = LangQuery::create()->findOneById($edit_language_id)) { + return $edit_language; + } + } + + // Otherwise return the lang stored in session. + return $this->getSession()->getAdminEditionLang(); } /** - * A simple helper to get the current edition locale, from the session edition language ID + * A simple helper to get the current edition locale. */ protected function getCurrentEditionLocale() { - return LangQuery::create()->findOneById($this->getCurrentEditionLangId())->getLocale(); + return $this->getCurrentEditionLang()->getLocale(); } /** @@ -217,23 +230,14 @@ class BaseAdminController extends BaseController $session = $this->getSession(); - $edition_language = $this->getCurrentEditionLangId(); - - // Current back-office (not edition) language - $current_lang = LangQuery::create()->findOneById($session->getLangId()); - // Find the current edit language ID - $edition_language = LangQuery::create()->findOneById($this->getCurrentEditionLangId()); + $edition_language = $this->getCurrentEditionLang(); // Prepare common template variables $args = array_merge($args, array( - 'locale' => $session->getLocale(), - 'lang_code' => $session->getLang(), - 'lang_id' => $session->getLangId(), - - 'datetime_format' => $current_lang->getDateTimeFormat(), - 'date_format' => $current_lang->getDateFormat(), - 'time_format' => $current_lang->getTimeFormat(), + 'locale' => $session->getLang()->getLocale(), + 'lang_code' => $session->getLang()->getCode(), + 'lang_id' => $session->getLang()->getId(), 'edit_language_id' => $edition_language->getId(), 'edit_language_locale' => $edition_language->getLocale(), @@ -242,7 +246,7 @@ class BaseAdminController extends BaseController )); // Update the current edition language in session - $this->getSession()->setAdminEditionLangId($edition_language->getId()); + $this->getSession()->setAdminEditionLang($edition_language); // Render the template. try { diff --git a/core/lib/Thelia/Controller/Admin/ConfigController.php b/core/lib/Thelia/Controller/Admin/ConfigController.php index d6bcc09ab..b84368c2f 100644 --- a/core/lib/Thelia/Controller/Admin/ConfigController.php +++ b/core/lib/Thelia/Controller/Admin/ConfigController.php @@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin; use Thelia\Core\Event\ConfigDeleteEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Tools\URL; -use Thelia\Core\Event\ConfigChangeEvent; +use Thelia\Core\Event\ConfigUpdateEvent; use Thelia\Core\Event\ConfigCreateEvent; use Thelia\Log\Tlog; use Thelia\Form\Exception\FormValidationException; @@ -154,7 +154,7 @@ class ConfigController extends BaseAdminController public function changeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response; // Load the config object $config = ConfigQuery::create() @@ -196,7 +196,7 @@ class ConfigController extends BaseAdminController public function saveChangeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response; $message = false; @@ -214,7 +214,7 @@ class ConfigController extends BaseAdminController // Get the form field values $data = $form->getData(); - $changeEvent = new ConfigChangeEvent($data['id']); + $changeEvent = new ConfigUpdateEvent($data['id']); // Create and dispatch the change event $changeEvent @@ -241,7 +241,7 @@ class ConfigController extends BaseAdminController if ($this->getRequest()->get('save_mode') == 'stay') { $this->redirectToRoute( - "admin.configuration.variables.change", + "admin.configuration.variables.update", array('variable_id' => $variable_id) ); } @@ -284,13 +284,13 @@ class ConfigController extends BaseAdminController public function changeValuesAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response; $variables = $this->getRequest()->get('variable', array()); // Process all changed variables foreach($variables as $id => $value) { - $event = new ConfigChangeEvent($id); + $event = new ConfigUpdateEvent($id); $event->setValue($value); $this->dispatch(TheliaEvents::CONFIG_SETVALUE, $event); diff --git a/core/lib/Thelia/Controller/Admin/CurrencyController.php b/core/lib/Thelia/Controller/Admin/CurrencyController.php index 71814d05b..caa3d1bed 100644 --- a/core/lib/Thelia/Controller/Admin/CurrencyController.php +++ b/core/lib/Thelia/Controller/Admin/CurrencyController.php @@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin; use Thelia\Core\Event\CurrencyDeleteEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Tools\URL; -use Thelia\Core\Event\CurrencyChangeEvent; +use Thelia\Core\Event\CurrencyUpdateEvent; use Thelia\Core\Event\CurrencyCreateEvent; use Thelia\Log\Tlog; use Thelia\Form\Exception\FormValidationException; @@ -34,6 +34,7 @@ use Thelia\Core\Security\Exception\AuthorizationException; use Thelia\Model\CurrencyQuery; use Thelia\Form\CurrencyModificationForm; use Thelia\Form\CurrencyCreationForm; +use Thelia\Core\Event\CurrencyUpdatePositionEvent; /** * Manages currencies sent by mail @@ -124,7 +125,7 @@ class CurrencyController extends BaseAdminController } catch (\Exception $ex) { // Any other error - $error_msg = sprintf("Sorry, an error occured: %s", $ex->getMessage()); + $error_msg = $ex; } if ($error_msg !== false) { @@ -153,7 +154,7 @@ class CurrencyController extends BaseAdminController public function changeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; // Load the currency object $currency = CurrencyQuery::create() @@ -191,7 +192,7 @@ class CurrencyController extends BaseAdminController public function saveChangeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; $error_msg = false; @@ -209,7 +210,7 @@ class CurrencyController extends BaseAdminController // Get the form field values $data = $form->getData(); - $changeEvent = new CurrencyChangeEvent($data['id']); + $changeEvent = new CurrencyUpdateEvent($data['id']); // Create and dispatch the change event $changeEvent @@ -231,7 +232,7 @@ class CurrencyController extends BaseAdminController // just redirect to the edit page again. if ($this->getRequest()->get('save_mode') == 'stay') { $this->redirectToRoute( - "admin.configuration.currencies.change", + "admin.configuration.currencies.update", array('currency_id' => $currency_id) ); } @@ -245,7 +246,7 @@ class CurrencyController extends BaseAdminController } catch (\Exception $ex) { // Any other error - $error_msg = sprintf("Sorry, an error occured: %s", $ex->getMessage()); + $error_msg = $ex; } if ($error_msg !== false) { @@ -271,9 +272,9 @@ class CurrencyController extends BaseAdminController */ public function setDefaultAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; - $changeEvent = new CurrencyChangeEvent($this->getRequest()->get('currency_id', 0)); + $changeEvent = new CurrencyUpdateEvent($this->getRequest()->get('currency_id', 0)); // Create and dispatch the change event $changeEvent->setIsDefault(true); @@ -283,7 +284,7 @@ class CurrencyController extends BaseAdminController } catch (\Exception $ex) { // Any error - return $this->errorPage(sprintf("Sorry, an error occured: %s", $ex->getMessage())); + return $this->errorPage($ex); } $this->redirectToRoute('admin.configuration.currencies.default'); @@ -294,19 +295,50 @@ class CurrencyController extends BaseAdminController */ public function updateRatesAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; try { $this->dispatch(TheliaEvents::CURRENCY_UPDATE_RATES); } catch (\Exception $ex) { // Any error - return $this->errorPage(sprintf("Sorry, an error occured: %s", $ex->getMessage())); + return $this->errorPage($ex); } $this->redirectToRoute('admin.configuration.currencies.default'); } + /** + * Update currencyposition + */ + public function updatePositionAction() { + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response; + + try { + $id = $this->getRequest()->get('currency_id', 0); + $mode = $this->getRequest()->get('mode', null); + $position = $this->getRequest()->get('position', null); + + $event = new CurrencyUpdatePositionEvent(); + + $event + ->setObjectId($this->getRequest()->get('currency_id', 0)) + ->setPosition($this->getRequest()->get('position', 0)) + ->setMode($mode) + ; + + $this->dispatch(TheliaEvents::CURRENCY_UPDATE_POSITION, $event); + } + catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + + $this->redirectToRoute('admin.configuration.currencies.default'); + } + + /** * Delete a currency object * diff --git a/core/lib/Thelia/Controller/Admin/MessageController.php b/core/lib/Thelia/Controller/Admin/MessageController.php index 5cc3d2734..8b31e6b52 100644 --- a/core/lib/Thelia/Controller/Admin/MessageController.php +++ b/core/lib/Thelia/Controller/Admin/MessageController.php @@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin; use Thelia\Core\Event\MessageDeleteEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Tools\URL; -use Thelia\Core\Event\MessageChangeEvent; +use Thelia\Core\Event\MessageUpdateEvent; use Thelia\Core\Event\MessageCreateEvent; use Thelia\Log\Tlog; use Thelia\Form\Exception\FormValidationException; @@ -133,7 +133,7 @@ class MessageController extends BaseAdminController public function changeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.messages.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.messages.update")) return $response; // Load the message object $message = MessageQuery::create() @@ -173,7 +173,7 @@ class MessageController extends BaseAdminController public function saveChangeAction() { // Check current user authorization - if (null !== $response = $this->checkAuth("admin.configuration.messages.change")) return $response; + if (null !== $response = $this->checkAuth("admin.configuration.messages.update")) return $response; $message = false; @@ -191,7 +191,7 @@ class MessageController extends BaseAdminController // Get the form field values $data = $form->getData(); - $changeEvent = new MessageChangeEvent($data['id']); + $changeEvent = new MessageUpdateEvent($data['id']); // Create and dispatch the change event $changeEvent @@ -215,7 +215,7 @@ class MessageController extends BaseAdminController // just redirect to the edit page again. if ($this->getRequest()->get('save_mode') == 'stay') { $this->redirectToRoute( - "admin.configuration.messages.change", + "admin.configuration.messages.update", array('message_id' => $message_id) ); } diff --git a/core/lib/Thelia/Core/Event/CategoryChangePositionEvent.php b/core/lib/Thelia/Core/Event/CategoryChangePositionEvent.php index 94f131626..3a3dbb18f 100644 --- a/core/lib/Thelia/Core/Event/CategoryChangePositionEvent.php +++ b/core/lib/Thelia/Core/Event/CategoryChangePositionEvent.php @@ -22,64 +22,7 @@ /*************************************************************************************/ namespace Thelia\Core\Event; -use Thelia\Model\Category; -class CategoryChangePositionEvent extends ActionEvent +class CurrencyUpdatePositionEvent extends BaseUpdatePositionEvent { - const POSITION_UP = 1; - const POSITION_DOWN = 2; - const POSITION_ABSOLUTE = 3; - - protected $category_id; - protected $mode; - protected $position; - protected $category; - - public function __construct($category_id, $mode, $position = null) - { - $this->category_id = $category_id; - $this->mode = $mode; - $this->position = $position; - } - - public function getMode() - { - return $this->mode; - } - - public function setMode($mode) - { - $this->mode = $mode; - } - - public function getPosition() - { - return $this->position; - } - - public function setPosition($position) - { - $this->position = $position; - } - - public function getCategory() - { - return $this->category; - } - - public function setCategory($category) - { - $this->category = $category; - } - - public function getCategoryId() - { - return $this->category_id; - } - - public function setCategoryId($category_id) - { - $this->category_id = $category_id; - } - -} +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/CategoryChangeEvent.php b/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php similarity index 97% rename from core/lib/Thelia/Core/Event/CategoryChangeEvent.php rename to core/lib/Thelia/Core/Event/CategoryUpdateEvent.php index e8e183b3f..8103864c5 100644 --- a/core/lib/Thelia/Core/Event/CategoryChangeEvent.php +++ b/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php @@ -25,7 +25,7 @@ namespace Thelia\Core\Event; use Thelia\Model\Category; -class CategoryCreateEvent extends ActionEvent +class CategoryUpdateEvent extends ActionEvent { protected $category_id; protected $locale; diff --git a/core/lib/Thelia/Core/Event/ConfigChangeEvent.php b/core/lib/Thelia/Core/Event/ConfigUpdateEvent.php similarity index 98% rename from core/lib/Thelia/Core/Event/ConfigChangeEvent.php rename to core/lib/Thelia/Core/Event/ConfigUpdateEvent.php index e7da059ee..a73613699 100644 --- a/core/lib/Thelia/Core/Event/ConfigChangeEvent.php +++ b/core/lib/Thelia/Core/Event/ConfigUpdateEvent.php @@ -25,7 +25,7 @@ namespace Thelia\Core\Event; use Thelia\Model\Config; -class ConfigChangeEvent extends ConfigCreateEvent +class ConfigUpdateEvent extends ConfigCreateEvent { protected $config_id; diff --git a/core/lib/Thelia/Core/Event/CurrencyChangeEvent.php b/core/lib/Thelia/Core/Event/CurrencyUpdateEvent.php similarity index 97% rename from core/lib/Thelia/Core/Event/CurrencyChangeEvent.php rename to core/lib/Thelia/Core/Event/CurrencyUpdateEvent.php index 1e7677fee..044a93baa 100644 --- a/core/lib/Thelia/Core/Event/CurrencyChangeEvent.php +++ b/core/lib/Thelia/Core/Event/CurrencyUpdateEvent.php @@ -24,7 +24,7 @@ namespace Thelia\Core\Event; use Thelia\Model\Currency; -class CurrencyChangeEvent extends CurrencyCreateEvent +class CurrencyUpdateEvent extends CurrencyCreateEvent { protected $currency_id; protected $is_default; diff --git a/core/lib/Thelia/Core/Event/MessageChangeEvent.php b/core/lib/Thelia/Core/Event/MessageUpdateEvent.php similarity index 98% rename from core/lib/Thelia/Core/Event/MessageChangeEvent.php rename to core/lib/Thelia/Core/Event/MessageUpdateEvent.php index 1d36f1d30..1b3712266 100644 --- a/core/lib/Thelia/Core/Event/MessageChangeEvent.php +++ b/core/lib/Thelia/Core/Event/MessageUpdateEvent.php @@ -25,7 +25,7 @@ namespace Thelia\Core\Event; use Thelia\Model\Message; -class MessageChangeEvent extends MessageCreateEvent +class MessageUpdateEvent extends MessageCreateEvent { protected $message_id; diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 150edb748..c9a97f6d9 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -124,7 +124,7 @@ final class TheliaEvents /** * Change category position */ - const CATEGORY_CHANGE_POSITION = "action.changeCategoryPosition"; + const CATEGORY_CHANGE_POSITION = "action.updateCategoryPosition"; /** * Sent just after a successful insert of a new category in the database. @@ -220,12 +220,12 @@ final class TheliaEvents // -- Currencies management --------------------------------------------- - const CURRENCY_CREATE = "action.createCurrency"; - const CURRENCY_UPDATE = "action.updateCurrency"; - const CURRENCY_DELETE = "action.deleteCurrency"; - const CURRENCY_SET_DEFAULT = "action.setDefaultCurrency"; - const CURRENCY_UPDATE_RATES = "action.updateCurrencyRates"; - + const CURRENCY_CREATE = "action.createCurrency"; + const CURRENCY_UPDATE = "action.updateCurrency"; + const CURRENCY_DELETE = "action.deleteCurrency"; + const CURRENCY_SET_DEFAULT = "action.setDefaultCurrency"; + const CURRENCY_UPDATE_RATES = "action.updateCurrencyRates"; + const CURRENCY_UPDATE_POSITION = "action.updateCurrencyPosition"; const BEFORE_CREATECURRENCY = "action.before_createCurrency"; const AFTER_CREATECURRENCY = "action.after_createCurrency"; @@ -237,4 +237,4 @@ final class TheliaEvents const AFTER_DELETECURRENCY = "action.after_deleteCurrency"; -} +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php index 5f311ad0e..53c4c45e8 100755 --- a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php +++ b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php @@ -41,55 +41,29 @@ use Thelia\Model\Lang; */ class Session extends BaseSession { - // -- Language ------------------------------------------------------------ - - public function getLocale() - { - return $this->get("locale", "en_US"); - } - - public function setLocale($locale) - { - $this->set("locale", $locale); - - return $this; - } - /** * @return \Thelia\Model\Lang|null */ public function getLang() { - return $this->get("lang"); + return $this->get("thelia.current.lang", Lang::getDefaultLanguage()); } public function setLang(Lang $lang) { - $this->set("lang", $lang); + $this->set("thelia.current.lang", $lang); return $this; } - public function getLangId() + public function getAdminEditionLang() { - return $this->get("lang_id", Lang::getDefaultLanguage()->getId()); + return $this->get('thelia.admin.edition.lang', Lang::getDefaultLanguage()); } - public function setLangId($langId) + public function setAdminEditionLang($langId) { - $this->set("lang_id", $langId); - - return $this; - } - - public function getAdminEditionLangId() - { - return $this->get('admin.edition_language', Lang::getDefaultLanguage()->getId()); - } - - public function setAdminEditionLangId($langId) - { - $this->set('admin.edition_language', $langId); + $this->set('thelia.admin.edition.lang', $langId); return $this; } @@ -98,43 +72,43 @@ class Session extends BaseSession public function setCustomerUser(UserInterface $user) { - $this->set('customer_user', $user); + $this->set('thelia.customer_user', $user); return $this; } public function getCustomerUser() { - return $this->get('customer_user'); + return $this->get('thelia.customer_user'); } public function clearCustomerUser() { - return $this->remove('customer_user'); + return $this->remove('thelia.customer_user'); } // -- Admin user ----------------------------------------------------------- public function setAdminUser(UserInterface $user) { - $this->set('admin_user', $user); + $this->set('thelia.admin_user', $user); return $this; } public function getAdminUser() { - return $this->get('admin_user'); + return $this->get('thelia.admin_user'); } public function clearAdminUser() { - return $this->remove('admin_user'); + return $this->remove('thelia.admin_user'); } // -- Return page ---------------------------------------------------------- public function setReturnToUrl($url) { - $this->set('return_to_url', $url); + $this->set('thelia.return_to_url', $url); return $this; } @@ -144,7 +118,7 @@ class Session extends BaseSession */ public function getReturnToUrl() { - return $this->get('return_to_url', URL::getIndexPage()); + return $this->get('thelia.return_to_url', URL::getIndexPage()); } // -- Cart ------------------------------------------------------------------ @@ -156,7 +130,7 @@ class Session extends BaseSession */ public function getCart() { - $cart_id = $this->get("cart_id"); + $cart_id = $this->get("thelia.cart_id"); $cart = null; if ($cart_id) { $cart = CartQuery::create()->findPk($cart_id); @@ -193,7 +167,7 @@ class Session extends BaseSession */ public function setCart($cart_id) { - $this->set("cart_id", $cart_id); + $this->set("thelia.cart_id", $cart_id); return $this; } -} +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php b/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php index ef51d51b8..18eadce3c 100644 --- a/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php @@ -69,7 +69,7 @@ abstract class BaseI18nLoop extends BaseLoop $this->getBackend_context(), $this->getLang(), $search, - $this->request->getSession()->getLocale(), + $this->request->getSession()->getLang()->getLocale(), $columns, $foreignTable, $foreignKey, diff --git a/core/lib/Thelia/Core/Template/Element/BaseLoop.php b/core/lib/Thelia/Core/Template/Element/BaseLoop.php index befb53dc7..fc05b23a7 100755 --- a/core/lib/Thelia/Core/Template/Element/BaseLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseLoop.php @@ -235,31 +235,6 @@ abstract class BaseLoop } } - /** - * Setup ModelCriteria for proper i18n processing - * - * @param ModelCriteria $search the Propel Criteria to configure - * @param array $columns the i18n columns - * @param string $foreignTable the specified table (default to criteria table) - * @param string $foreignKey the foreign key in this table (default to criteria table) - * - * @return mixed the locale - */ - protected function configureI18nProcessing(ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false) { - - /* manage translations */ - return ModelCriteriaTools::getI18n( - $this->getBackend_context(), - $this->getLang(), - $search, - $this->request->getSession()->getLocale(), - $columns, - $foreignTable, - $foreignKey, - $forceReturn - ); - } - /** * * this function have to be implement in your own loop class. diff --git a/core/lib/Thelia/Core/Template/Loop/Config.php b/core/lib/Thelia/Core/Template/Loop/Config.php index f8819afef..a1bba2a98 100644 --- a/core/lib/Thelia/Core/Template/Loop/Config.php +++ b/core/lib/Thelia/Core/Template/Loop/Config.php @@ -167,9 +167,6 @@ class Config extends BaseI18nLoop ->set("CREATE_DATE" , $result->getCreatedAt()) ->set("UPDATE_DATE" , $result->getUpdatedAt()) - ->set("VERSION" , $result->getVersion()) - ->set("VERSION_DATE" , $result->getVersionCreatedAt()) - ->set("VERSION_AUTHOR" , $result->getVersionCreatedBy()) ; $loopResult->addRow($loopResultRow); diff --git a/core/lib/Thelia/Model/Category.php b/core/lib/Thelia/Model/Category.php index 475481c2b..10c61adcd 100755 --- a/core/lib/Thelia/Model/Category.php +++ b/core/lib/Thelia/Model/Category.php @@ -13,6 +13,8 @@ class Category extends BaseCategory { use \Thelia\Model\Tools\ModelEventDispatcherTrait; + use \Thelia\Model\Tools\PositionManagementTrait; + /** * @return int number of child for the current category */ @@ -46,18 +48,6 @@ class Category extends BaseCategory $this->save(); } - public function getNextPosition($parent) { - - $last = CategoryQuery::create() - ->filterByParent($parent) - ->orderByPosition(Criteria::DESC) - ->limit(1) - ->findOne() - ; - - return $last != null ? $last->getPosition() + 1 : 1; - } - /** * * count all products for current category and sub categories diff --git a/core/lib/Thelia/Model/Currency.php b/core/lib/Thelia/Model/Currency.php index fc1c86b67..20c36782d 100755 --- a/core/lib/Thelia/Model/Currency.php +++ b/core/lib/Thelia/Model/Currency.php @@ -11,6 +11,8 @@ class Currency extends BaseCurrency { use \Thelia\Model\Tools\ModelEventDispatcherTrait; + use \Thelia\Model\Tools\PositionManagementTrait; + /** * {@inheritDoc} */ diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index a527746ce..e6e3c32dd 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -23,38 +23,100 @@ namespace Thelia\Tools; -use Symfony\Component\HttpFoundation\Request; use Thelia\Model\ConfigQuery; use Thelia\Rewriting\RewritingResolver; use Thelia\Rewriting\RewritingRetriever; -class URL +use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Thelia\Core\HttpFoundation\Request; +use Symfony\Component\DependencyInjection\ContainerAware; + +class URL extends ContainerAware { + protected $container; + protected $request; + protected $resolver = null; protected $retriever = null; const PATH_TO_FILE = true; const WITH_INDEX_PAGE = false; - public function __construct() + private static $instance = null; + + public function __construct(Request $request) { + $this->request = $request; + $this->retriever = new RewritingRetriever(); $this->resolver = new RewritingResolver(); + + self::instance = $this; } - public static function getIndexPage() - { - return ConfigQuery::read('base_url', '/') . "index_dev.php"; // FIXME ! + /** + * Give this class a singleton behavior + */ + public static getInstance() { + + return self::$instance; } - public static function init() + /** + * Return the base URL, either the base_url defined in Config, or the URL + * of the current language, if 'one_domain_foreach_lang' is enabled. + * + * @return string the base URL, with a trailing '/' + */ + public function getBaseUrl() { - return new URL(); + // Check if we have a specific URL for each lang. + $one_domain_foreach_lang = ConfigQuery::read("one_domain_foreach_lang", false); + + if ($one_domain_foreach_lang == true) { + // If it's the case, get the current lang URL + $base_url = $this->request->getSession()->getLang()->getUrl(); + + $err_msg = 'base_url'; + } + else { + // Get the base URL + $base_url = ConfigQuery::read('base_url', null); + + $err_msg = sprintf('base_url for lang %s', $this->request->getSession()->getCode()); + } + + // Be sure that base-url starts with http, give up if it's not the case. + if (substr($base_url, 0, 4) != 'http') { + throw new \InvalidArgumentException("The 'base_url' configuration parameter shoud contains the URL of your shop, starting with http or https."); + } + + // Normalize the base_url + return rtrim($base_url, '/').'/'; + } + + /** + * @return string the index page, which is basically the base_url in prod environment. + */ + public function getIndexPage() + { + // Get the base URL + $base_url = $this->getBaseUrl(); + + // Check if we're in dev or prod + $env = $this->container->get(‘kernel’)->getEnvironment(); + + // For dev, add the proper page. + if ($env == 'dev') { + $base_url .= "index_dev.php"; + } + + return $base_url; } /** * Returns the Absolute URL for a given path relative to web root. By default, - * the index.php (or index_dev.php) script name is added to the URL, use + * the script name (index_dev.php) is added to the URL in dev_environment, use * $path_only = true to get a path without the index script. * * @param string $path the relative path @@ -63,7 +125,7 @@ class URL * * @return string The generated URL */ - public static function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE) + public function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE) { // Already absolute ? if (substr($path, 0, 4) != 'http') { @@ -72,9 +134,9 @@ class URL * @etienne : can't be done here for it's already done in ::viewUrl / ::adminViewUrl * @franck : should be done, as absoluteUrl() is sometimes called directly (see UrlGenerator::generateUrlFunction()) */ - $root = $path_only == self::PATH_TO_FILE ? ConfigQuery::read('base_url', '/') : self::getIndexPage(); - //$root = $path_only == self::PATH_TO_FILE ? ConfigQuery::read('base_url', '/') : ''; + $root = $path_only == self::PATH_TO_FILE ? $this->getBaseUrl() : $this->getIndexPage(); + // Normalize root path $base = rtrim($root, '/') . '/' . ltrim($path, '/'); } else $base = $path; @@ -90,6 +152,7 @@ class URL $sepChar = strstr($base, '?') === false ? '?' : '&'; if ('' !== $queryString = rtrim($queryString, "&")) $queryString = $sepChar . $queryString; + return $base . $queryString; } @@ -101,11 +164,11 @@ class URL * * @return string The generated URL */ - public static function adminViewUrl($viewName, array $parameters = array()) + public function adminViewUrl($viewName, array $parameters = array()) { - $path = sprintf("%s/admin/%s", self::getIndexPage(), $viewName); // FIXME ! view= should not be required, check routing parameters + $path = sprintf("%s/admin/%s", $this->getIndexPage(), $viewName); - return self::absoluteUrl($path, $parameters); + return $this->absoluteUrl($path, $parameters); } /** @@ -116,11 +179,11 @@ class URL * * @return string The generated URL */ - public static function viewUrl($viewName, array $parameters = array()) + public function viewUrl($viewName, array $parameters = array()) { $path = sprintf("?view=%s", $viewName); - return self::absoluteUrl($path, $parameters); + return $this>absoluteUrl($path, $parameters); } /** @@ -137,7 +200,7 @@ class URL $rewrittenUrl = $this->retriever->loadViewUrl($view, $viewLocale, $viewId); } - return $rewrittenUrl === null ? self::viewUrl($view, array($view . '_id' => $viewId, 'locale' => $viewLocale)) : $rewrittenUrl; + return $rewrittenUrl === null ? $this->viewUrl($view, array($view . '_id' => $viewId, 'locale' => $viewLocale)) : $rewrittenUrl; } public function retrieveCurrent(Request $request) diff --git a/templates/admin/default/assets/css/admin.less b/templates/admin/default/assets/css/admin.less index 0bc9fc274..4b5369a80 100755 --- a/templates/admin/default/assets/css/admin.less +++ b/templates/admin/default/assets/css/admin.less @@ -74,6 +74,10 @@ h4 { a { color: #e9720f; font-weight: bold; + + &.btn { + font-weight: normal; + } } // Bootstrap Adjustements ------------------------------------------------------ diff --git a/templates/admin/default/currencies.html b/templates/admin/default/currencies.html index a693214d7..6f5dc0c0d 100644 --- a/templates/admin/default/currencies.html +++ b/templates/admin/default/currencies.html @@ -122,7 +122,7 @@ {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} - {$NAME} + {$NAME} {/loop} {elseloop rel="can_change"} {$NAME} @@ -155,7 +155,7 @@
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.currencies.delete"} @@ -203,7 +203,7 @@ {form_field form=$form field='success_url'} {* on success, redirect to the edition page, _ID_ is replaced with the created currency ID, see controller *} - + {/form_field} {* We do not allow users to create secured currencies from here *} @@ -371,7 +371,7 @@ placement : 'left', success : function(response, newValue) { // The URL template - var url = "{url path='/admin/configuration/currencies/changePosition' currency_id='__ID__' position='__POS__'}"; + var url = "{url path='/admin/configuration/currencies/updatePosition' currency_id='__ID__' position='__POS__'}"; // Perform subtitutions url = url.replace('__ID__', $(this).data('id')) diff --git a/templates/admin/default/general_error.html b/templates/admin/default/general_error.html index dcbcc80ab..06f7b6608 100755 --- a/templates/admin/default/general_error.html +++ b/templates/admin/default/general_error.html @@ -14,7 +14,7 @@ {block name="error-message"}
{$error_message}
{/block} -

{intl l="Go to administration home"}

+

{intl l="Go to administration home"}

diff --git a/templates/admin/default/messages.html b/templates/admin/default/messages.html index 9a41e922e..1f6cb210e 100644 --- a/templates/admin/default/messages.html +++ b/templates/admin/default/messages.html @@ -20,7 +20,7 @@
-
+
";if(this.o.calendarWeeks){var c='';b+=c,this.picker.find(".datepicker-days thead tr:first-child").prepend(c)}for(;a'+k[this.o.language].daysMin[a++%7]+"";b+="",this.picker.find(".datepicker-days thead").append(b)},fillMonths:function(){for(var a="",b=0;12>b;)a+=''+k[this.o.language].monthsShort[b++]+"";this.picker.find(".datepicker-months td").html(a)},setRange:function(b){b&&b.length?this.range=a.map(b,function(a){return a.valueOf()}):delete this.range,this.fill()},getClassNames:function(b){var c=[],d=this.viewDate.getUTCFullYear(),e=this.viewDate.getUTCMonth(),f=this.date.valueOf(),g=new Date;return b.getUTCFullYear()d||b.getUTCFullYear()==d&&b.getUTCMonth()>e)&&c.push("new"),this.o.todayHighlight&&b.getUTCFullYear()==g.getFullYear()&&b.getUTCMonth()==g.getMonth()&&b.getUTCDate()==g.getDate()&&c.push("today"),f&&b.valueOf()==f&&c.push("active"),(b.valueOf()this.o.endDate||-1!==a.inArray(b.getUTCDay(),this.o.daysOfWeekDisabled))&&c.push("disabled"),this.range&&(b>this.range[0]&&b"),this.o.calendarWeeks)){var r=new Date(+m+864e5*((this.o.weekStart-m.getUTCDay()-7)%7)),s=new Date(+r+864e5*((11-r.getUTCDay())%7)),t=new Date(+(t=b(s.getUTCFullYear(),0,1))+864e5*((11-t.getUTCDay())%7)),u=(s-t)/864e5/7+1;q.push('")}p=this.getClassNames(m),p.push("day");var v=this.o.beforeShowDay(m);void 0===v?v={}:"boolean"==typeof v?v={enabled:v}:"string"==typeof v&&(v={classes:v}),v.enabled===!1&&p.push("disabled"),v.classes&&(p=p.concat(v.classes.split(/\s+/))),v.tooltip&&(c=v.tooltip),p=a.unique(p),q.push('"),m.getUTCDay()==this.o.weekEnd&&q.push(""),m.setUTCDate(m.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(q.join(""));var w=this.date&&this.date.getUTCFullYear(),x=this.picker.find(".datepicker-months").find("th:eq(1)").text(e).end().find("span").removeClass("active");w&&w==e&&x.eq(this.date.getUTCMonth()).addClass("active"),(g>e||e>i)&&x.addClass("disabled"),e==g&&x.slice(0,h).addClass("disabled"),e==i&&x.slice(j+1).addClass("disabled"),q="",e=10*parseInt(e/10,10);var y=this.picker.find(".datepicker-years").find("th:eq(1)").text(e+"-"+(e+9)).end().find("td");e-=1;for(var z=-1;11>z;z++)q+='e||e>i?" disabled":"")+'">'+e+"",e+=1;y.html(q)},updateNavArrows:function(){if(this._allow_update){var a=new Date(this.viewDate),b=a.getUTCFullYear(),c=a.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()&&c<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()&&c>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}}},click:function(c){c.preventDefault();var d=a(c.target).closest("span, td, th");if(1==d.length)switch(d[0].nodeName.toLowerCase()){case"th":switch(d[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var e=l.modes[this.viewMode].navStep*("prev"==d[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,e);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,e)}this.fill();break;case"today":var f=new Date;f=b(f.getFullYear(),f.getMonth(),f.getDate(),0,0,0),this.showMode(-2);var g="linked"==this.o.todayBtn?null:"view";this._setDate(f,g);break;case"clear":var h;this.isInput?h=this.element:this.component&&(h=this.element.find("input")),h&&h.val("").change(),this._trigger("changeDate"),this.update(),this.o.autoclose&&this.hide()}break;case"span":if(!d.is(".disabled")){if(this.viewDate.setUTCDate(1),d.is(".month")){var i=1,j=d.parent().find("span").index(d),k=this.viewDate.getUTCFullYear();this.viewDate.setUTCMonth(j),this._trigger("changeMonth",this.viewDate),1===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}else{var k=parseInt(d.text(),10)||0,i=1,j=0;this.viewDate.setUTCFullYear(k),this._trigger("changeYear",this.viewDate),2===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}this.showMode(-1),this.fill()}break;case"td":if(d.is(".day")&&!d.is(".disabled")){var i=parseInt(d.text(),10)||1,k=this.viewDate.getUTCFullYear(),j=this.viewDate.getUTCMonth();d.is(".old")?0===j?(j=11,k-=1):j-=1:d.is(".new")&&(11==j?(j=0,k+=1):j+=1),this._setDate(b(k,j,i,0,0,0,0))}}},_setDate:function(a,b){b&&"date"!=b||(this.date=new Date(a)),b&&"view"!=b||(this.viewDate=new Date(a)),this.fill(),this.setValue(),this._trigger("changeDate");var c;this.isInput?c=this.element:this.component&&(c=this.element.find("input")),c&&(c.change(),!this.o.autoclose||b&&"date"!=b||this.hide())},moveMonth:function(a,b){if(!b)return a;var c,d,e=new Date(a.valueOf()),f=e.getUTCDate(),g=e.getUTCMonth(),h=Math.abs(b);if(b=b>0?1:-1,1==h)d=-1==b?function(){return e.getUTCMonth()==g}:function(){return e.getUTCMonth()!=c},c=g+b,e.setUTCMonth(c),(0>c||c>11)&&(c=(c+12)%12);else{for(var i=0;h>i;i++)e=this.moveMonth(e,b);c=e.getUTCMonth(),e.setUTCDate(f),d=function(){return c!=e.getUTCMonth()}}for(;d();)e.setUTCDate(--f),e.setUTCMonth(c);return e},moveYear:function(a,b){return this.moveMonth(a,12*b)},dateWithinRange:function(a){return a>=this.o.startDate&&a<=this.o.endDate},keydown:function(a){if(this.picker.is(":not(:visible)"))return 27==a.keyCode&&this.show(),void 0;var b,c,d,e=!1;switch(a.keyCode){case 27:this.hide(),a.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;b=37==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 38:case 40:if(!this.o.keyboardNavigation)break;b=38==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+7*b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+7*b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 13:this.hide(),a.preventDefault();break;case 9:this.hide()}if(e){this._trigger("changeDate");var f;this.isInput?f=this.element:this.component&&(f=this.element.find("input")),f&&f.change()}},showMode:function(a){a&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+a))),this.picker.find(">div").hide().filter(".datepicker-"+l.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()}};var f=function(b,c){this.element=a(b),this.inputs=a.map(c.inputs,function(a){return a.jquery?a[0]:a}),delete c.inputs,a(this.inputs).datepicker(c).bind("changeDate",a.proxy(this.dateUpdated,this)),this.pickers=a.map(this.inputs,function(b){return a(b).data("datepicker")}),this.updateDates()};f.prototype={updateDates:function(){this.dates=a.map(this.pickers,function(a){return a.date}),this.updateRanges()},updateRanges:function(){var b=a.map(this.dates,function(a){return a.valueOf()});a.each(this.pickers,function(a,c){c.setRange(b)})},dateUpdated:function(b){var c=a(b.target).data("datepicker"),d=c.getUTCDate(),e=a.inArray(b.target,this.inputs),f=this.inputs.length;if(-1!=e){if(d=0&&dthis.dates[e])for(;f>e&&d>this.dates[e];)this.pickers[e++].setUTCDate(d);this.updateDates()}},remove:function(){a.map(this.pickers,function(a){a.remove()}),delete this.element.data().datepicker}};var g=a.fn.datepicker,h=a.fn.datepicker=function(b){var g=Array.apply(null,arguments);g.shift();var h;return this.each(function(){var j=a(this),k=j.data("datepicker"),l="object"==typeof b&&b;if(!k){var m=c(this,"date"),n=a.extend({},i,m,l),o=d(n.language),p=a.extend({},i,o,m,l);if(j.is(".input-daterange")||p.inputs){var q={inputs:p.inputs||j.find("input").toArray()};j.data("datepicker",k=new f(this,a.extend(p,q)))}else j.data("datepicker",k=new e(this,p))}return"string"==typeof b&&"function"==typeof k[b]&&(h=k[b].apply(k,g),void 0!==h)?!1:void 0}),void 0!==h?h:this},i=a.fn.datepicker.defaults={autoclose:!1,beforeShowDay:a.noop,calendarWeeks:!1,clearBtn:!1,daysOfWeekDisabled:[],endDate:1/0,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,rtl:!1,startDate:-1/0,startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0},j=a.fn.datepicker.locale_opts=["format","rtl","weekStart"];a.fn.datepicker.Constructor=e;var k=a.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},l={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(a){return 0===a%4&&0!==a%100||0===a%400},getDaysInMonth:function(a,b){return[31,l.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(a){var b=a.replace(this.validParts,"\0").split("\0"),c=a.match(this.validParts);if(!b||!b.length||!c||0===c.length)throw new Error("Invalid date format.");return{separators:b,parts:c}},parseDate:function(c,d,f){if(c instanceof Date)return c;if("string"==typeof d&&(d=l.parseFormat(d)),/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(c)){var g,h,i=/([\-+]\d+)([dmwy])/,j=c.match(/([\-+]\d+)([dmwy])/g);c=new Date;for(var m=0;mb;)b+=12;for(b%=12,a.setUTCMonth(b);a.getUTCMonth()!=b;)a.setUTCDate(a.getUTCDate()-1);return a},d:function(a,b){return a.setUTCDate(b)}};r.M=r.MM=r.mm=r.m,r.dd=r.d,c=b(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0);var s=d.parts.slice();if(j.length!=s.length&&(s=a(s).filter(function(b,c){return-1!==a.inArray(c,q)}).toArray()),j.length==s.length){for(var m=0,t=s.length;t>m;m++){if(n=parseInt(j[m],10),g=s[m],isNaN(n))switch(g){case"MM":o=a(k[f].months).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length);return a==b}),n=a.inArray(o[0],k[f].months)+1;break;case"M":o=a(k[f].monthsShort).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length); -return a==b}),n=a.inArray(o[0],k[f].monthsShort)+1}p[g]=n}for(var u,m=0;m=g;g++)f.length&&b.push(f.shift()),b.push(e[c.parts[g]]);return b.join("")},headTemplate:'',contTemplate:'',footTemplate:''};l.template='
@@ -49,7 +49,7 @@
{if ! $SECURED} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"} - {$NAME} + {$NAME} {/loop} {elseloop rel="can_change"} {$NAME} @@ -65,7 +65,7 @@ {if ! $SECURED}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.messages.delete"} @@ -116,7 +116,7 @@ {form_field form=$form field='success_url'} {* on success, redirect to the edition page, _ID_ is replaced with the created message ID, see controller *} - + {/form_field} {* We do not allow users to create secured messages from here *} diff --git a/templates/admin/default/variables.html b/templates/admin/default/variables.html index 9b61eca59..fe4554124 100644 --- a/templates/admin/default/variables.html +++ b/templates/admin/default/variables.html @@ -20,7 +20,7 @@
- +
- {loop name="category_list" type="category" visible="*" parent="{$current_category_id}" order="$category_order"} + {loop name="category_list" type="category" visible="*" parent=$current_category_id order=$category_order backend_context="1" lang=$lang_id} diff --git a/templates/admin/default/currencies.html b/templates/admin/default/currencies.html index 98fd36272..d446de776 100644 --- a/templates/admin/default/currencies.html +++ b/templates/admin/default/currencies.html @@ -155,7 +155,7 @@ '; - if(this.o.calendarWeeks){ - var cell = ''; - html += cell; - this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); - } - while (dowCnt < this.o.weekStart + 7) { - html += ''; - } - html += ''; - this.picker.find('.datepicker-days thead').append(html); - }, - - fillMonths: function(){ - var html = '', - i = 0; - while (i < 12) { - html += ''+dates[this.o.language].monthsShort[i++]+''; - } - this.picker.find('.datepicker-months td').html(html); - }, - - setRange: function(range){ - if (!range || !range.length) - delete this.range; - else - this.range = $.map(range, function(d){ return d.valueOf(); }); - this.fill(); - }, - - getClassNames: function(date){ - var cls = [], - year = this.viewDate.getUTCFullYear(), - month = this.viewDate.getUTCMonth(), - currentDate = this.date.valueOf(), - today = new Date(); - if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) { - cls.push('old'); - } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) { - cls.push('new'); - } - // Compare internal UTC date with local today, not UTC today - if (this.o.todayHighlight && - date.getUTCFullYear() == today.getFullYear() && - date.getUTCMonth() == today.getMonth() && - date.getUTCDate() == today.getDate()) { - cls.push('today'); - } - if (currentDate && date.valueOf() == currentDate) { - cls.push('active'); - } - if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate || - $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) { - cls.push('disabled'); - } - if (this.range){ - if (date > this.range[0] && date < this.range[this.range.length-1]){ - cls.push('range'); - } - if ($.inArray(date.valueOf(), this.range) != -1){ - cls.push('selected'); - } - } - return cls; - }, - - fill: function() { - var d = new Date(this.viewDate), - year = d.getUTCFullYear(), - month = d.getUTCMonth(), - startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, - startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, - endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, - endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, - currentDate = this.date && this.date.valueOf(), - tooltip; - this.picker.find('.datepicker-days thead th.datepicker-switch') - .text(dates[this.o.language].months[month]+' '+year); - this.picker.find('tfoot th.today') - .text(dates[this.o.language].today) - .toggle(this.o.todayBtn !== false); - this.picker.find('tfoot th.clear') - .text(dates[this.o.language].clear) - .toggle(this.o.clearBtn !== false); - this.updateNavArrows(); - this.fillMonths(); - var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), - day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); - prevMonth.setUTCDate(day); - prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7); - var nextMonth = new Date(prevMonth); - nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); - nextMonth = nextMonth.valueOf(); - var html = []; - var clsName; - while(prevMonth.valueOf() < nextMonth) { - if (prevMonth.getUTCDay() == this.o.weekStart) { - html.push(''); - if(this.o.calendarWeeks){ - // ISO 8601: First week contains first thursday. - // ISO also states week starts on Monday, but we can be more abstract here. - var - // Start of current week: based on weekstart/current date - ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), - // Thursday of this week - th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), - // First Thursday of year, year from thursday - yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), - // Calendar week: ms between thursdays, div ms per day, div 7 days - calWeek = (th - yth) / 864e5 / 7 + 1; - html.push(''); - - } - } - clsName = this.getClassNames(prevMonth); - clsName.push('day'); - - var before = this.o.beforeShowDay(prevMonth); - if (before === undefined) - before = {}; - else if (typeof(before) === 'boolean') - before = {enabled: before}; - else if (typeof(before) === 'string') - before = {classes: before}; - if (before.enabled === false) - clsName.push('disabled'); - if (before.classes) - clsName = clsName.concat(before.classes.split(/\s+/)); - if (before.tooltip) - tooltip = before.tooltip; - - clsName = $.unique(clsName); - html.push(''); - if (prevMonth.getUTCDay() == this.o.weekEnd) { - html.push(''); - } - prevMonth.setUTCDate(prevMonth.getUTCDate()+1); - } - this.picker.find('.datepicker-days tbody').empty().append(html.join('')); - var currentYear = this.date && this.date.getUTCFullYear(); - - var months = this.picker.find('.datepicker-months') - .find('th:eq(1)') - .text(year) - .end() - .find('span').removeClass('active'); - if (currentYear && currentYear == year) { - months.eq(this.date.getUTCMonth()).addClass('active'); - } - if (year < startYear || year > endYear) { - months.addClass('disabled'); - } - if (year == startYear) { - months.slice(0, startMonth).addClass('disabled'); - } - if (year == endYear) { - months.slice(endMonth+1).addClass('disabled'); - } - - html = ''; - year = parseInt(year/10, 10) * 10; - var yearCont = this.picker.find('.datepicker-years') - .find('th:eq(1)') - .text(year + '-' + (year + 9)) - .end() - .find('td'); - year -= 1; - for (var i = -1; i < 11; i++) { - html += ''+year+''; - year += 1; - } - yearCont.html(html); - }, - - updateNavArrows: function() { - if (!this._allow_update) return; - - var d = new Date(this.viewDate), - year = d.getUTCFullYear(), - month = d.getUTCMonth(); - switch (this.viewMode) { - case 0: - if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) { - this.picker.find('.prev').css({visibility: 'hidden'}); - } else { - this.picker.find('.prev').css({visibility: 'visible'}); - } - if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) { - this.picker.find('.next').css({visibility: 'hidden'}); - } else { - this.picker.find('.next').css({visibility: 'visible'}); - } - break; - case 1: - case 2: - if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) { - this.picker.find('.prev').css({visibility: 'hidden'}); - } else { - this.picker.find('.prev').css({visibility: 'visible'}); - } - if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) { - this.picker.find('.next').css({visibility: 'hidden'}); - } else { - this.picker.find('.next').css({visibility: 'visible'}); - } - break; - } - }, - - click: function(e) { - e.preventDefault(); - var target = $(e.target).closest('span, td, th'); - if (target.length == 1) { - switch(target[0].nodeName.toLowerCase()) { - case 'th': - switch(target[0].className) { - case 'datepicker-switch': - this.showMode(1); - break; - case 'prev': - case 'next': - var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); - switch(this.viewMode){ - case 0: - this.viewDate = this.moveMonth(this.viewDate, dir); - break; - case 1: - case 2: - this.viewDate = this.moveYear(this.viewDate, dir); - break; - } - this.fill(); - break; - case 'today': - var date = new Date(); - date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); - - this.showMode(-2); - var which = this.o.todayBtn == 'linked' ? null : 'view'; - this._setDate(date, which); - break; - case 'clear': - var element; - if (this.isInput) - element = this.element; - else if (this.component) - element = this.element.find('input'); - if (element) - element.val("").change(); - this._trigger('changeDate'); - this.update(); - if (this.o.autoclose) - this.hide(); - break; - } - break; - case 'span': - if (!target.is('.disabled')) { - this.viewDate.setUTCDate(1); - if (target.is('.month')) { - var day = 1; - var month = target.parent().find('span').index(target); - var year = this.viewDate.getUTCFullYear(); - this.viewDate.setUTCMonth(month); - this._trigger('changeMonth', this.viewDate); - if (this.o.minViewMode === 1) { - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - } else { - var year = parseInt(target.text(), 10)||0; - var day = 1; - var month = 0; - this.viewDate.setUTCFullYear(year); - this._trigger('changeYear', this.viewDate); - if (this.o.minViewMode === 2) { - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - } - this.showMode(-1); - this.fill(); - } - break; - case 'td': - if (target.is('.day') && !target.is('.disabled')){ - var day = parseInt(target.text(), 10)||1; - var year = this.viewDate.getUTCFullYear(), - month = this.viewDate.getUTCMonth(); - if (target.is('.old')) { - if (month === 0) { - month = 11; - year -= 1; - } else { - month -= 1; - } - } else if (target.is('.new')) { - if (month == 11) { - month = 0; - year += 1; - } else { - month += 1; - } - } - this._setDate(UTCDate(year, month, day,0,0,0,0)); - } - break; - } - } - }, - - _setDate: function(date, which){ - if (!which || which == 'date') - this.date = new Date(date); - if (!which || which == 'view') - this.viewDate = new Date(date); - this.fill(); - this.setValue(); - this._trigger('changeDate'); - var element; - if (this.isInput) { - element = this.element; - } else if (this.component){ - element = this.element.find('input'); - } - if (element) { - element.change(); - if (this.o.autoclose && (!which || which == 'date')) { - this.hide(); - } - } - }, - - moveMonth: function(date, dir){ - if (!dir) return date; - var new_date = new Date(date.valueOf()), - day = new_date.getUTCDate(), - month = new_date.getUTCMonth(), - mag = Math.abs(dir), - new_month, test; - dir = dir > 0 ? 1 : -1; - if (mag == 1){ - test = dir == -1 - // If going back one month, make sure month is not current month - // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) - ? function(){ return new_date.getUTCMonth() == month; } - // If going forward one month, make sure month is as expected - // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) - : function(){ return new_date.getUTCMonth() != new_month; }; - new_month = month + dir; - new_date.setUTCMonth(new_month); - // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 - if (new_month < 0 || new_month > 11) - new_month = (new_month + 12) % 12; - } else { - // For magnitudes >1, move one month at a time... - for (var i=0; i= this.o.startDate && date <= this.o.endDate; - }, - - keydown: function(e){ - if (this.picker.is(':not(:visible)')){ - if (e.keyCode == 27) // allow escape to hide and re-show picker - this.show(); - return; - } - var dateChanged = false, - dir, day, month, - newDate, newViewDate; - switch(e.keyCode){ - case 27: // escape - this.hide(); - e.preventDefault(); - break; - case 37: // left - case 39: // right - if (!this.o.keyboardNavigation) break; - dir = e.keyCode == 37 ? -1 : 1; - if (e.ctrlKey){ - newDate = this.moveYear(this.date, dir); - newViewDate = this.moveYear(this.viewDate, dir); - } else if (e.shiftKey){ - newDate = this.moveMonth(this.date, dir); - newViewDate = this.moveMonth(this.viewDate, dir); - } else { - newDate = new Date(this.date); - newDate.setUTCDate(this.date.getUTCDate() + dir); - newViewDate = new Date(this.viewDate); - newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); - } - if (this.dateWithinRange(newDate)){ - this.date = newDate; - this.viewDate = newViewDate; - this.setValue(); - this.update(); - e.preventDefault(); - dateChanged = true; - } - break; - case 38: // up - case 40: // down - if (!this.o.keyboardNavigation) break; - dir = e.keyCode == 38 ? -1 : 1; - if (e.ctrlKey){ - newDate = this.moveYear(this.date, dir); - newViewDate = this.moveYear(this.viewDate, dir); - } else if (e.shiftKey){ - newDate = this.moveMonth(this.date, dir); - newViewDate = this.moveMonth(this.viewDate, dir); - } else { - newDate = new Date(this.date); - newDate.setUTCDate(this.date.getUTCDate() + dir * 7); - newViewDate = new Date(this.viewDate); - newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); - } - if (this.dateWithinRange(newDate)){ - this.date = newDate; - this.viewDate = newViewDate; - this.setValue(); - this.update(); - e.preventDefault(); - dateChanged = true; - } - break; - case 13: // enter - this.hide(); - e.preventDefault(); - break; - case 9: // tab - this.hide(); - break; - } - if (dateChanged){ - this._trigger('changeDate'); - var element; - if (this.isInput) { - element = this.element; - } else if (this.component){ - element = this.element.find('input'); - } - if (element) { - element.change(); - } - } - }, - - showMode: function(dir) { - if (dir) { - this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir)); - } - /* - vitalets: fixing bug of very special conditions: - jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. - Method show() does not set display css correctly and datepicker is not shown. - Changed to .css('display', 'block') solve the problem. - See https://github.com/vitalets/x-editable/issues/37 - - In jquery 1.7.2+ everything works fine. - */ - //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); - this.updateNavArrows(); - } - }; - - var DateRangePicker = function(element, options){ - this.element = $(element); - this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; }); - delete options.inputs; - - $(this.inputs) - .datepicker(options) - .bind('changeDate', $.proxy(this.dateUpdated, this)); - - this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); }); - this.updateDates(); - }; - DateRangePicker.prototype = { - updateDates: function(){ - this.dates = $.map(this.pickers, function(i){ return i.date; }); - this.updateRanges(); - }, - updateRanges: function(){ - var range = $.map(this.dates, function(d){ return d.valueOf(); }); - $.each(this.pickers, function(i, p){ - p.setRange(range); - }); - }, - dateUpdated: function(e){ - var dp = $(e.target).data('datepicker'), - new_date = dp.getUTCDate(), - i = $.inArray(e.target, this.inputs), - l = this.inputs.length; - if (i == -1) return; - - if (new_date < this.dates[i]){ - // Date being moved earlier/left - while (i>=0 && new_date < this.dates[i]){ - this.pickers[i--].setUTCDate(new_date); - } - } - else if (new_date > this.dates[i]){ - // Date being moved later/right - while (i this.dates[i]){ - this.pickers[i++].setUTCDate(new_date); - } - } - this.updateDates(); - }, - remove: function(){ - $.map(this.pickers, function(p){ p.remove(); }); - delete this.element.data().datepicker; - } - }; - - function opts_from_el(el, prefix){ - // Derive options from element data-attrs - var data = $(el).data(), - out = {}, inkey, - replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'), - prefix = new RegExp('^' + prefix.toLowerCase()); - for (var key in data) - if (prefix.test(key)){ - inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); }); - out[inkey] = data[key]; - } - return out; - } - - function opts_from_locale(lang){ - // Derive options from locale plugins - var out = {}; - // Check if "de-DE" style date is available, if not language should - // fallback to 2 letter code eg "de" - if (!dates[lang]) { - lang = lang.split('-')[0] - if (!dates[lang]) - return; - } - var d = dates[lang]; - $.each(locale_opts, function(i,k){ - if (k in d) - out[k] = d[k]; - }); - return out; - } - - var old = $.fn.datepicker; - var datepicker = $.fn.datepicker = function ( option ) { - var args = Array.apply(null, arguments); - args.shift(); - var internal_return, - this_return; - this.each(function () { - var $this = $(this), - data = $this.data('datepicker'), - options = typeof option == 'object' && option; - if (!data) { - var elopts = opts_from_el(this, 'date'), - // Preliminary otions - xopts = $.extend({}, defaults, elopts, options), - locopts = opts_from_locale(xopts.language), - // Options priority: js args, data-attrs, locales, defaults - opts = $.extend({}, defaults, locopts, elopts, options); - if ($this.is('.input-daterange') || opts.inputs){ - var ropts = { - inputs: opts.inputs || $this.find('input').toArray() - }; - $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts)))); - } - else{ - $this.data('datepicker', (data = new Datepicker(this, opts))); - } - } - if (typeof option == 'string' && typeof data[option] == 'function') { - internal_return = data[option].apply(data, args); - if (internal_return !== undefined) - return false; - } - }); - if (internal_return !== undefined) - return internal_return; - else - return this; - }; - - var defaults = $.fn.datepicker.defaults = { - autoclose: false, - beforeShowDay: $.noop, - calendarWeeks: false, - clearBtn: false, - daysOfWeekDisabled: [], - endDate: Infinity, - forceParse: true, - format: 'mm/dd/yyyy', - keyboardNavigation: true, - language: 'en', - minViewMode: 0, - rtl: false, - startDate: -Infinity, - startView: 0, - todayBtn: false, - todayHighlight: false, - weekStart: 0 - }; - var locale_opts = $.fn.datepicker.locale_opts = [ - 'format', - 'rtl', - 'weekStart' - ]; - $.fn.datepicker.Constructor = Datepicker; - var dates = $.fn.datepicker.dates = { - en: { - days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], - daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], - months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], - today: "Today", - clear: "Clear" - } - }; - - var DPGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'Month', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'FullYear', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'FullYear', - navStep: 10 - }], - isLeapYear: function (year) { - return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); - }, - getDaysInMonth: function (year, month) { - return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - }, - validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, - nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, - parseFormat: function(format){ - // IE treats \0 as a string end in inputs (truncating the value), - // so it's a bad format delimiter, anyway - var separators = format.replace(this.validParts, '\0').split('\0'), - parts = format.match(this.validParts); - if (!separators || !separators.length || !parts || parts.length === 0){ - throw new Error("Invalid date format."); - } - return {separators: separators, parts: parts}; - }, - parseDate: function(date, format, language) { - if (date instanceof Date) return date; - if (typeof format === 'string') - format = DPGlobal.parseFormat(format); - if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { - var part_re = /([\-+]\d+)([dmwy])/, - parts = date.match(/([\-+]\d+)([dmwy])/g), - part, dir; - date = new Date(); - for (var i=0; i'+ - ''+ - ''+ - ''+ - ''+ - ''+ - '', - contTemplate: '', - footTemplate: '' - }; - DPGlobal.template = '
'+ - '
'+ - '
@@ -77,7 +77,7 @@
{if ! $SECURED} {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"} - {$NAME} + {$NAME} {/loop} {elseloop rel="can_change"} {$NAME} @@ -103,7 +103,7 @@ {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.variables.delete"} @@ -144,7 +144,7 @@ {form_field form=$form field='success_url'} {* on success, redirect to the edition page, _ID_ is replaced with the created variable ID, see controller *} - + {/form_field} {* We do not allow users to create hidden or secured variables from here *} From ceb02841e1273b7489c710ef47e97f12cbd831ca Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Wed, 4 Sep 2013 17:52:58 +0200 Subject: [PATCH 05/39] validate create and update address in front context --- core/lib/Thelia/Config/Resources/action.xml | 5 + core/lib/Thelia/Config/Resources/config.xml | 3 + .../Thelia/Config/Resources/routing/front.xml | 16 ++- ...ssController.php => AddressController.php} | 95 +++++++++++++---- .../Controller/Front/BaseFrontController.php | 1 + .../Controller/Front/DefaultController.php | 7 +- core/lib/Thelia/Core/Event/AddressEvent.php | 54 ++++++++++ core/lib/Thelia/Core/Event/TheliaEvents.php | 16 ++- .../lib/Thelia/Core/Template/Loop/Address.php | 7 +- ...{AddressForm.php => AddressCreateForm.php} | 7 +- core/lib/Thelia/Form/AddressUpdateForm.php | 69 ++++++++++++ core/lib/Thelia/Model/Address.php | 24 ++--- core/lib/Thelia/Model/Customer.php | 8 +- .../Thelia.Core.Event.TheliaEvents.html | 12 +-- .../api/files/Action/Category.php.txt | 4 +- .../api/files/Core/Event/TheliaEvents.php.txt | 4 +- .../api/files/Model/Customer.php.txt | 4 +- templates/default/address.html | 99 +++++++++++++++++ templates/default/address_edit.html | 100 ++++++++++++++++++ templates/default/address_list.html | 11 ++ templates/default/connexion.html | 1 - 21 files changed, 482 insertions(+), 65 deletions(-) rename core/lib/Thelia/Controller/Front/{CustomerAddressController.php => AddressController.php} (55%) create mode 100644 core/lib/Thelia/Core/Event/AddressEvent.php rename core/lib/Thelia/Form/{AddressForm.php => AddressCreateForm.php} (97%) create mode 100644 core/lib/Thelia/Form/AddressUpdateForm.php create mode 100644 templates/default/address.html create mode 100644 templates/default/address_edit.html create mode 100644 templates/default/address_list.html diff --git a/core/lib/Thelia/Config/Resources/action.xml b/core/lib/Thelia/Config/Resources/action.xml index 7eea2e005..5bf4cbab8 100755 --- a/core/lib/Thelia/Config/Resources/action.xml +++ b/core/lib/Thelia/Config/Resources/action.xml @@ -22,6 +22,11 @@ + + + + + diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index eda938f2b..6011e9c98 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -43,6 +43,9 @@ + + + diff --git a/core/lib/Thelia/Config/Resources/routing/front.xml b/core/lib/Thelia/Config/Resources/routing/front.xml index 3d6078f58..3ccf9e557 100755 --- a/core/lib/Thelia/Config/Resources/routing/front.xml +++ b/core/lib/Thelia/Config/Resources/routing/front.xml @@ -30,7 +30,17 @@ - Thelia\Controller\Front\CustomerAddressController::createAction + Thelia\Controller\Front\AddressController::createAction + address + + + + Thelia\Controller\Front\DefaultController::noAction + address_edit + + + + Thelia\Controller\Front\AddressController::updateAction @@ -50,7 +60,7 @@ cart - + diff --git a/core/lib/Thelia/Controller/Front/CustomerAddressController.php b/core/lib/Thelia/Controller/Front/AddressController.php similarity index 55% rename from core/lib/Thelia/Controller/Front/CustomerAddressController.php rename to core/lib/Thelia/Controller/Front/AddressController.php index a2c426dac..8568236f6 100644 --- a/core/lib/Thelia/Controller/Front/CustomerAddressController.php +++ b/core/lib/Thelia/Controller/Front/AddressController.php @@ -24,33 +24,41 @@ namespace Thelia\Controller\Front; use Thelia\Core\Event\AddressCreateOrUpdateEvent; use Thelia\Core\Event\TheliaEvents; -use Thelia\Form\AddressForm; +use Thelia\Form\AddressCreateForm; +use Thelia\Form\AddressUpdateForm; use Thelia\Form\Exception\FormValidationException; +use Thelia\Model\Base\AddressQuery; use Thelia\Model\Customer; use Thelia\Tools\URL; /** - * Class CustomerAddressController + * Class AddressController * @package Thelia\Controller\Front * @author Manuel Raynaud */ -class CustomerAddressController extends BaseFrontController +class AddressController extends BaseFrontController { + /** + * Create controller. + * Check if customer is logged in + * + * Dispatch TheliaEvents::ADDRESS_CREATE event + */ public function createAction() { if ($this->getSecurityContext()->hasCustomerUser() === false) { $this->redirect(URL::getIndexPage()); } - $addressCreate = new AddressForm($this->getRequest()); + $addressCreate = new AddressCreateForm($this->getRequest()); try { $customer = $this->getSecurityContext()->getCustomerUser(); $form = $this->validateForm($addressCreate, "post"); - $event = $this->createAddressEvent($form->getData()); + $event = $this->createAddressEvent($form); $event->setCustomer($customer); $this->dispatch(TheliaEvents::ADDRESS_CREATE, $event); @@ -77,25 +85,74 @@ class CustomerAddressController extends BaseFrontController public function updateAction() { + $request = $this->getRequest(); + if ($this->getSecurityContext()->hasCustomerUser() === false) { + $this->redirectToRoute("home"); + } + + if(null === $address_id = $request->get("address_id")) { + $this->redirectToRoute("home"); + } + + $addressUpdate = new AddressUpdateForm($request); + + try { + $customer = $this->getSecurityContext()->getCustomerUser(); + + $form = $this->validateForm($addressUpdate); + + $address = AddressQuery::create()->findPk($address_id); + + if (null === $address) { + $this->redirectToRoute("home"); + } + + if($address->getCustomer()->getId() != $customer->getId()) { + $this->redirectToRoute("home"); + } + + $event = $this->createAddressEvent($form); + $event->setAddress($address); + + $this->dispatch(TheliaEvents::ADDRESS_UPDATE, $event); + + $this->redirectSuccess($addressUpdate); + }catch (FormValidationException $e) { + $message = sprintf("Please check your input: %s", $e->getMessage()); + } + catch (\Exception $e) { + $message = sprintf("Sorry, an error occured: %s", $e->getMessage()); + } + + if ($message !== false) { + \Thelia\Log\Tlog::getInstance()->error(sprintf("Error during address creation process : %s", $message)); + + $addressUpdate->setErrorMessage($message); + + $this->getParserContext() + ->addForm($addressUpdate) + ->setGeneralError($message) + ; + } } - protected function createAddressEvent($data) + protected function createAddressEvent($form) { return new AddressCreateOrUpdateEvent( - $data["label"], - $data["title"], - $data["firstname"], - $data["lastname"], - $data["address1"], - $data["address2"], - $data["address3"], - $data["zipcode"], - $data["city"], - $data["country"], - $data["cellpone"], - $data["phone"], - $data["company"] + $form->get("label")->getData(), + $form->get("title")->getData(), + $form->get("firstname")->getData(), + $form->get("lastname")->getData(), + $form->get("address1")->getData(), + $form->get("address2")->getData(), + $form->get("address3")->getData(), + $form->get("zipcode")->getData(), + $form->get("city")->getData(), + $form->get("country")->getData(), + $form->get("cellphone")->getData(), + $form->get("phone")->getData(), + $form->get("company")->getData() ); } } \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Front/BaseFrontController.php b/core/lib/Thelia/Controller/Front/BaseFrontController.php index b6d4a6f93..40296f361 100755 --- a/core/lib/Thelia/Controller/Front/BaseFrontController.php +++ b/core/lib/Thelia/Controller/Front/BaseFrontController.php @@ -23,6 +23,7 @@ namespace Thelia\Controller\Front; use Thelia\Controller\BaseController; +use Thelia\Tools\URL; class BaseFrontController extends BaseController { diff --git a/core/lib/Thelia/Controller/Front/DefaultController.php b/core/lib/Thelia/Controller/Front/DefaultController.php index d9c5a681a..2b1792640 100755 --- a/core/lib/Thelia/Controller/Front/DefaultController.php +++ b/core/lib/Thelia/Controller/Front/DefaultController.php @@ -56,13 +56,16 @@ class DefaultController extends BaseFrontController } } + $view = null; + if (! $view = $request->query->get('view')) { - $view = "index"; if ($request->request->has('view')) { $view = $request->request->get('view'); } } + if(!is_null($view)) { + $request->attributes->set('_view', $view); + } - $request->attributes->set('_view', $view); } } diff --git a/core/lib/Thelia/Core/Event/AddressEvent.php b/core/lib/Thelia/Core/Event/AddressEvent.php new file mode 100644 index 000000000..5167108fd --- /dev/null +++ b/core/lib/Thelia/Core/Event/AddressEvent.php @@ -0,0 +1,54 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; +use Symfony\Component\EventDispatcher\Event; +use Thelia\Model\Address; + + +/** + * Class AddressEvent + * @package Thelia\Core\Event + * @author Manuel Raynaud + */ +class AddressEvent extends ActionEvent +{ + /** + * @var \Thelia\Model\Address + */ + protected $address; + + function __construct(Address $address) + { + $this->address = $address; + } + + + /** + * @return \Thelia\Model\Address + */ + public function getAddress() + { + return $this->address; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 150edb748..8e3156cfc 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -88,12 +88,13 @@ final class TheliaEvents /** * Sent once the customer change form has been successfully validated, and before customer update in the database. */ - const BEFORE_CHANGECUSTOMER = "action.before_updateCustomer"; + const BEFORE_UPDATECUSTOMER = "action.before_updateCustomer"; /** * Sent just after a successful update of a customer in the database. */ - const AFTER_CHANGECUSTOMER = "action.after_updateCustomer"; + const AFTER_UPDATECUSTOMER = "action.after_updateCustomer"; + // -- ADDRESS MANAGEMENT --------------------------------------------------------- /** * sent for address creation */ @@ -104,6 +105,17 @@ final class TheliaEvents */ const ADDRESS_UPDATE = "action.updateAddress"; + const BEFORE_CREATEADDRESS = "action.before_createAddress"; + const AFTER_CREATEADDRESS = "action.after_createAddress"; + + const BEFORE_UPDATEADDRESS = "action.before_updateAddress"; + const AFTER_UPDATEADDRESS = "action.after_updateAddress"; + + const BEFORE_DELETEADDRESS = "action.before_deleteAddress"; + const AFTER_DELETEADDRESS = "action.after_deleteAddress"; + + // -- END ADDRESS MANAGEMENT --------------------------------------------------------- + /** * Sent once the category creation form has been successfully validated, and before category insertion in the database. */ diff --git a/core/lib/Thelia/Core/Template/Loop/Address.php b/core/lib/Thelia/Core/Template/Loop/Address.php index 43bbbaefb..329890e07 100755 --- a/core/lib/Thelia/Core/Template/Loop/Address.php +++ b/core/lib/Thelia/Core/Template/Loop/Address.php @@ -61,7 +61,7 @@ class Address extends BaseLoop ), 'current' ), - Argument::createBooleanTypeArgument('default'), + Argument::createBooleanTypeArgument('default', false), Argument::createIntListTypeArgument('exclude') ); } @@ -96,10 +96,9 @@ class Address extends BaseLoop $default = $this->getDefault(); + if ($default === true) { $search->filterByIsDefault(1, Criteria::EQUAL); - } elseif ($default === false) { - $search->filterByIsDefault(1, Criteria::NOT_EQUAL); } $exclude = $this->getExclude(); @@ -116,7 +115,7 @@ class Address extends BaseLoop $loopResultRow = new LoopResultRow(); $loopResultRow ->set("ID", $address->getId()) - ->set("NAME", $address->getName()) + ->set("LABEL", $address->getLabel()) ->set("CUSTOMER", $address->getCustomerId()) ->set("TITLE", $address->getTitleId()) ->set("COMPANY", $address->getCompany()) diff --git a/core/lib/Thelia/Form/AddressForm.php b/core/lib/Thelia/Form/AddressCreateForm.php similarity index 97% rename from core/lib/Thelia/Form/AddressForm.php rename to core/lib/Thelia/Form/AddressCreateForm.php index b98577927..3f953fe38 100644 --- a/core/lib/Thelia/Form/AddressForm.php +++ b/core/lib/Thelia/Form/AddressCreateForm.php @@ -26,11 +26,11 @@ use Symfony\Component\Validator\Constraints\NotBlank; /** - * Class AddressForm + * Class AddressCreateForm * @package Thelia\Form * @author Manuel Raynaud */ -class AddressForm extends BaseForm +class AddressCreateForm extends BaseForm { /** @@ -60,7 +60,8 @@ class AddressForm extends BaseForm "constraints" => array( new NotBlank() ), - "label" => "address name" + "label" => "address name", + "required" => true )) ->add("title", "text", array( "constraints" => array( diff --git a/core/lib/Thelia/Form/AddressUpdateForm.php b/core/lib/Thelia/Form/AddressUpdateForm.php new file mode 100644 index 000000000..aa969831b --- /dev/null +++ b/core/lib/Thelia/Form/AddressUpdateForm.php @@ -0,0 +1,69 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Form; +use Symfony\Component\Validator\Constraints\NotBlank; + + +/** + * Class AddressUpdateForm + * @package Thelia\Form + * @author Manuel Raynaud + */ +class AddressUpdateForm extends AddressCreateForm { + + /** + * + * in this function you add all the fields you need for your Form. + * Form this you have to call add method on $this->formBuilder attribute : + * + * $this->formBuilder->add("name", "text") + * ->add("email", "email", array( + * "attr" => array( + * "class" => "field" + * ), + * "label" => "email", + * "constraints" => array( + * new \Symfony\Component\Validator\Constraints\NotBlank() + * ) + * ) + * ) + * ->add('age', 'integer'); + * + * @return null + */ + protected function buildForm() + { + parent::buildForm(); + + + } + + /** + * @return string the name of you form. This name must be unique + */ + public function getName() + { + return "thelia_address_update"; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Address.php b/core/lib/Thelia/Model/Address.php index 2501d5d1f..413797eeb 100755 --- a/core/lib/Thelia/Model/Address.php +++ b/core/lib/Thelia/Model/Address.php @@ -4,21 +4,12 @@ namespace Thelia\Model; use Propel\Runtime\Connection\ConnectionInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Event\AddressEvent; +use Thelia\Core\Event\TheliaEvents; use Thelia\Model\Base\Address as BaseAddress; class Address extends BaseAddress { - - protected $dispatcher; - - public function setDispatcher(EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - } - - public function getDispatcher() - { - return $this->dispatcher; - } + use \Thelia\Model\Tools\ModelEventDispatcherTrait; /** * Code to be run before inserting to database @@ -27,6 +18,7 @@ class Address extends BaseAddress { */ public function preInsert(ConnectionInterface $con = null) { + $this->dispatchEvent(TheliaEvents::BEFORE_CREATEADDRESS, new AddressEvent($this)); return true; } @@ -36,7 +28,7 @@ class Address extends BaseAddress { */ public function postInsert(ConnectionInterface $con = null) { - + $this->dispatchEvent(TheliaEvents::AFTER_CREATEADDRESS, new AddressEvent($this)); } /** @@ -46,6 +38,7 @@ class Address extends BaseAddress { */ public function preUpdate(ConnectionInterface $con = null) { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATEADDRESS, new AddressEvent($this)); return true; } @@ -55,7 +48,7 @@ class Address extends BaseAddress { */ public function postUpdate(ConnectionInterface $con = null) { - + $this->dispatchEvent(TheliaEvents::AFTER_UPDATEADDRESS, new AddressEvent($this)); } /** @@ -65,6 +58,7 @@ class Address extends BaseAddress { */ public function preDelete(ConnectionInterface $con = null) { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETEADDRESS, new AddressEvent($this)); return true; } @@ -74,7 +68,7 @@ class Address extends BaseAddress { */ public function postDelete(ConnectionInterface $con = null) { - + $this->dispatchEvent(TheliaEvents::AFTER_DELETEADDRESS, new AddressEvent($this)); } } diff --git a/core/lib/Thelia/Model/Customer.php b/core/lib/Thelia/Model/Customer.php index 9572b6441..080c02ed6 100755 --- a/core/lib/Thelia/Model/Customer.php +++ b/core/lib/Thelia/Model/Customer.php @@ -2,7 +2,7 @@ namespace Thelia\Model; -use Symfony\Component\Config\Definition\Exception\Exception; +use Propel\Runtime\Exception\PropelException; use Thelia\Model\AddressQuery; use Thelia\Model\Base\Customer as BaseCustomer; @@ -115,7 +115,7 @@ class Customer extends BaseCustomer implements UserInterface $con->commit(); - } catch(Exception $e) { + } catch(PropelException $e) { $con->rollback(); throw $e; } @@ -225,7 +225,7 @@ class Customer extends BaseCustomer implements UserInterface */ public function preUpdate(ConnectionInterface $con = null) { - $this->dispatchEvent(TheliaEvents::BEFORE_CHANGECUSTOMER, new CustomerEvent($this)); + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECUSTOMER, new CustomerEvent($this)); return true; } @@ -234,7 +234,7 @@ class Customer extends BaseCustomer implements UserInterface */ public function postUpdate(ConnectionInterface $con = null) { - $this->dispatchEvent(TheliaEvents::AFTER_CHANGECUSTOMER, new CustomerEvent($this)); + $this->dispatchEvent(TheliaEvents::AFTER_UPDATECUSTOMER, new CustomerEvent($this)); } /** diff --git a/documentation/api/classes/Thelia.Core.Event.TheliaEvents.html b/documentation/api/classes/Thelia.Core.Event.TheliaEvents.html index fe9f532a1..2d4072603 100755 --- a/documentation/api/classes/Thelia.Core.Event.TheliaEvents.html +++ b/documentation/api/classes/Thelia.Core.Event.TheliaEvents.html @@ -1631,8 +1631,8 @@ ADMIN_LOGIN
BEFORE_CREATECUSTOMER
AFTER_CREATECUSTOMER
- BEFORE_CHANGECUSTOMER
- AFTER_CHANGECUSTOMER
+ BEFORE_UPDATECUSTOMER
+ AFTER_UPDATECUSTOMER
BEFORE_CREATECATEGORY
AFTER_CREATECATEGORY
BEFORE_DELETECATEGORY
@@ -1891,8 +1891,8 @@
-

BEFORE_CHANGECUSTOMER

-
BEFORE_CHANGECUSTOMER
+

BEFORE_UPDATECUSTOMER

+
BEFORE_UPDATECUSTOMER

Sent once the customer change form has been successfully validated, and before customer update in the database.

@@ -1913,8 +1913,8 @@
-

AFTER_CHANGECUSTOMER

-
AFTER_CHANGECUSTOMER
+

AFTER_UPDATECUSTOMER

+
AFTER_UPDATECUSTOMER

Sent just after a successful update of a customer in the database.

diff --git a/documentation/api/files/Action/Category.php.txt b/documentation/api/files/Action/Category.php.txt index b62357b08..ddd3362a5 100755 --- a/documentation/api/files/Action/Category.php.txt +++ b/documentation/api/files/Action/Category.php.txt @@ -109,7 +109,7 @@ class Category extends BaseAction implements EventSubscriberInterface $customer = CustomerQuery::create()->findPk(1); try { $customerEvent = new CustomerEvent($customer); - $event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent); + $event->getDispatcher()->dispatch(TheliaEvents::BEFORE_UPDATECUSTOMER, $customerEvent); $data = $form->getData(); @@ -127,7 +127,7 @@ class Category extends BaseAction implements EventSubscriberInterface ); $customerEvent->customer = $customer; - $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); + $event->getDispatcher()->dispatch(TheliaEvents::AFTER_UPDATECUSTOMER, $customerEvent); // Update the logged-in user, and redirect to the success URL (exits) // We don-t send the login event, as the customer si already logged. diff --git a/documentation/api/files/Core/Event/TheliaEvents.php.txt b/documentation/api/files/Core/Event/TheliaEvents.php.txt index e06abc3c7..ca95903a8 100755 --- a/documentation/api/files/Core/Event/TheliaEvents.php.txt +++ b/documentation/api/files/Core/Event/TheliaEvents.php.txt @@ -78,11 +78,11 @@ final class TheliaEvents /** * Sent once the customer change form has been successfully validated, and before customer update in the database. */ - const BEFORE_CHANGECUSTOMER = "action.before_changecustomer"; + const BEFORE_UPDATECUSTOMER = "action.before_changecustomer"; /** * Sent just after a successful update of a customer in the database. */ - const AFTER_CHANGECUSTOMER = "action.after_changecustomer"; + const AFTER_UPDATECUSTOMER = "action.after_changecustomer"; /** * Sent once the category creation form has been successfully validated, and before category insertion in the database. diff --git a/documentation/api/files/Model/Customer.php.txt b/documentation/api/files/Model/Customer.php.txt index cbd507bf4..a220fd0c8 100755 --- a/documentation/api/files/Model/Customer.php.txt +++ b/documentation/api/files/Model/Customer.php.txt @@ -125,7 +125,7 @@ class Customer extends BaseCustomer implements UserInterface public function preUpdate(ConnectionInterface $con = null) { $customerEvent = new CustomerEvent($this); - $this->dispatchEvent(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent); + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECUSTOMER, $customerEvent); return true; } @@ -133,7 +133,7 @@ class Customer extends BaseCustomer implements UserInterface public function postUpdate(ConnectionInterface $con = null) { $customerEvent = new CustomerEvent($this); - $this->dispatchEvent(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); + $this->dispatchEvent(TheliaEvents::AFTER_UPDATECUSTOMER, $customerEvent); } protected function dispatchEvent($eventName, CustomerEvent $customerEvent) diff --git a/templates/default/address.html b/templates/default/address.html new file mode 100644 index 000000000..afae59197 --- /dev/null +++ b/templates/default/address.html @@ -0,0 +1,99 @@ +{check_auth context="front" roles="CUSTOMER" login_tpl="login"} +{include file="includes/header.html"} +{$page_title="{intl l='My Account'}"} + + +{form name="thelia.address.create"} +{if $form_error}
{$form_error_message}
{/if} +{* We use {navigate to="index"} as form action to avoid mixing post and get data *} + + {form_field form=$form field='success_url'} + + {/form_field} + {form_hidden_fields form=$form} + + {form_field form=$form field="label"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="title"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="firstname"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="lastname"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="address1"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + {form_field form=$form field="zipcode"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="city"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="country"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + {form_field form=$form field="phone"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + +{/form} + + +{include file="includes/footer.html"} diff --git a/templates/default/address_edit.html b/templates/default/address_edit.html new file mode 100644 index 000000000..22e70289a --- /dev/null +++ b/templates/default/address_edit.html @@ -0,0 +1,100 @@ +{check_auth context="front" roles="CUSTOMER" login_tpl="login"} +{include file="includes/header.html"} +{$page_title="{intl l='My Account'}"} + + +{form name="thelia.address.update"} +{if $form_error}
{$form_error_message}
{/if} +{* We use {navigate to="index"} as form action to avoid mixing post and get data *} +
+ {form_field form=$form field='success_url'} + + {/form_field} + + {form_hidden_fields form=$form} + + {form_field form=$form field="label"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="title"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="firstname"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="lastname"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="address1"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + {form_field form=$form field="zipcode"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="city"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + + {form_field form=$form field="country"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + {form_field form=$form field="phone"} + {if $error}{$message}{/if} + + + +
+ {/form_field} + +
+{/form} + + +{include file="includes/footer.html"} diff --git a/templates/default/address_list.html b/templates/default/address_list.html new file mode 100644 index 000000000..88a483e23 --- /dev/null +++ b/templates/default/address_list.html @@ -0,0 +1,11 @@ +{check_auth context="front" roles="CUSTOMER" login_tpl="login"} +{include file="includes/header.html"} +{$page_title="{intl l='My Account'}"} + +
    +{loop type="address" name="customer_list" customer="current"} +
  • {#LABEL} - {#FIRSTNAME} {#LASTNAME} - edit
  • +{/loop} +
+ +{include file="includes/footer.html"} diff --git a/templates/default/connexion.html b/templates/default/connexion.html index a6a2cc665..b3867782f 100755 --- a/templates/default/connexion.html +++ b/templates/default/connexion.html @@ -7,7 +7,6 @@ The two fields below are not par of the form, they are here to defines the action to process, and the view to render once the form is submited *} - {* the action triggered by this form *} {* This field is common to all BaseForm instances (thus, this one), and defines From 31c074d492c613c77def77365403ee57622f399e Mon Sep 17 00:00:00 2001 From: franck Date: Wed, 4 Sep 2013 17:59:07 +0200 Subject: [PATCH 06/39] Fixed image tests --- core/lib/Thelia/Model/Category.php | 2 +- core/lib/Thelia/Model/Content.php | 2 +- core/lib/Thelia/Model/Folder.php | 2 +- core/lib/Thelia/Model/Product.php | 2 +- core/lib/Thelia/Tests/Action/ImageTest.php | 9 ++ core/lib/Thelia/Tools/URL.php | 122 ++++++++++----------- 6 files changed, 69 insertions(+), 70 deletions(-) diff --git a/core/lib/Thelia/Model/Category.php b/core/lib/Thelia/Model/Category.php index e380457ca..ced10c94b 100755 --- a/core/lib/Thelia/Model/Category.php +++ b/core/lib/Thelia/Model/Category.php @@ -25,7 +25,7 @@ class Category extends BaseCategory public function getUrl($locale) { - return URL::getInstance()->retrieve('category', $this->getId(), $locale); + return URL::getInstance()->retrieve('category', $this->getId(), $locale)->toString(); } /** diff --git a/core/lib/Thelia/Model/Content.php b/core/lib/Thelia/Model/Content.php index 430408521..5bc0ba6b2 100755 --- a/core/lib/Thelia/Model/Content.php +++ b/core/lib/Thelia/Model/Content.php @@ -9,6 +9,6 @@ class Content extends BaseContent { public function getUrl($locale) { - return URL::getInstance()->retrieve('content', $this->getId(), $locale); + return URL::getInstance()->retrieve('content', $this->getId(), $locale)->toString(); } } diff --git a/core/lib/Thelia/Model/Folder.php b/core/lib/Thelia/Model/Folder.php index 5aab7c5bf..8151dae0e 100755 --- a/core/lib/Thelia/Model/Folder.php +++ b/core/lib/Thelia/Model/Folder.php @@ -17,7 +17,7 @@ class Folder extends BaseFolder public function getUrl($locale) { - return URL::getInstance()->retrieve('folder', $this->getId(), $locale); + return URL::getInstance()->retrieve('folder', $this->getId(), $locale)->toString(); } /** diff --git a/core/lib/Thelia/Model/Product.php b/core/lib/Thelia/Model/Product.php index f02792285..6c7ffbe44 100755 --- a/core/lib/Thelia/Model/Product.php +++ b/core/lib/Thelia/Model/Product.php @@ -9,6 +9,6 @@ class Product extends BaseProduct { public function getUrl($locale) { - return URL::getInstance()->retrieve('product', $this->getId(), $locale); + return URL::getInstance()->retrieve('product', $this->getId(), $locale)->toString(); } } diff --git a/core/lib/Thelia/Tests/Action/ImageTest.php b/core/lib/Thelia/Tests/Action/ImageTest.php index bde077481..526f7cb86 100755 --- a/core/lib/Thelia/Tests/Action/ImageTest.php +++ b/core/lib/Thelia/Tests/Action/ImageTest.php @@ -30,6 +30,7 @@ use Thelia\Core\HttpFoundation\Session\Session; use Thelia\Action\Image; use Thelia\Core\Event\ImageEvent; use Thelia\Model\ConfigQuery; +use Thelia\Tools\URL; /** * Class ImageTest @@ -48,7 +49,15 @@ class ImageTest extends \PHPUnit_Framework_TestCase $dispatcher = $this->getMock("Symfony\Component\EventDispatcher\EventDispatcherInterface"); + $url = new URL($container, 'dev'); + $container->set("event_dispatcher", $dispatcher); + $container->set("thelia.url.manager", $dispatcher); + + $request = new Request(); + $request->setSession($this->session); + + $container->set("request", $request); return $container; } diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index 1816f76ec..b1fa6cd03 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -55,8 +55,6 @@ class URL $this->retriever = new RewritingRetriever(); $this->resolver = new RewritingResolver(); - - echo "instanciation ok !"; } /** @@ -79,10 +77,7 @@ class URL */ public function getBaseUrl() { - $lang = $this->container - ->get('request') - ->getSession() - ->getLang(); + $lang = $this->container->get('request')->getSession()->getLang(); // Check if we have a specific URL for each lang. $one_domain_foreach_lang = ConfigQuery::read("one_domain_foreach_lang", false); @@ -197,70 +192,65 @@ class URL return $this->absoluteUrl($path, $parameters); } + /** + * Retrieve a rewritten URL from a view, a view id and a locale + * + * @param $view + * @param $viewId + * @param $viewLocale + * + * @return RewritingRetriever You can access $url and $rewrittenUrl properties + */ + public function retrieve($view, $viewId, $viewLocale) + { + if(ConfigQuery::isRewritingEnable()) { + $this->retriever->loadViewUrl($view, $viewLocale, $viewId); + } - /** - * Retrieve a rewritten URL from a view, a view id and a locale - * - * @param $view - * @param $viewId - * @param $viewLocale - * - * @return RewritingRetriever You can access $url and $rewrittenUrl properties - */ - public function retrieve($view, $viewId, $viewLocale) - { - if(ConfigQuery::isRewritingEnable()) { - $this->retriever->loadViewUrl($view, $viewLocale, $viewId); - } + return $this->retriever; + } - // Bug: $rewrittenUrl n'est pas initialisé - //return $rewrittenUrl === null ? $this->viewUrl($view, array($view . '_id' => $viewId, 'locale' => $viewLocale)) : $rewrittenUrl; - return $this->viewUrl($view, array($view . '_id' => $viewId, 'locale' => $viewLocale)); - } + /** + * Retrieve a rewritten URL from the current GET parameters + * + * @param Request $request + * + * @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method + */ + public function retrieveCurrent(Request $request) + { + if(ConfigQuery::isRewritingEnable()) { + $view = $request->query->get('view', null); + $viewLocale = $request->query->get('locale', null); + $viewId = $view === null ? null : $request->query->get($view . '_id', null); - /** - * Retrieve a rewritten URL from the current request GET parameters - * - * @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method - */ - public function retrieveCurrent() - { - if (ConfigQuery::isRewritingEnable()) { + $allOtherParameters = $request->query->all(); + if($view !== null) { + unset($allOtherParameters['view']); + } + if($viewLocale !== null) { + unset($allOtherParameters['locale']); + } + if($viewId !== null) { + unset($allOtherParameters[$view . '_id']); + } - $query = $this->container->get('request')->query; + $this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters); + } - $view = $query->get('view', null); - $viewLocale = $query->get('locale', null); - $viewId = $view === null ? null : $query->get($view . '_id', null); + return $this->retriever; + } - $allOtherParameters = $query->all(); - if($view !== null) { - unset($allOtherParameters['view']); - } - if($viewLocale !== null) { - unset($allOtherParameters['locale']); - } - if($viewId !== null) { - unset($allOtherParameters[$view . '_id']); - } - - $this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters); - } - - return $this->retriever; - } - - /** - * Retrieve a rewritten URL from the current GET parameters or use toString method - * - * @param $url - * - * @return RewritingResolver - */ - public function resolve($url) - { - $this->resolver->load($url); - - return $this->resolver; - } + /** + * Retrieve a rewritten URL from the current GET parameters or use toString method + * + * @param $url + * + * @return RewritingResolver + */ + public function resolve($url) + { + $this->resolver->load($url); + return $this->resolver; + } } \ No newline at end of file From d3a287333ecedd0a1c72e3f2d81d93c1c454924b Mon Sep 17 00:00:00 2001 From: franck Date: Wed, 4 Sep 2013 19:02:26 +0200 Subject: [PATCH 07/39] Fixed TheliaLoop Smarty plugin (lopp imbrication was broken) --- .../Thelia/Action/PositionManagementTrait.php | 157 ++++++++++++++++ .../Thelia/Config/Resources/routing/admin.xml | 6 +- .../Controller/Admin/ConfigController.php | 2 +- .../Core/Event/BaseUpdatePositionEvent.php | 87 +++++++++ .../Event/CurrencyUpdatePositionEvent.php | 28 +++ .../Smarty/Plugins/AdminUtilities.php | 2 +- .../Template/Smarty/Plugins/TheliaLoop.php | 15 ++ core/lib/Thelia/Core/TheliaHttpKernel.php | 4 +- .../Model/Tools/PositionManagementTrait.php | 176 ++++++++++++++++++ core/lib/Thelia/Tools/URL.php | 2 + templates/admin/default/categories.html | 6 +- templates/admin/default/currencies.html | 2 +- templates/admin/default/currency-edit.html | 2 +- templates/admin/default/message-edit.html | 2 +- templates/admin/default/messages.html | 4 +- templates/admin/default/variable-edit.html | 2 +- templates/admin/default/variables.html | 4 +- 17 files changed, 484 insertions(+), 17 deletions(-) create mode 100644 core/lib/Thelia/Action/PositionManagementTrait.php create mode 100644 core/lib/Thelia/Core/Event/BaseUpdatePositionEvent.php create mode 100644 core/lib/Thelia/Core/Event/CurrencyUpdatePositionEvent.php create mode 100644 core/lib/Thelia/Model/Tools/PositionManagementTrait.php diff --git a/core/lib/Thelia/Action/PositionManagementTrait.php b/core/lib/Thelia/Action/PositionManagementTrait.php new file mode 100644 index 000000000..70f91d995 --- /dev/null +++ b/core/lib/Thelia/Action/PositionManagementTrait.php @@ -0,0 +1,157 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Action; + +use Thelia\Core\Event\BaseChangePositionEvent; + +trait PositionManagementTrait { + + const POSITION_UP + /** + * Changes object position, selecting absolute ou relative change. + * + * @param BaseChangePositionEvent $event + */ + public function changePosition(BaseChangePositionEvent $event) + { + if ($event->getMode() == BaseChangePositionEvent::POSITION_ABSOLUTE) + return $this->changeAbsolutePosition($event); + else + return $this->exchangePosition($event); + } + + /** + * Move up or down a object + * + * @param BaseChangePositionEvent $event + */ + protected function exchangePosition(BaseChangePositionEvent $event) + { + $object = CategoryQuery::create()->findPk($event->getCategoryId()); + + if ($object !== null) { + + // The current position of the object + $my_position = $object->getPosition(); + + // Find object to exchange position with + $search = CategoryQuery::create() + ->filterByParent($object->getParent()); + + // Up or down ? + if ($event->getMode() == BaseChangePositionEvent::POSITION_UP) { + // Find the object immediately before me + $search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC); + } elseif ($event->getMode() == BaseChangePositionEvent::POSITION_DOWN) { + // Find the object immediately after me + $search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC); + } else + + return; + + $result = $search->findOne(); + + // If we found the proper object, exchange their positions + if ($result) { + + $cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); + + $cnx->beginTransaction(); + + try { + $object + ->setDispatcher($this->getDispatcher()) + ->setPosition($result->getPosition()) + ->save() + ; + + $result->setPosition($my_position)->save(); + + $cnx->commit(); + } catch (Exception $e) { + $cnx->rollback(); + } + } + } + } + + /** + * Changes object position + * + * @param BaseChangePositionEvent $event + */ + protected function changeAbsolutePosition(BaseChangePositionEvent $event) + { + $object = CategoryQuery::create()->findPk($event->getCategoryId()); + + if ($object !== null) { + + // The required position + $new_position = $event->getPosition(); + + // The current position + $current_position = $object->getPosition(); + + if ($new_position != null && $new_position > 0 && $new_position != $current_position) { + + // Find categories to offset + $search = CategoryQuery::create()->filterByParent($object->getParent()); + + if ($new_position > $current_position) { + // The new position is after the current position -> we will offset + 1 all categories located between us and the new position + $search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position)); + + $delta = -1; + } else { + // The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position + $search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1)); + + $delta = 1; + } + + $results = $search->find(); + + $cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); + + $cnx->beginTransaction(); + + try { + foreach ($results as $result) { + $result->setPosition($result->getPosition() + $delta)->save($cnx); + } + + $object + ->setDispatcher($this->getDispatcher()) + ->setPosition($new_position) + ->save($cnx) + ; + + $cnx->commit(); + } catch (Exception $e) { + $cnx->rollback(); + } + } + } + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 9f56548ed..ac652017c 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -53,7 +53,7 @@ Thelia\Controller\Admin\ConfigController::changeAction - + Thelia\Controller\Admin\ConfigController::saveChangeAction @@ -75,7 +75,7 @@ Thelia\Controller\Admin\MessageController::changeAction - + Thelia\Controller\Admin\MessageController::saveChangeAction @@ -97,7 +97,7 @@ Thelia\Controller\Admin\CurrencyController::changeAction - + Thelia\Controller\Admin\CurrencyController::saveChangeAction diff --git a/core/lib/Thelia/Controller/Admin/ConfigController.php b/core/lib/Thelia/Controller/Admin/ConfigController.php index b84368c2f..a67ecbaaa 100644 --- a/core/lib/Thelia/Controller/Admin/ConfigController.php +++ b/core/lib/Thelia/Controller/Admin/ConfigController.php @@ -241,7 +241,7 @@ class ConfigController extends BaseAdminController if ($this->getRequest()->get('save_mode') == 'stay') { $this->redirectToRoute( - "admin.configuration.variables.update", + "admin.configuration.variables.change", array('variable_id' => $variable_id) ); } diff --git a/core/lib/Thelia/Core/Event/BaseUpdatePositionEvent.php b/core/lib/Thelia/Core/Event/BaseUpdatePositionEvent.php new file mode 100644 index 000000000..3587a0757 --- /dev/null +++ b/core/lib/Thelia/Core/Event/BaseUpdatePositionEvent.php @@ -0,0 +1,87 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class BaseUpdatePositionEvent extends ActionEvent +{ + const POSITION_UP = 1; + const POSITION_DOWN = 2; + const POSITION_ABSOLUTE = 3; + + protected $object_id; + protected $mode; + protected $position; + + protected $object; + + public function __construct($object_id, $mode, $position = null) + { + $this->object_id = $object_id; + $this->mode = $mode; + $this->position = $position; + } + + public function getMode() + { + return $this->mode; + } + + public function setMode($mode) + { + $this->mode = $mode; + return $this; + } + + public function getPosition() + { + return $this->position; + } + + public function setPosition($position) + { + $this->position = $position; + return $this; + } + + public function getObjectId() + { + return $this->object_id; + } + + public function setObjectId($object_id) + { + $this->object_id = $object_id; + return $this; + } + + public function getObjectId() + { + return $this->object_id; + } + + public function setObjectId($object_id) + { + $this->object_id = $object_id; + } +} diff --git a/core/lib/Thelia/Core/Event/CurrencyUpdatePositionEvent.php b/core/lib/Thelia/Core/Event/CurrencyUpdatePositionEvent.php new file mode 100644 index 000000000..655e24c9a --- /dev/null +++ b/core/lib/Thelia/Core/Event/CurrencyUpdatePositionEvent.php @@ -0,0 +1,28 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class CategoryChangePositionEvent extends BaseChangePositionEvent +{ +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/AdminUtilities.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/AdminUtilities.php index 4e2c065fd..fcea9ffd6 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/AdminUtilities.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/AdminUtilities.php @@ -70,7 +70,7 @@ class AdminUtilities extends AbstractSmartyPlugin if ($permissions == null || $this->securityContext->isGranted("ADMIN", array($permission))) { return sprintf( - '%s', + '%s', URL::getInstance()->absoluteUrl("$path/positionUp", array($url_parameter => $id)), $in_place_edit_class, $id, diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index e7ee5e995..a65e15a8e 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -136,8 +136,23 @@ class TheliaLoop extends AbstractSmartyPlugin } if ($loopResults->valid()) { + $loopResultRow = $loopResults->current(); + // On first iteration, save variables that may be overwritten by this loop + if (! isset($this->varstack[$name])) { + + $saved_vars = array(); + + $varlist = $loopResultRow->getVars(); + + foreach ($varlist as $var) { + $saved_vars[$var] = $template->getTemplateVars($var); + } + + $this->varstack[$name] = $saved_vars; + } + foreach ($loopResultRow->getVarVal() as $var => $val) { $template->assign($var, $val); } diff --git a/core/lib/Thelia/Core/TheliaHttpKernel.php b/core/lib/Thelia/Core/TheliaHttpKernel.php index 950f08832..20197d9c6 100755 --- a/core/lib/Thelia/Core/TheliaHttpKernel.php +++ b/core/lib/Thelia/Core/TheliaHttpKernel.php @@ -122,7 +122,9 @@ class TheliaHttpKernel extends HttpKernel */ protected function initParam(Request $request) { - // Ensure an instaciation of URL service + // Ensure an instaciation of URL service, which is accessed as a pseudo-singleton + // in the rest of the application. + // See Thelia\Tools\URL class. $this->container->get('thelia.url.manager'); $lang = $this->detectLang($request); diff --git a/core/lib/Thelia/Model/Tools/PositionManagementTrait.php b/core/lib/Thelia/Model/Tools/PositionManagementTrait.php new file mode 100644 index 000000000..eccbb00dd --- /dev/null +++ b/core/lib/Thelia/Model/Tools/PositionManagementTrait.php @@ -0,0 +1,176 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Model\Tools; + +use Propel\Runtime\ActiveQuery\PropelQuery; +use Propel\Runtime\ActiveQuery\Criteria; + +trait PositionManagementTrait { + + /** + * Create an instancer of this object query + */ + private function createQuery() { + return PropelQuery::from(__CLASS__); + } + + /** + * Return the database name from this object's table map. + */ + private function getDatabaseNameFromMap() { + $class = new \ReflectionClass(self::TABLE_MAP); + + return $class->getConstant('DATABASE_NAME'); + } + + + /** + * Get the position of the next inserted object + */ + public function getNextPosition($parent) { + + $last = $this->createQuery() + ->filterByParent($parent) + ->orderByPosition(Criteria::DESC) + ->limit(1) + ->findOne() + ; + + return $last != null ? $last->getPosition() + 1 : 1; + } + + /** + * Move up a object + */ + protected function movePositionUp() { + $this->movePositionUpOrDown(true); + } + + /** + * Move down a object + */ + protected function movePositionDown() { + $this->movePositionUpOrDown(false); + } + + /** + * Move up or down a object + * + * @param the exchange mode: go up (POSITION_UP) or go down (POSITION_DOWN) + */ + protected function movePositionUpOrDown($up = true) + { + // The current position of the object + $my_position = $this->getPosition(); + + // Find object to exchange position with + $search = $this->createQuery() + ->filterByParent($this->getParent()); + + // Up or down ? + if ($up === true) { + // Find the object immediately before me + $search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC); + } + else { + // Find the object immediately after me + $search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC); + } + + $result = $search->findOne(); + + // If we found the proper object, exchange their positions + if ($result) { + + $cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); + + $cnx->beginTransaction(); + + try { + $this + ->setDispatcher($this->getDispatcher()) + ->setPosition($result->getPosition()) + ->save() + ; + + $result->setPosition($my_position)->save(); + + $cnx->commit(); + } catch (Exception $e) { + $cnx->rollback(); + } + } + } + + /** + * Changes object position + * + * @param newPosition + */ + protected function changeAbsolutePosition($newPosition) + { + // The current position + $current_position = $this->getPosition(); + + if ($newPosition != null && $newPosition > 0 && $newPosition != $current_position) { + + // Find categories to offset + $search = $this->createQuery()->filterByParent($this->getParent()); + + if ($newPosition > $current_position) { + // The new position is after the current position -> we will offset + 1 all categories located between us and the new position + $search->filterByPosition(array('min' => 1+$current_position, 'max' => $newPosition)); + + $delta = -1; + } else { + // The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position + $search->filterByPosition(array('min' => $newPosition, 'max' => $current_position - 1)); + + $delta = 1; + } + + $results = $search->find(); + + $cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME); + + $cnx->beginTransaction(); + + try { + foreach ($results as $result) { + $result->setPosition($result->getPosition() + $delta)->save($cnx); + } + + $this + ->setDispatcher($this->getDispatcher()) + ->setPosition($newPosition) + ->save($cnx) + ; + + $cnx->commit(); + } catch (Exception $e) { + $cnx->rollback(); + } + } + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index b1fa6cd03..84d35b457 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -48,6 +48,8 @@ class URL public function __construct(ContainerInterface $container, $environment) { // Allow singleton style calls once intanciated. + // For this to work, the URL service has to be instanciated very early. This is done manually + // in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager'); self::$instance = $this; $this->container = $container; diff --git a/templates/admin/default/categories.html b/templates/admin/default/categories.html index d4f753f91..fdf2ab093 100755 --- a/templates/admin/default/categories.html +++ b/templates/admin/default/categories.html @@ -85,17 +85,17 @@
- {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} + i={$ID} {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} #TITLE {/loop} - {$TITLE} + {$ID} p={$POSITION} {$TITLE}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.currencies.delete"} diff --git a/templates/admin/default/currency-edit.html b/templates/admin/default/currency-edit.html index 4ac8bb7c5..173876ede 100644 --- a/templates/admin/default/currency-edit.html +++ b/templates/admin/default/currency-edit.html @@ -29,7 +29,7 @@
{form name="thelia.admin.currency.modification"} -
+
{* Be sure to get the currency ID, even if the form could not be validated *} diff --git a/templates/admin/default/message-edit.html b/templates/admin/default/message-edit.html index 71570f69a..92d707b45 100644 --- a/templates/admin/default/message-edit.html +++ b/templates/admin/default/message-edit.html @@ -29,7 +29,7 @@
{form name="thelia.admin.message.modification"} - +
{* Be sure to get the message ID, even if the form could not be validated *} diff --git a/templates/admin/default/messages.html b/templates/admin/default/messages.html index 257e64c0e..75ee742bf 100644 --- a/templates/admin/default/messages.html +++ b/templates/admin/default/messages.html @@ -19,7 +19,7 @@
- +
";if(this.o.calendarWeeks){var c='';b+=c,this.picker.find(".datepicker-days thead tr:first-child").prepend(c)}for(;a'+k[this.o.language].daysMin[a++%7]+"";b+="",this.picker.find(".datepicker-days thead").append(b)},fillMonths:function(){for(var a="",b=0;12>b;)a+=''+k[this.o.language].monthsShort[b++]+"";this.picker.find(".datepicker-months td").html(a)},setRange:function(b){b&&b.length?this.range=a.map(b,function(a){return a.valueOf()}):delete this.range,this.fill()},getClassNames:function(b){var c=[],d=this.viewDate.getUTCFullYear(),e=this.viewDate.getUTCMonth(),f=this.date.valueOf(),g=new Date;return b.getUTCFullYear()d||b.getUTCFullYear()==d&&b.getUTCMonth()>e)&&c.push("new"),this.o.todayHighlight&&b.getUTCFullYear()==g.getFullYear()&&b.getUTCMonth()==g.getMonth()&&b.getUTCDate()==g.getDate()&&c.push("today"),f&&b.valueOf()==f&&c.push("active"),(b.valueOf()this.o.endDate||-1!==a.inArray(b.getUTCDay(),this.o.daysOfWeekDisabled))&&c.push("disabled"),this.range&&(b>this.range[0]&&b"),this.o.calendarWeeks)){var r=new Date(+m+864e5*((this.o.weekStart-m.getUTCDay()-7)%7)),s=new Date(+r+864e5*((11-r.getUTCDay())%7)),t=new Date(+(t=b(s.getUTCFullYear(),0,1))+864e5*((11-t.getUTCDay())%7)),u=(s-t)/864e5/7+1;q.push('")}p=this.getClassNames(m),p.push("day");var v=this.o.beforeShowDay(m);void 0===v?v={}:"boolean"==typeof v?v={enabled:v}:"string"==typeof v&&(v={classes:v}),v.enabled===!1&&p.push("disabled"),v.classes&&(p=p.concat(v.classes.split(/\s+/))),v.tooltip&&(c=v.tooltip),p=a.unique(p),q.push('"),m.getUTCDay()==this.o.weekEnd&&q.push(""),m.setUTCDate(m.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(q.join(""));var w=this.date&&this.date.getUTCFullYear(),x=this.picker.find(".datepicker-months").find("th:eq(1)").text(e).end().find("span").removeClass("active");w&&w==e&&x.eq(this.date.getUTCMonth()).addClass("active"),(g>e||e>i)&&x.addClass("disabled"),e==g&&x.slice(0,h).addClass("disabled"),e==i&&x.slice(j+1).addClass("disabled"),q="",e=10*parseInt(e/10,10);var y=this.picker.find(".datepicker-years").find("th:eq(1)").text(e+"-"+(e+9)).end().find("td");e-=1;for(var z=-1;11>z;z++)q+='e||e>i?" disabled":"")+'">'+e+"",e+=1;y.html(q)},updateNavArrows:function(){if(this._allow_update){var a=new Date(this.viewDate),b=a.getUTCFullYear(),c=a.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()&&c<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()&&c>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}}},click:function(c){c.preventDefault();var d=a(c.target).closest("span, td, th");if(1==d.length)switch(d[0].nodeName.toLowerCase()){case"th":switch(d[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var e=l.modes[this.viewMode].navStep*("prev"==d[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,e);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,e)}this.fill();break;case"today":var f=new Date;f=b(f.getFullYear(),f.getMonth(),f.getDate(),0,0,0),this.showMode(-2);var g="linked"==this.o.todayBtn?null:"view";this._setDate(f,g);break;case"clear":var h;this.isInput?h=this.element:this.component&&(h=this.element.find("input")),h&&h.val("").change(),this._trigger("changeDate"),this.update(),this.o.autoclose&&this.hide()}break;case"span":if(!d.is(".disabled")){if(this.viewDate.setUTCDate(1),d.is(".month")){var i=1,j=d.parent().find("span").index(d),k=this.viewDate.getUTCFullYear();this.viewDate.setUTCMonth(j),this._trigger("changeMonth",this.viewDate),1===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}else{var k=parseInt(d.text(),10)||0,i=1,j=0;this.viewDate.setUTCFullYear(k),this._trigger("changeYear",this.viewDate),2===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}this.showMode(-1),this.fill()}break;case"td":if(d.is(".day")&&!d.is(".disabled")){var i=parseInt(d.text(),10)||1,k=this.viewDate.getUTCFullYear(),j=this.viewDate.getUTCMonth();d.is(".old")?0===j?(j=11,k-=1):j-=1:d.is(".new")&&(11==j?(j=0,k+=1):j+=1),this._setDate(b(k,j,i,0,0,0,0))}}},_setDate:function(a,b){b&&"date"!=b||(this.date=new Date(a)),b&&"view"!=b||(this.viewDate=new Date(a)),this.fill(),this.setValue(),this._trigger("changeDate");var c;this.isInput?c=this.element:this.component&&(c=this.element.find("input")),c&&(c.change(),!this.o.autoclose||b&&"date"!=b||this.hide())},moveMonth:function(a,b){if(!b)return a;var c,d,e=new Date(a.valueOf()),f=e.getUTCDate(),g=e.getUTCMonth(),h=Math.abs(b);if(b=b>0?1:-1,1==h)d=-1==b?function(){return e.getUTCMonth()==g}:function(){return e.getUTCMonth()!=c},c=g+b,e.setUTCMonth(c),(0>c||c>11)&&(c=(c+12)%12);else{for(var i=0;h>i;i++)e=this.moveMonth(e,b);c=e.getUTCMonth(),e.setUTCDate(f),d=function(){return c!=e.getUTCMonth()}}for(;d();)e.setUTCDate(--f),e.setUTCMonth(c);return e},moveYear:function(a,b){return this.moveMonth(a,12*b)},dateWithinRange:function(a){return a>=this.o.startDate&&a<=this.o.endDate},keydown:function(a){if(this.picker.is(":not(:visible)"))return 27==a.keyCode&&this.show(),void 0;var b,c,d,e=!1;switch(a.keyCode){case 27:this.hide(),a.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;b=37==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 38:case 40:if(!this.o.keyboardNavigation)break;b=38==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+7*b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+7*b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 13:this.hide(),a.preventDefault();break;case 9:this.hide()}if(e){this._trigger("changeDate");var f;this.isInput?f=this.element:this.component&&(f=this.element.find("input")),f&&f.change()}},showMode:function(a){a&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+a))),this.picker.find(">div").hide().filter(".datepicker-"+l.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()}};var f=function(b,c){this.element=a(b),this.inputs=a.map(c.inputs,function(a){return a.jquery?a[0]:a}),delete c.inputs,a(this.inputs).datepicker(c).bind("changeDate",a.proxy(this.dateUpdated,this)),this.pickers=a.map(this.inputs,function(b){return a(b).data("datepicker")}),this.updateDates()};f.prototype={updateDates:function(){this.dates=a.map(this.pickers,function(a){return a.date}),this.updateRanges()},updateRanges:function(){var b=a.map(this.dates,function(a){return a.valueOf()});a.each(this.pickers,function(a,c){c.setRange(b)})},dateUpdated:function(b){var c=a(b.target).data("datepicker"),d=c.getUTCDate(),e=a.inArray(b.target,this.inputs),f=this.inputs.length;if(-1!=e){if(d=0&&dthis.dates[e])for(;f>e&&d>this.dates[e];)this.pickers[e++].setUTCDate(d);this.updateDates()}},remove:function(){a.map(this.pickers,function(a){a.remove()}),delete this.element.data().datepicker}};var g=a.fn.datepicker,h=a.fn.datepicker=function(b){var g=Array.apply(null,arguments);g.shift();var h;return this.each(function(){var j=a(this),k=j.data("datepicker"),l="object"==typeof b&&b;if(!k){var m=c(this,"date"),n=a.extend({},i,m,l),o=d(n.language),p=a.extend({},i,o,m,l);if(j.is(".input-daterange")||p.inputs){var q={inputs:p.inputs||j.find("input").toArray()};j.data("datepicker",k=new f(this,a.extend(p,q)))}else j.data("datepicker",k=new e(this,p))}return"string"==typeof b&&"function"==typeof k[b]&&(h=k[b].apply(k,g),void 0!==h)?!1:void 0}),void 0!==h?h:this},i=a.fn.datepicker.defaults={autoclose:!1,beforeShowDay:a.noop,calendarWeeks:!1,clearBtn:!1,daysOfWeekDisabled:[],endDate:1/0,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,rtl:!1,startDate:-1/0,startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0},j=a.fn.datepicker.locale_opts=["format","rtl","weekStart"];a.fn.datepicker.Constructor=e;var k=a.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},l={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(a){return 0===a%4&&0!==a%100||0===a%400},getDaysInMonth:function(a,b){return[31,l.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(a){var b=a.replace(this.validParts,"\0").split("\0"),c=a.match(this.validParts);if(!b||!b.length||!c||0===c.length)throw new Error("Invalid date format.");return{separators:b,parts:c}},parseDate:function(c,d,f){if(c instanceof Date)return c;if("string"==typeof d&&(d=l.parseFormat(d)),/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(c)){var g,h,i=/([\-+]\d+)([dmwy])/,j=c.match(/([\-+]\d+)([dmwy])/g);c=new Date;for(var m=0;mb;)b+=12;for(b%=12,a.setUTCMonth(b);a.getUTCMonth()!=b;)a.setUTCDate(a.getUTCDate()-1);return a},d:function(a,b){return a.setUTCDate(b)}};r.M=r.MM=r.mm=r.m,r.dd=r.d,c=b(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0);var s=d.parts.slice();if(j.length!=s.length&&(s=a(s).filter(function(b,c){return-1!==a.inArray(c,q)}).toArray()),j.length==s.length){for(var m=0,t=s.length;t>m;m++){if(n=parseInt(j[m],10),g=s[m],isNaN(n))switch(g){case"MM":o=a(k[f].months).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length);return a==b}),n=a.inArray(o[0],k[f].months)+1;break;case"M":o=a(k[f].monthsShort).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length); +return a==b}),n=a.inArray(o[0],k[f].monthsShort)+1}p[g]=n}for(var u,m=0;m=g;g++)f.length&&b.push(f.shift()),b.push(e[c.parts[g]]);return b.join("")},headTemplate:'',contTemplate:'',footTemplate:''};l.template='
@@ -64,7 +64,7 @@ {if ! $SECURED}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.messages.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.messages.delete"} diff --git a/templates/admin/default/variable-edit.html b/templates/admin/default/variable-edit.html index 7c89ec378..80410c444 100644 --- a/templates/admin/default/variable-edit.html +++ b/templates/admin/default/variable-edit.html @@ -29,7 +29,7 @@
{form name="thelia.admin.config.modification"} - +
{* Be sure to get the variable ID, even if the form could not be validated *} diff --git a/templates/admin/default/variables.html b/templates/admin/default/variables.html index 307ee85d5..bbab0ae72 100644 --- a/templates/admin/default/variables.html +++ b/templates/admin/default/variables.html @@ -19,7 +19,7 @@
- +
@@ -102,7 +102,7 @@ {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.variables.change"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.variables.delete"} From 43a2c0ac7b21162eada1c9465496ef0bec82b7f7 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 08:30:15 +0200 Subject: [PATCH 08/39] refactor Lang table --- core/lib/Thelia/Model/Base/Lang.php | 432 +++++++++++++++++++-- core/lib/Thelia/Model/Base/LangQuery.php | 256 ++++++++++-- core/lib/Thelia/Model/Lang.php | 30 -- core/lib/Thelia/Model/Map/LangTableMap.php | 86 +++- install/insert.sql | 10 +- install/thelia.sql | 8 +- local/config/schema.xml | 8 +- 7 files changed, 703 insertions(+), 127 deletions(-) diff --git a/core/lib/Thelia/Model/Base/Lang.php b/core/lib/Thelia/Model/Base/Lang.php index 293b0f3a7..1c11103af 100755 --- a/core/lib/Thelia/Model/Base/Lang.php +++ b/core/lib/Thelia/Model/Base/Lang.php @@ -85,10 +85,40 @@ abstract class Lang implements ActiveRecordInterface protected $url; /** - * The value for the position field. - * @var int + * The value for the date_format field. + * @var string */ - protected $position; + protected $date_format; + + /** + * The value for the time_format field. + * @var string + */ + protected $time_format; + + /** + * The value for the datetime_format field. + * @var string + */ + protected $datetime_format; + + /** + * The value for the decimal_separator field. + * @var string + */ + protected $decimal_separator; + + /** + * The value for the thousands_separator field. + * @var string + */ + protected $thousands_separator; + + /** + * The value for the decimals field. + * @var string + */ + protected $decimals; /** * The value for the by_default field. @@ -96,6 +126,12 @@ abstract class Lang implements ActiveRecordInterface */ protected $by_default; + /** + * The value for the position field. + * @var int + */ + protected $position; + /** * The value for the created_at field. * @var string @@ -426,14 +462,69 @@ abstract class Lang implements ActiveRecordInterface } /** - * Get the [position] column value. + * Get the [date_format] column value. * - * @return int + * @return string */ - public function getPosition() + public function getDateFormat() { - return $this->position; + return $this->date_format; + } + + /** + * Get the [time_format] column value. + * + * @return string + */ + public function getTimeFormat() + { + + return $this->time_format; + } + + /** + * Get the [datetime_format] column value. + * + * @return string + */ + public function getDatetimeFormat() + { + + return $this->datetime_format; + } + + /** + * Get the [decimal_separator] column value. + * + * @return string + */ + public function getDecimalSeparator() + { + + return $this->decimal_separator; + } + + /** + * Get the [thousands_separator] column value. + * + * @return string + */ + public function getThousandsSeparator() + { + + return $this->thousands_separator; + } + + /** + * Get the [decimals] column value. + * + * @return string + */ + public function getDecimals() + { + + return $this->decimals; } /** @@ -447,6 +538,17 @@ abstract class Lang implements ActiveRecordInterface return $this->by_default; } + /** + * Get the [position] column value. + * + * @return int + */ + public function getPosition() + { + + return $this->position; + } + /** * Get the [optionally formatted] temporal [created_at] column value. * @@ -593,25 +695,130 @@ abstract class Lang implements ActiveRecordInterface } // setUrl() /** - * Set the value of [position] column. + * Set the value of [date_format] column. * - * @param int $v new value + * @param string $v new value * @return \Thelia\Model\Lang The current object (for fluent API support) */ - public function setPosition($v) + public function setDateFormat($v) { if ($v !== null) { - $v = (int) $v; + $v = (string) $v; } - if ($this->position !== $v) { - $this->position = $v; - $this->modifiedColumns[] = LangTableMap::POSITION; + if ($this->date_format !== $v) { + $this->date_format = $v; + $this->modifiedColumns[] = LangTableMap::DATE_FORMAT; } return $this; - } // setPosition() + } // setDateFormat() + + /** + * Set the value of [time_format] column. + * + * @param string $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setTimeFormat($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->time_format !== $v) { + $this->time_format = $v; + $this->modifiedColumns[] = LangTableMap::TIME_FORMAT; + } + + + return $this; + } // setTimeFormat() + + /** + * Set the value of [datetime_format] column. + * + * @param string $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setDatetimeFormat($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->datetime_format !== $v) { + $this->datetime_format = $v; + $this->modifiedColumns[] = LangTableMap::DATETIME_FORMAT; + } + + + return $this; + } // setDatetimeFormat() + + /** + * Set the value of [decimal_separator] column. + * + * @param string $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setDecimalSeparator($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->decimal_separator !== $v) { + $this->decimal_separator = $v; + $this->modifiedColumns[] = LangTableMap::DECIMAL_SEPARATOR; + } + + + return $this; + } // setDecimalSeparator() + + /** + * Set the value of [thousands_separator] column. + * + * @param string $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setThousandsSeparator($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->thousands_separator !== $v) { + $this->thousands_separator = $v; + $this->modifiedColumns[] = LangTableMap::THOUSANDS_SEPARATOR; + } + + + return $this; + } // setThousandsSeparator() + + /** + * Set the value of [decimals] column. + * + * @param string $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setDecimals($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->decimals !== $v) { + $this->decimals = $v; + $this->modifiedColumns[] = LangTableMap::DECIMALS; + } + + + return $this; + } // setDecimals() /** * Set the value of [by_default] column. @@ -634,6 +841,27 @@ abstract class Lang implements ActiveRecordInterface return $this; } // setByDefault() + /** + * Set the value of [position] column. + * + * @param int $v new value + * @return \Thelia\Model\Lang The current object (for fluent API support) + */ + public function setPosition($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->position !== $v) { + $this->position = $v; + $this->modifiedColumns[] = LangTableMap::POSITION; + } + + + return $this; + } // setPosition() + /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. * @@ -728,19 +956,37 @@ abstract class Lang implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : LangTableMap::translateFieldName('Url', TableMap::TYPE_PHPNAME, $indexType)]; $this->url = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)]; - $this->position = (null !== $col) ? (int) $col : null; + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('DateFormat', TableMap::TYPE_PHPNAME, $indexType)]; + $this->date_format = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('TimeFormat', TableMap::TYPE_PHPNAME, $indexType)]; + $this->time_format = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('DatetimeFormat', TableMap::TYPE_PHPNAME, $indexType)]; + $this->datetime_format = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : LangTableMap::translateFieldName('DecimalSeparator', TableMap::TYPE_PHPNAME, $indexType)]; + $this->decimal_separator = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : LangTableMap::translateFieldName('ThousandsSeparator', TableMap::TYPE_PHPNAME, $indexType)]; + $this->thousands_separator = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 10 + $startcol : LangTableMap::translateFieldName('Decimals', TableMap::TYPE_PHPNAME, $indexType)]; + $this->decimals = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 11 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)]; $this->by_default = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 12 + $startcol : LangTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)]; + $this->position = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 13 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 14 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -753,7 +999,7 @@ abstract class Lang implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 9; // 9 = LangTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 15; // 15 = LangTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\Lang object", 0, $e); @@ -988,12 +1234,30 @@ abstract class Lang implements ActiveRecordInterface if ($this->isColumnModified(LangTableMap::URL)) { $modifiedColumns[':p' . $index++] = 'URL'; } - if ($this->isColumnModified(LangTableMap::POSITION)) { - $modifiedColumns[':p' . $index++] = 'POSITION'; + if ($this->isColumnModified(LangTableMap::DATE_FORMAT)) { + $modifiedColumns[':p' . $index++] = 'DATE_FORMAT'; + } + if ($this->isColumnModified(LangTableMap::TIME_FORMAT)) { + $modifiedColumns[':p' . $index++] = 'TIME_FORMAT'; + } + if ($this->isColumnModified(LangTableMap::DATETIME_FORMAT)) { + $modifiedColumns[':p' . $index++] = 'DATETIME_FORMAT'; + } + if ($this->isColumnModified(LangTableMap::DECIMAL_SEPARATOR)) { + $modifiedColumns[':p' . $index++] = 'DECIMAL_SEPARATOR'; + } + if ($this->isColumnModified(LangTableMap::THOUSANDS_SEPARATOR)) { + $modifiedColumns[':p' . $index++] = 'THOUSANDS_SEPARATOR'; + } + if ($this->isColumnModified(LangTableMap::DECIMALS)) { + $modifiedColumns[':p' . $index++] = 'DECIMALS'; } if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) { $modifiedColumns[':p' . $index++] = 'BY_DEFAULT'; } + if ($this->isColumnModified(LangTableMap::POSITION)) { + $modifiedColumns[':p' . $index++] = 'POSITION'; + } if ($this->isColumnModified(LangTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; } @@ -1026,12 +1290,30 @@ abstract class Lang implements ActiveRecordInterface case 'URL': $stmt->bindValue($identifier, $this->url, PDO::PARAM_STR); break; - case 'POSITION': - $stmt->bindValue($identifier, $this->position, PDO::PARAM_INT); + case 'DATE_FORMAT': + $stmt->bindValue($identifier, $this->date_format, PDO::PARAM_STR); + break; + case 'TIME_FORMAT': + $stmt->bindValue($identifier, $this->time_format, PDO::PARAM_STR); + break; + case 'DATETIME_FORMAT': + $stmt->bindValue($identifier, $this->datetime_format, PDO::PARAM_STR); + break; + case 'DECIMAL_SEPARATOR': + $stmt->bindValue($identifier, $this->decimal_separator, PDO::PARAM_STR); + break; + case 'THOUSANDS_SEPARATOR': + $stmt->bindValue($identifier, $this->thousands_separator, PDO::PARAM_STR); + break; + case 'DECIMALS': + $stmt->bindValue($identifier, $this->decimals, PDO::PARAM_STR); break; case 'BY_DEFAULT': $stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT); break; + case 'POSITION': + $stmt->bindValue($identifier, $this->position, PDO::PARAM_INT); + break; case 'CREATED_AT': $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); break; @@ -1116,15 +1398,33 @@ abstract class Lang implements ActiveRecordInterface return $this->getUrl(); break; case 5: - return $this->getPosition(); + return $this->getDateFormat(); break; case 6: - return $this->getByDefault(); + return $this->getTimeFormat(); break; case 7: - return $this->getCreatedAt(); + return $this->getDatetimeFormat(); break; case 8: + return $this->getDecimalSeparator(); + break; + case 9: + return $this->getThousandsSeparator(); + break; + case 10: + return $this->getDecimals(); + break; + case 11: + return $this->getByDefault(); + break; + case 12: + return $this->getPosition(); + break; + case 13: + return $this->getCreatedAt(); + break; + case 14: return $this->getUpdatedAt(); break; default: @@ -1160,10 +1460,16 @@ abstract class Lang implements ActiveRecordInterface $keys[2] => $this->getCode(), $keys[3] => $this->getLocale(), $keys[4] => $this->getUrl(), - $keys[5] => $this->getPosition(), - $keys[6] => $this->getByDefault(), - $keys[7] => $this->getCreatedAt(), - $keys[8] => $this->getUpdatedAt(), + $keys[5] => $this->getDateFormat(), + $keys[6] => $this->getTimeFormat(), + $keys[7] => $this->getDatetimeFormat(), + $keys[8] => $this->getDecimalSeparator(), + $keys[9] => $this->getThousandsSeparator(), + $keys[10] => $this->getDecimals(), + $keys[11] => $this->getByDefault(), + $keys[12] => $this->getPosition(), + $keys[13] => $this->getCreatedAt(), + $keys[14] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1220,15 +1526,33 @@ abstract class Lang implements ActiveRecordInterface $this->setUrl($value); break; case 5: - $this->setPosition($value); + $this->setDateFormat($value); break; case 6: - $this->setByDefault($value); + $this->setTimeFormat($value); break; case 7: - $this->setCreatedAt($value); + $this->setDatetimeFormat($value); break; case 8: + $this->setDecimalSeparator($value); + break; + case 9: + $this->setThousandsSeparator($value); + break; + case 10: + $this->setDecimals($value); + break; + case 11: + $this->setByDefault($value); + break; + case 12: + $this->setPosition($value); + break; + case 13: + $this->setCreatedAt($value); + break; + case 14: $this->setUpdatedAt($value); break; } // switch() @@ -1260,10 +1584,16 @@ abstract class Lang implements ActiveRecordInterface if (array_key_exists($keys[2], $arr)) $this->setCode($arr[$keys[2]]); if (array_key_exists($keys[3], $arr)) $this->setLocale($arr[$keys[3]]); if (array_key_exists($keys[4], $arr)) $this->setUrl($arr[$keys[4]]); - if (array_key_exists($keys[5], $arr)) $this->setPosition($arr[$keys[5]]); - if (array_key_exists($keys[6], $arr)) $this->setByDefault($arr[$keys[6]]); - if (array_key_exists($keys[7], $arr)) $this->setCreatedAt($arr[$keys[7]]); - if (array_key_exists($keys[8], $arr)) $this->setUpdatedAt($arr[$keys[8]]); + if (array_key_exists($keys[5], $arr)) $this->setDateFormat($arr[$keys[5]]); + if (array_key_exists($keys[6], $arr)) $this->setTimeFormat($arr[$keys[6]]); + if (array_key_exists($keys[7], $arr)) $this->setDatetimeFormat($arr[$keys[7]]); + if (array_key_exists($keys[8], $arr)) $this->setDecimalSeparator($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setThousandsSeparator($arr[$keys[9]]); + if (array_key_exists($keys[10], $arr)) $this->setDecimals($arr[$keys[10]]); + if (array_key_exists($keys[11], $arr)) $this->setByDefault($arr[$keys[11]]); + if (array_key_exists($keys[12], $arr)) $this->setPosition($arr[$keys[12]]); + if (array_key_exists($keys[13], $arr)) $this->setCreatedAt($arr[$keys[13]]); + if (array_key_exists($keys[14], $arr)) $this->setUpdatedAt($arr[$keys[14]]); } /** @@ -1280,8 +1610,14 @@ abstract class Lang implements ActiveRecordInterface if ($this->isColumnModified(LangTableMap::CODE)) $criteria->add(LangTableMap::CODE, $this->code); if ($this->isColumnModified(LangTableMap::LOCALE)) $criteria->add(LangTableMap::LOCALE, $this->locale); if ($this->isColumnModified(LangTableMap::URL)) $criteria->add(LangTableMap::URL, $this->url); - if ($this->isColumnModified(LangTableMap::POSITION)) $criteria->add(LangTableMap::POSITION, $this->position); + if ($this->isColumnModified(LangTableMap::DATE_FORMAT)) $criteria->add(LangTableMap::DATE_FORMAT, $this->date_format); + if ($this->isColumnModified(LangTableMap::TIME_FORMAT)) $criteria->add(LangTableMap::TIME_FORMAT, $this->time_format); + if ($this->isColumnModified(LangTableMap::DATETIME_FORMAT)) $criteria->add(LangTableMap::DATETIME_FORMAT, $this->datetime_format); + if ($this->isColumnModified(LangTableMap::DECIMAL_SEPARATOR)) $criteria->add(LangTableMap::DECIMAL_SEPARATOR, $this->decimal_separator); + if ($this->isColumnModified(LangTableMap::THOUSANDS_SEPARATOR)) $criteria->add(LangTableMap::THOUSANDS_SEPARATOR, $this->thousands_separator); + if ($this->isColumnModified(LangTableMap::DECIMALS)) $criteria->add(LangTableMap::DECIMALS, $this->decimals); if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) $criteria->add(LangTableMap::BY_DEFAULT, $this->by_default); + if ($this->isColumnModified(LangTableMap::POSITION)) $criteria->add(LangTableMap::POSITION, $this->position); if ($this->isColumnModified(LangTableMap::CREATED_AT)) $criteria->add(LangTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(LangTableMap::UPDATED_AT)) $criteria->add(LangTableMap::UPDATED_AT, $this->updated_at); @@ -1351,8 +1687,14 @@ abstract class Lang implements ActiveRecordInterface $copyObj->setCode($this->getCode()); $copyObj->setLocale($this->getLocale()); $copyObj->setUrl($this->getUrl()); - $copyObj->setPosition($this->getPosition()); + $copyObj->setDateFormat($this->getDateFormat()); + $copyObj->setTimeFormat($this->getTimeFormat()); + $copyObj->setDatetimeFormat($this->getDatetimeFormat()); + $copyObj->setDecimalSeparator($this->getDecimalSeparator()); + $copyObj->setThousandsSeparator($this->getThousandsSeparator()); + $copyObj->setDecimals($this->getDecimals()); $copyObj->setByDefault($this->getByDefault()); + $copyObj->setPosition($this->getPosition()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); if ($makeNew) { @@ -1393,8 +1735,14 @@ abstract class Lang implements ActiveRecordInterface $this->code = null; $this->locale = null; $this->url = null; - $this->position = null; + $this->date_format = null; + $this->time_format = null; + $this->datetime_format = null; + $this->decimal_separator = null; + $this->thousands_separator = null; + $this->decimals = null; $this->by_default = null; + $this->position = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; diff --git a/core/lib/Thelia/Model/Base/LangQuery.php b/core/lib/Thelia/Model/Base/LangQuery.php index a5100c5f8..2fabec9ee 100755 --- a/core/lib/Thelia/Model/Base/LangQuery.php +++ b/core/lib/Thelia/Model/Base/LangQuery.php @@ -23,8 +23,14 @@ use Thelia\Model\Map\LangTableMap; * @method ChildLangQuery orderByCode($order = Criteria::ASC) Order by the code column * @method ChildLangQuery orderByLocale($order = Criteria::ASC) Order by the locale column * @method ChildLangQuery orderByUrl($order = Criteria::ASC) Order by the url column - * @method ChildLangQuery orderByPosition($order = Criteria::ASC) Order by the position column + * @method ChildLangQuery orderByDateFormat($order = Criteria::ASC) Order by the date_format column + * @method ChildLangQuery orderByTimeFormat($order = Criteria::ASC) Order by the time_format column + * @method ChildLangQuery orderByDatetimeFormat($order = Criteria::ASC) Order by the datetime_format column + * @method ChildLangQuery orderByDecimalSeparator($order = Criteria::ASC) Order by the decimal_separator column + * @method ChildLangQuery orderByThousandsSeparator($order = Criteria::ASC) Order by the thousands_separator column + * @method ChildLangQuery orderByDecimals($order = Criteria::ASC) Order by the decimals column * @method ChildLangQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column + * @method ChildLangQuery orderByPosition($order = Criteria::ASC) Order by the position column * @method ChildLangQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildLangQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * @@ -33,8 +39,14 @@ use Thelia\Model\Map\LangTableMap; * @method ChildLangQuery groupByCode() Group by the code column * @method ChildLangQuery groupByLocale() Group by the locale column * @method ChildLangQuery groupByUrl() Group by the url column - * @method ChildLangQuery groupByPosition() Group by the position column + * @method ChildLangQuery groupByDateFormat() Group by the date_format column + * @method ChildLangQuery groupByTimeFormat() Group by the time_format column + * @method ChildLangQuery groupByDatetimeFormat() Group by the datetime_format column + * @method ChildLangQuery groupByDecimalSeparator() Group by the decimal_separator column + * @method ChildLangQuery groupByThousandsSeparator() Group by the thousands_separator column + * @method ChildLangQuery groupByDecimals() Group by the decimals column * @method ChildLangQuery groupByByDefault() Group by the by_default column + * @method ChildLangQuery groupByPosition() Group by the position column * @method ChildLangQuery groupByCreatedAt() Group by the created_at column * @method ChildLangQuery groupByUpdatedAt() Group by the updated_at column * @@ -50,8 +62,14 @@ use Thelia\Model\Map\LangTableMap; * @method ChildLang findOneByCode(string $code) Return the first ChildLang filtered by the code column * @method ChildLang findOneByLocale(string $locale) Return the first ChildLang filtered by the locale column * @method ChildLang findOneByUrl(string $url) Return the first ChildLang filtered by the url column - * @method ChildLang findOneByPosition(int $position) Return the first ChildLang filtered by the position column + * @method ChildLang findOneByDateFormat(string $date_format) Return the first ChildLang filtered by the date_format column + * @method ChildLang findOneByTimeFormat(string $time_format) Return the first ChildLang filtered by the time_format column + * @method ChildLang findOneByDatetimeFormat(string $datetime_format) Return the first ChildLang filtered by the datetime_format column + * @method ChildLang findOneByDecimalSeparator(string $decimal_separator) Return the first ChildLang filtered by the decimal_separator column + * @method ChildLang findOneByThousandsSeparator(string $thousands_separator) Return the first ChildLang filtered by the thousands_separator column + * @method ChildLang findOneByDecimals(string $decimals) Return the first ChildLang filtered by the decimals column * @method ChildLang findOneByByDefault(int $by_default) Return the first ChildLang filtered by the by_default column + * @method ChildLang findOneByPosition(int $position) Return the first ChildLang filtered by the position column * @method ChildLang findOneByCreatedAt(string $created_at) Return the first ChildLang filtered by the created_at column * @method ChildLang findOneByUpdatedAt(string $updated_at) Return the first ChildLang filtered by the updated_at column * @@ -60,8 +78,14 @@ use Thelia\Model\Map\LangTableMap; * @method array findByCode(string $code) Return ChildLang objects filtered by the code column * @method array findByLocale(string $locale) Return ChildLang objects filtered by the locale column * @method array findByUrl(string $url) Return ChildLang objects filtered by the url column - * @method array findByPosition(int $position) Return ChildLang objects filtered by the position column + * @method array findByDateFormat(string $date_format) Return ChildLang objects filtered by the date_format column + * @method array findByTimeFormat(string $time_format) Return ChildLang objects filtered by the time_format column + * @method array findByDatetimeFormat(string $datetime_format) Return ChildLang objects filtered by the datetime_format column + * @method array findByDecimalSeparator(string $decimal_separator) Return ChildLang objects filtered by the decimal_separator column + * @method array findByThousandsSeparator(string $thousands_separator) Return ChildLang objects filtered by the thousands_separator column + * @method array findByDecimals(string $decimals) Return ChildLang objects filtered by the decimals column * @method array findByByDefault(int $by_default) Return ChildLang objects filtered by the by_default column + * @method array findByPosition(int $position) Return ChildLang objects filtered by the position column * @method array findByCreatedAt(string $created_at) Return ChildLang objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildLang objects filtered by the updated_at column * @@ -152,7 +176,7 @@ abstract class LangQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, POSITION, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0'; + $sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR, DECIMALS, BY_DEFAULT, POSITION, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -399,44 +423,177 @@ abstract class LangQuery extends ModelCriteria } /** - * Filter the query on the position column + * Filter the query on the date_format column * * Example usage: * - * $query->filterByPosition(1234); // WHERE position = 1234 - * $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34) - * $query->filterByPosition(array('min' => 12)); // WHERE position > 12 + * $query->filterByDateFormat('fooValue'); // WHERE date_format = 'fooValue' + * $query->filterByDateFormat('%fooValue%'); // WHERE date_format LIKE '%fooValue%' * * - * @param mixed $position The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $dateFormat The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return ChildLangQuery The current query, for fluid interface */ - public function filterByPosition($position = null, $comparison = null) + public function filterByDateFormat($dateFormat = null, $comparison = null) { - if (is_array($position)) { - $useMinMax = false; - if (isset($position['min'])) { - $this->addUsingAlias(LangTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($position['max'])) { - $this->addUsingAlias(LangTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { + if (null === $comparison) { + if (is_array($dateFormat)) { $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $dateFormat)) { + $dateFormat = str_replace('*', '%', $dateFormat); + $comparison = Criteria::LIKE; } } - return $this->addUsingAlias(LangTableMap::POSITION, $position, $comparison); + return $this->addUsingAlias(LangTableMap::DATE_FORMAT, $dateFormat, $comparison); + } + + /** + * Filter the query on the time_format column + * + * Example usage: + * + * $query->filterByTimeFormat('fooValue'); // WHERE time_format = 'fooValue' + * $query->filterByTimeFormat('%fooValue%'); // WHERE time_format LIKE '%fooValue%' + * + * + * @param string $timeFormat The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByTimeFormat($timeFormat = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($timeFormat)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $timeFormat)) { + $timeFormat = str_replace('*', '%', $timeFormat); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(LangTableMap::TIME_FORMAT, $timeFormat, $comparison); + } + + /** + * Filter the query on the datetime_format column + * + * Example usage: + * + * $query->filterByDatetimeFormat('fooValue'); // WHERE datetime_format = 'fooValue' + * $query->filterByDatetimeFormat('%fooValue%'); // WHERE datetime_format LIKE '%fooValue%' + * + * + * @param string $datetimeFormat The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByDatetimeFormat($datetimeFormat = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($datetimeFormat)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $datetimeFormat)) { + $datetimeFormat = str_replace('*', '%', $datetimeFormat); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(LangTableMap::DATETIME_FORMAT, $datetimeFormat, $comparison); + } + + /** + * Filter the query on the decimal_separator column + * + * Example usage: + * + * $query->filterByDecimalSeparator('fooValue'); // WHERE decimal_separator = 'fooValue' + * $query->filterByDecimalSeparator('%fooValue%'); // WHERE decimal_separator LIKE '%fooValue%' + * + * + * @param string $decimalSeparator The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByDecimalSeparator($decimalSeparator = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($decimalSeparator)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $decimalSeparator)) { + $decimalSeparator = str_replace('*', '%', $decimalSeparator); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(LangTableMap::DECIMAL_SEPARATOR, $decimalSeparator, $comparison); + } + + /** + * Filter the query on the thousands_separator column + * + * Example usage: + * + * $query->filterByThousandsSeparator('fooValue'); // WHERE thousands_separator = 'fooValue' + * $query->filterByThousandsSeparator('%fooValue%'); // WHERE thousands_separator LIKE '%fooValue%' + * + * + * @param string $thousandsSeparator The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByThousandsSeparator($thousandsSeparator = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($thousandsSeparator)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $thousandsSeparator)) { + $thousandsSeparator = str_replace('*', '%', $thousandsSeparator); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(LangTableMap::THOUSANDS_SEPARATOR, $thousandsSeparator, $comparison); + } + + /** + * Filter the query on the decimals column + * + * Example usage: + * + * $query->filterByDecimals('fooValue'); // WHERE decimals = 'fooValue' + * $query->filterByDecimals('%fooValue%'); // WHERE decimals LIKE '%fooValue%' + * + * + * @param string $decimals The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByDecimals($decimals = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($decimals)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $decimals)) { + $decimals = str_replace('*', '%', $decimals); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(LangTableMap::DECIMALS, $decimals, $comparison); } /** @@ -480,6 +637,47 @@ abstract class LangQuery extends ModelCriteria return $this->addUsingAlias(LangTableMap::BY_DEFAULT, $byDefault, $comparison); } + /** + * Filter the query on the position column + * + * Example usage: + * + * $query->filterByPosition(1234); // WHERE position = 1234 + * $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34) + * $query->filterByPosition(array('min' => 12)); // WHERE position > 12 + * + * + * @param mixed $position The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildLangQuery The current query, for fluid interface + */ + public function filterByPosition($position = null, $comparison = null) + { + if (is_array($position)) { + $useMinMax = false; + if (isset($position['min'])) { + $this->addUsingAlias(LangTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($position['max'])) { + $this->addUsingAlias(LangTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(LangTableMap::POSITION, $position, $comparison); + } + /** * Filter the query on the created_at column * diff --git a/core/lib/Thelia/Model/Lang.php b/core/lib/Thelia/Model/Lang.php index 654c89719..d6b1a204c 100755 --- a/core/lib/Thelia/Model/Lang.php +++ b/core/lib/Thelia/Model/Lang.php @@ -23,34 +23,4 @@ class Lang extends BaseLang { return $default_lang; } - - public function getDateFormat() - { - return "d/m/Y"; - } - - public function getTimeFormat() - { - return "H:i:s"; - } - - public function getDateTimeFormat() - { - return "d/m/Y H:i:s"; - } - - public function getDecimalSeparator() - { - return "."; - } - - public function getThousandsSeparator() - { - return " "; - } - - public function getDecimals() - { - return 2; - } } diff --git a/core/lib/Thelia/Model/Map/LangTableMap.php b/core/lib/Thelia/Model/Map/LangTableMap.php index 9eb864388..6d153b869 100755 --- a/core/lib/Thelia/Model/Map/LangTableMap.php +++ b/core/lib/Thelia/Model/Map/LangTableMap.php @@ -57,7 +57,7 @@ class LangTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 9; + const NUM_COLUMNS = 15; /** * The number of lazy-loaded columns @@ -67,7 +67,7 @@ class LangTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 9; + const NUM_HYDRATE_COLUMNS = 15; /** * the column name for the ID field @@ -95,15 +95,45 @@ class LangTableMap extends TableMap const URL = 'lang.URL'; /** - * the column name for the POSITION field + * the column name for the DATE_FORMAT field */ - const POSITION = 'lang.POSITION'; + const DATE_FORMAT = 'lang.DATE_FORMAT'; + + /** + * the column name for the TIME_FORMAT field + */ + const TIME_FORMAT = 'lang.TIME_FORMAT'; + + /** + * the column name for the DATETIME_FORMAT field + */ + const DATETIME_FORMAT = 'lang.DATETIME_FORMAT'; + + /** + * the column name for the DECIMAL_SEPARATOR field + */ + const DECIMAL_SEPARATOR = 'lang.DECIMAL_SEPARATOR'; + + /** + * the column name for the THOUSANDS_SEPARATOR field + */ + const THOUSANDS_SEPARATOR = 'lang.THOUSANDS_SEPARATOR'; + + /** + * the column name for the DECIMALS field + */ + const DECIMALS = 'lang.DECIMALS'; /** * the column name for the BY_DEFAULT field */ const BY_DEFAULT = 'lang.BY_DEFAULT'; + /** + * the column name for the POSITION field + */ + const POSITION = 'lang.POSITION'; + /** * the column name for the CREATED_AT field */ @@ -126,12 +156,12 @@ class LangTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'Position', 'ByDefault', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'byDefault', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::POSITION, LangTableMap::BY_DEFAULT, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'POSITION', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'by_default', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, ) + self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'DateFormat', 'TimeFormat', 'DatetimeFormat', 'DecimalSeparator', 'ThousandsSeparator', 'Decimals', 'ByDefault', 'Position', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'dateFormat', 'timeFormat', 'datetimeFormat', 'decimalSeparator', 'thousandsSeparator', 'decimals', 'byDefault', 'position', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::DATE_FORMAT, LangTableMap::TIME_FORMAT, LangTableMap::DATETIME_FORMAT, LangTableMap::DECIMAL_SEPARATOR, LangTableMap::THOUSANDS_SEPARATOR, LangTableMap::DECIMALS, LangTableMap::BY_DEFAULT, LangTableMap::POSITION, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'DATE_FORMAT', 'TIME_FORMAT', 'DATETIME_FORMAT', 'DECIMAL_SEPARATOR', 'THOUSANDS_SEPARATOR', 'DECIMALS', 'BY_DEFAULT', 'POSITION', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'date_format', 'time_format', 'datetime_format', 'decimal_separator', 'thousands_separator', 'decimals', 'by_default', 'position', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ) ); /** @@ -141,12 +171,12 @@ class LangTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'Position' => 5, 'ByDefault' => 6, 'CreatedAt' => 7, 'UpdatedAt' => 8, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'byDefault' => 6, 'createdAt' => 7, 'updatedAt' => 8, ), - self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::POSITION => 5, LangTableMap::BY_DEFAULT => 6, LangTableMap::CREATED_AT => 7, LangTableMap::UPDATED_AT => 8, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'POSITION' => 5, 'BY_DEFAULT' => 6, 'CREATED_AT' => 7, 'UPDATED_AT' => 8, ), - self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'by_default' => 6, 'created_at' => 7, 'updated_at' => 8, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, ) + self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'DateFormat' => 5, 'TimeFormat' => 6, 'DatetimeFormat' => 7, 'DecimalSeparator' => 8, 'ThousandsSeparator' => 9, 'Decimals' => 10, 'ByDefault' => 11, 'Position' => 12, 'CreatedAt' => 13, 'UpdatedAt' => 14, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'dateFormat' => 5, 'timeFormat' => 6, 'datetimeFormat' => 7, 'decimalSeparator' => 8, 'thousandsSeparator' => 9, 'decimals' => 10, 'byDefault' => 11, 'position' => 12, 'createdAt' => 13, 'updatedAt' => 14, ), + self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::DATE_FORMAT => 5, LangTableMap::TIME_FORMAT => 6, LangTableMap::DATETIME_FORMAT => 7, LangTableMap::DECIMAL_SEPARATOR => 8, LangTableMap::THOUSANDS_SEPARATOR => 9, LangTableMap::DECIMALS => 10, LangTableMap::BY_DEFAULT => 11, LangTableMap::POSITION => 12, LangTableMap::CREATED_AT => 13, LangTableMap::UPDATED_AT => 14, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'DATE_FORMAT' => 5, 'TIME_FORMAT' => 6, 'DATETIME_FORMAT' => 7, 'DECIMAL_SEPARATOR' => 8, 'THOUSANDS_SEPARATOR' => 9, 'DECIMALS' => 10, 'BY_DEFAULT' => 11, 'POSITION' => 12, 'CREATED_AT' => 13, 'UPDATED_AT' => 14, ), + self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'date_format' => 5, 'time_format' => 6, 'datetime_format' => 7, 'decimal_separator' => 8, 'thousands_separator' => 9, 'decimals' => 10, 'by_default' => 11, 'position' => 12, 'created_at' => 13, 'updated_at' => 14, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ) ); /** @@ -170,8 +200,14 @@ class LangTableMap extends TableMap $this->addColumn('CODE', 'Code', 'VARCHAR', false, 10, null); $this->addColumn('LOCALE', 'Locale', 'VARCHAR', false, 45, null); $this->addColumn('URL', 'Url', 'VARCHAR', false, 255, null); - $this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null); + $this->addColumn('DATE_FORMAT', 'DateFormat', 'VARCHAR', false, 45, null); + $this->addColumn('TIME_FORMAT', 'TimeFormat', 'VARCHAR', false, 45, null); + $this->addColumn('DATETIME_FORMAT', 'DatetimeFormat', 'VARCHAR', false, 45, null); + $this->addColumn('DECIMAL_SEPARATOR', 'DecimalSeparator', 'VARCHAR', false, 45, null); + $this->addColumn('THOUSANDS_SEPARATOR', 'ThousandsSeparator', 'VARCHAR', false, 45, null); + $this->addColumn('DECIMALS', 'Decimals', 'VARCHAR', false, 45, null); $this->addColumn('BY_DEFAULT', 'ByDefault', 'TINYINT', false, null, null); + $this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -339,8 +375,14 @@ class LangTableMap extends TableMap $criteria->addSelectColumn(LangTableMap::CODE); $criteria->addSelectColumn(LangTableMap::LOCALE); $criteria->addSelectColumn(LangTableMap::URL); - $criteria->addSelectColumn(LangTableMap::POSITION); + $criteria->addSelectColumn(LangTableMap::DATE_FORMAT); + $criteria->addSelectColumn(LangTableMap::TIME_FORMAT); + $criteria->addSelectColumn(LangTableMap::DATETIME_FORMAT); + $criteria->addSelectColumn(LangTableMap::DECIMAL_SEPARATOR); + $criteria->addSelectColumn(LangTableMap::THOUSANDS_SEPARATOR); + $criteria->addSelectColumn(LangTableMap::DECIMALS); $criteria->addSelectColumn(LangTableMap::BY_DEFAULT); + $criteria->addSelectColumn(LangTableMap::POSITION); $criteria->addSelectColumn(LangTableMap::CREATED_AT); $criteria->addSelectColumn(LangTableMap::UPDATED_AT); } else { @@ -349,8 +391,14 @@ class LangTableMap extends TableMap $criteria->addSelectColumn($alias . '.CODE'); $criteria->addSelectColumn($alias . '.LOCALE'); $criteria->addSelectColumn($alias . '.URL'); - $criteria->addSelectColumn($alias . '.POSITION'); + $criteria->addSelectColumn($alias . '.DATE_FORMAT'); + $criteria->addSelectColumn($alias . '.TIME_FORMAT'); + $criteria->addSelectColumn($alias . '.DATETIME_FORMAT'); + $criteria->addSelectColumn($alias . '.DECIMAL_SEPARATOR'); + $criteria->addSelectColumn($alias . '.THOUSANDS_SEPARATOR'); + $criteria->addSelectColumn($alias . '.DECIMALS'); $criteria->addSelectColumn($alias . '.BY_DEFAULT'); + $criteria->addSelectColumn($alias . '.POSITION'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } diff --git a/install/insert.sql b/install/insert.sql index a4b7d3c1b..a2e5868e4 100755 --- a/install/insert.sql +++ b/install/insert.sql @@ -1,8 +1,8 @@ -INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`by_default`,`created_at`,`updated_at`)VALUES -(1, 'Français', 'fr', 'fr_FR', '','1', NOW(), NOW()), -(2, 'English', 'en', 'en_EN', '', '0', NOW(), NOW()), -(3, 'Espanol', 'es', 'es_ES', '', '0', NOW(), NOW()), -(4, 'Italiano', 'it', 'it_IT', '','0', NOW(), NOW()); +INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`date_format`,`time_format`,`datetime_format`,`decimal_separator`,`thousands_separator`,`decimals`,`by_default`,`created_at`,`updated_at`)VALUES +(1, 'Français', 'fr', 'fr_FR', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '1', NOW(), NOW()), +(2, 'English', 'en', 'en_EN', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', '.', ' ', '2', '0', NOW(), NOW()), +(3, 'castellano', 'es', 'es_ES', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', ',', '.', '2', '0', NOW(), NOW()), +(4, 'Italiano', 'it', 'it_IT', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '0', NOW(), NOW()); INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES ('session_config.default', '1', 1, 1, NOW(), NOW()), diff --git a/install/thelia.sql b/install/thelia.sql index 85c00b369..879f323b9 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -522,8 +522,14 @@ CREATE TABLE `lang` `code` VARCHAR(10), `locale` VARCHAR(45), `url` VARCHAR(255), - `position` INTEGER, + `date_format` VARCHAR(45), + `time_format` VARCHAR(45), + `datetime_format` VARCHAR(45), + `decimal_separator` VARCHAR(45), + `thousands_separator` VARCHAR(45), + `decimals` VARCHAR(45), `by_default` TINYINT, + `position` INTEGER, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) diff --git a/local/config/schema.xml b/local/config/schema.xml index 26023b117..a9d7badc4 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -389,8 +389,14 @@ - + + + + + + +
From fae48e9ee48237c05379295e6d7496baf471610e Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 08:35:47 +0200 Subject: [PATCH 09/39] fix issue in Lang Model --- core/lib/Thelia/Model/Lang.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/core/lib/Thelia/Model/Lang.php b/core/lib/Thelia/Model/Lang.php index d6b1a204c..3c45ade33 100755 --- a/core/lib/Thelia/Model/Lang.php +++ b/core/lib/Thelia/Model/Lang.php @@ -9,17 +9,14 @@ class Lang extends BaseLang { /** * Return the default language object, using a local variable to cache it. * - * @throws RuntimeException + * @throws \RuntimeException */ - private static $default_lang = null; - public static function getDefaultLanguage() { - if (self::$default_lang == null) { - $default_lang = LangQuery::create()->findOneByByDefault(true); - if ($default_lang == null) throw new RuntimeException("No default language is defined. Please define one."); - } + $default_lang = LangQuery::create()->findOneByByDefault(1); + + if ($default_lang == null) throw new \RuntimeException("No default language is defined. Please define one."); return $default_lang; } From c22761b60ab61bb47f5648725854b2d8e2f80fb6 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 09:00:46 +0200 Subject: [PATCH 10/39] fix issue if base_url does not exists --- core/lib/Thelia/Tools/URL.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index 84d35b457..f234f9086 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -79,7 +79,8 @@ class URL */ public function getBaseUrl() { - $lang = $this->container->get('request')->getSession()->getLang(); + $request = $this->container->get('request'); + $lang = $request->getSession()->getLang(); // Check if we have a specific URL for each lang. $one_domain_foreach_lang = ConfigQuery::read("one_domain_foreach_lang", false); @@ -92,7 +93,7 @@ class URL } else { // Get the base URL - $base_url = ConfigQuery::read('base_url', null); + $base_url = ConfigQuery::read('base_url', $request->getSchemeAndHttpHost()); $err_msg_part = sprintf('base_url for lang %s', $lang->getCode()); } From 86892f7af6ef66efeb2363b5363da86165c86069 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 09:10:53 +0200 Subject: [PATCH 11/39] fix issue for retrieving default view in defaultController --- core/lib/Thelia/Controller/Front/DefaultController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/lib/Thelia/Controller/Front/DefaultController.php b/core/lib/Thelia/Controller/Front/DefaultController.php index a08451cc0..58501ebb0 100755 --- a/core/lib/Thelia/Controller/Front/DefaultController.php +++ b/core/lib/Thelia/Controller/Front/DefaultController.php @@ -49,7 +49,7 @@ class DefaultController extends BaseFrontController if(ConfigQuery::isRewritingEnable()) { /* Does the query GET parameters match a rewritten URL ? */ - $rewrittenUrl = URL::getInstance()->retrieveCurrent(); + $rewrittenUrl = URL::getInstance()->retrieveCurrent($request); if($rewrittenUrl->rewrittenUrl !== null) { /* 301 redirection to rewritten URL */ $this->redirect($rewrittenUrl->rewrittenUrl, 301); @@ -63,9 +63,13 @@ class DefaultController extends BaseFrontController $view = $request->request->get('view'); } } - if(!is_null($view)) { + if(null !== $view) { $request->attributes->set('_view', $view); } + if (null === $view && null === $request->attributes->get("_view")) { + $request->attributes->set("_view", "index"); + } + } } From b0ac5f3f03a5d092b8d62665d92b4426335da912 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 09:24:22 +0200 Subject: [PATCH 12/39] add more test on DefaultController --- .../Controller/DefaultControllerTest.php | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php b/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php index fda569435..cecbb0e68 100755 --- a/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php +++ b/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php @@ -43,7 +43,7 @@ class DefaultControllerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($request->attributes->get('_view'), "index"); } - public function testNoActionWithQuery() + public function testNoActionWithGetParam() { $defaultController = new DefaultController(); $request = new Request(array( @@ -55,15 +55,59 @@ class DefaultControllerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($request->attributes->get('_view'), 'foo'); } - public function testNoActionWithRequest() + public function testNoActionWithPostParam() { $defaultController = new DefaultController(); - $request = new Request(array(), array( - "view" => "foo" - )); + $request = new Request( + array(), + array("view" => "foo") + ); $defaultController->noAction($request); $this->assertEquals($request->attributes->get('_view'), 'foo'); } + + + public function testNoActionWithAttribute() + { + $defaultController = new DefaultController(); + $request = new Request( + array(), + array(), + array("_view" => "foo") + ); + + $defaultController->noAction($request); + + $this->assertEquals($request->attributes->get('_view'), 'foo'); + } + + public function testNoActionWithAttributeAndQuery() + { + $defaultController = new DefaultController(); + $request = new Request( + array("view" => "bar"), + array(), + array("_view" => "foo") + ); + + $defaultController->noAction($request); + + $this->assertEquals($request->attributes->get('_view'), 'bar'); + } + + public function testNoActionWithAttirbuteAndRequest() + { + $defaultController = new DefaultController(); + $request = new Request( + array(), + array("view" => "bar"), + array("_view" => "foo") + ); + + $defaultController->noAction($request); + + $this->assertEquals($request->attributes->get('_view'), 'bar'); + } } From b70f5b1d6836bc6a7e40fdb078af099999c163d2 Mon Sep 17 00:00:00 2001 From: Manuel Raynaud Date: Thu, 5 Sep 2013 09:25:15 +0200 Subject: [PATCH 13/39] fix typo in method name --- core/lib/Thelia/Tests/Controller/DefaultControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php b/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php index cecbb0e68..33ea807e3 100755 --- a/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php +++ b/core/lib/Thelia/Tests/Controller/DefaultControllerTest.php @@ -97,7 +97,7 @@ class DefaultControllerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($request->attributes->get('_view'), 'bar'); } - public function testNoActionWithAttirbuteAndRequest() + public function testNoActionWithAttributeAndRequest() { $defaultController = new DefaultController(); $request = new Request( From 75513c778a2eb66aea5cd79ad1116cb5acaba73e Mon Sep 17 00:00:00 2001 From: mespeche Date: Thu, 5 Sep 2013 09:56:06 +0200 Subject: [PATCH 14/39] Working : New version of bootstrap-editable + Update of currency pages to bootstrap3 --- .../css/bootstrap-editable.css | 79 ++-- .../js/bootstrap-editable.js | 395 +++++------------- .../js/bootstrap-editable.min.js | 6 +- templates/admin/default/currencies.html | 268 ++++++------ templates/admin/default/currency-edit.html | 153 ++++--- 5 files changed, 355 insertions(+), 546 deletions(-) diff --git a/templates/admin/default/assets/bootstrap-editable/css/bootstrap-editable.css b/templates/admin/default/assets/bootstrap-editable/css/bootstrap-editable.css index 16de488fa..218e340ef 100755 --- a/templates/admin/default/assets/bootstrap-editable/css/bootstrap-editable.css +++ b/templates/admin/default/assets/bootstrap-editable/css/bootstrap-editable.css @@ -1,8 +1,7 @@ -/*! X-editable - v1.4.6 +/*! X-editable - v1.4.7 * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * http://github.com/vitalets/x-editable * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ - .editableform { margin-bottom: 0; /* overwrites bootstrap margin */ } @@ -18,45 +17,45 @@ vertical-align: top; margin-left: 7px; /* inline-block emulation for IE7*/ - zoom: 1; + zoom: 1; *display: inline; } .editable-buttons.editable-buttons-bottom { - display: block; + display: block; margin-top: 7px; margin-left: 0; } .editable-input { - vertical-align: top; + vertical-align: top; display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ white-space: normal; /* reset white-space decalred in parent*/ /* display-inline emulation for IE7*/ - zoom: 1; - *display: inline; + zoom: 1; + *display: inline; } .editable-buttons .editable-cancel { - margin-left: 7px; + margin-left: 7px; } /*for jquery-ui buttons need set height to look more pretty*/ .editable-buttons button.ui-button-icon-only { - height: 24px; + height: 24px; width: 30px; } .editableform-loading { - background: url('../img/loading.gif') center center no-repeat; + background: url('../img/loading.gif') center center no-repeat; height: 25px; - width: auto; - min-width: 25px; + width: auto; + min-width: 25px; } .editable-inline .editableform-loading { - background-position: left 5px; + background-position: left 5px; } .editable-error-block { @@ -68,17 +67,17 @@ /*add padding for jquery ui*/ .editable-error-block.ui-state-error { - padding: 3px; -} + padding: 3px; +} .editable-error { - color: red; + color: red; } /* ---- For specific types ---- */ .editableform .editable-date { - padding: 0; + padding: 0; margin: 0; float: left; } @@ -86,25 +85,25 @@ /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ .editable-inline .add-on .icon-th { margin-top: 3px; - margin-left: 1px; + margin-left: 1px; } /* checklist vertical alignment */ -.editable-checklist label input[type="checkbox"], +.editable-checklist label input[type="checkbox"], .editable-checklist label span { vertical-align: middle; margin: 0; } .editable-checklist label { - white-space: nowrap; + white-space: nowrap; } /* set exact width of textarea to fit buttons toolbar */ .editable-wysihtml5 { - width: 566px; - height: 250px; + width: 566px; + height: 250px; } /* clear button shown as link in date inputs */ @@ -119,16 +118,16 @@ .editable-clear-x { background: url('../img/clear.png') center center no-repeat; display: block; - width: 13px; + width: 13px; height: 13px; position: absolute; opacity: 0.6; z-index: 100; - + top: 50%; right: 6px; margin-top: -6px; - + } .editable-clear-x:hover { @@ -140,49 +139,49 @@ } .editable-container.editable-popup { max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ -} +} .editable-container.popover { width: auto; /* without this rule popover does not stretch */ } .editable-container.editable-inline { - display: inline-block; + display: inline-block; vertical-align: middle; width: auto; /* inline-block emulation for IE7*/ - zoom: 1; - *display: inline; + zoom: 1; + *display: inline; } .editable-container.ui-widget { font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ } -.editable-click, -a.editable-click, +.editable-click, +a.editable-click, a.editable-click:hover { text-decoration: none; - border-bottom: dotted 1px #0088cc; + border-bottom: dashed 1px #0088cc; } -.editable-click.editable-disabled, -a.editable-click.editable-disabled, +.editable-click.editable-disabled, +a.editable-click.editable-disabled, a.editable-click.editable-disabled:hover { - color: #585858; + color: #585858; cursor: default; border-bottom: none; } .editable-empty, .editable-empty:hover, .editable-empty:focus{ - font-style: italic; - color: #DD1144; + font-style: italic; + color: #DD1144; /* border-bottom: none; */ text-decoration: none; } .editable-unsaved { - font-weight: bold; + font-weight: bold; } .editable-unsaved:after { @@ -194,12 +193,12 @@ a.editable-click.editable-disabled:hover { -moz-transition: background-color 1400ms ease-out; -o-transition: background-color 1400ms ease-out; -ms-transition: background-color 1400ms ease-out; - transition: background-color 1400ms ease-out; + transition: background-color 1400ms ease-out; } /*see https://github.com/vitalets/x-editable/issues/139 */ .form-horizontal .editable -{ +{ padding-top: 5px; display:inline-block; } diff --git a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.js b/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.js index b70ea20bb..fc9959272 100755 --- a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.js +++ b/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.js @@ -1,8 +1,7 @@ -/*! X-editable - v1.4.6 +/*! X-editable - v1.4.7 * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * http://github.com/vitalets/x-editable * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ - /** Form with single input element, two buttons and two states: normal/loading. Applied as jQuery method to DIV tag (not to form tag!). This is because form can be in loading state when spinner shown. @@ -33,6 +32,9 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. //set initial value //todo: may be add check: typeof str === 'string' ? this.value = this.input.str2value(this.options.value); + + //prerender: get input.$input + this.input.prerender(); }, initTemplate: function() { this.$form = $($.fn.editableform.template); @@ -80,9 +82,8 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. this.initInput(); //append input to form - this.input.prerender(); this.$form.find('div.editable-input').append(this.input.$tpl); - + //append form to container this.$div.append(this.$form); @@ -620,6 +621,9 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. //error class attached to editable-error-block $.fn.editableform.errorBlockClass = 'editable-error'; + + //engine + $.fn.editableform.engine = 'jqeury'; }(window.jQuery)); /** @@ -898,6 +902,8 @@ Applied as jQuery method. containerDataName: null, //object name in element's .data() innerCss: null, //tbd in child class containerClass: 'editable-container editable-popup', //css class applied to container element + defaults: {}, //container itself defaults + init: function(element, options) { this.$element = $(element); //since 1.4.1 container do not use data-* directly as they already merged into options. @@ -975,10 +981,9 @@ Applied as jQuery method. throw new Error(this.containerName + ' not found. Have you included corresponding js file?'); } - var cDef = $.fn[this.containerName].defaults; //keys defined in container defaults go to container, others go to form for(var k in this.options) { - if(k in cDef) { + if(k in this.defaults) { this.containerOptions[k] = this.options[k]; } else { this.formOptions[k] = this.options[k]; @@ -2249,7 +2254,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. @since 1.4.5 @default #FFFF80 **/ - highlight: '#FFFF80' + highlight: '#FFFF80' }; }(window.jQuery)); @@ -2415,7 +2420,7 @@ To create your own input you can inherit from this class. }, // -------- helper functions -------- - setClass: function() { + setClass: function() { if(this.options.inputclass) { this.$input.addClass(this.options.inputclass); } @@ -2447,9 +2452,9 @@ To create your own input you can inherit from this class. @property inputclass @type string - @default input-medium + @default null **/ - inputclass: 'input-medium', + inputclass: null, //scope for external methods (e.g. source defined as function) //for internal use only scope: null, @@ -3817,7 +3822,7 @@ $(function(){ @type string @default ', ' **/ - viewseparator: ', ' + viewseparator: ', ' }); $.fn.editabletypes.select2 = Constructor; @@ -4343,7 +4348,14 @@ $(function(){ $.extend(Constructor.prototype, { render: function () { this.$input.combodate(this.options.combodate); + + if($.fn.editableform.engine === 'bs3') { + this.$input.siblings().find('select').addClass('form-control'); + } + if(this.options.inputclass) { + this.$input.siblings().find('select').addClass(this.options.inputclass); + } //"clear" link /* if(this.options.clear) { @@ -4468,29 +4480,71 @@ $(function(){ }(window.jQuery)); /* -Editableform based on Twitter Bootstrap +Editableform based on Twitter Bootstrap 3 */ (function ($) { "use strict"; + //store parent methods + var pInitInput = $.fn.editableform.Constructor.prototype.initInput; + $.extend($.fn.editableform.Constructor.prototype, { - initTemplate: function() { + initTemplate: function() { this.$form = $($.fn.editableform.template); + this.$form.find('.control-group').addClass('form-group'); this.$form.find('.editable-error-block').addClass('help-block'); - } + }, + initInput: function() { + pInitInput.apply(this); + + //for bs3 set default class `input-sm` to standard inputs + var emptyInputClass = this.input.options.inputclass === null || this.input.options.inputclass === false; + var defaultClass = 'input-sm'; + + //bs3 add `form-control` class to standard inputs + var stdtypes = 'text,select,textarea,password,email,url,tel,number,range,time'.split(','); + if(~$.inArray(this.input.type, stdtypes)) { + this.input.$input.addClass('form-control'); + if(emptyInputClass) { + this.input.options.inputclass = defaultClass; + this.input.$input.addClass(defaultClass); + } + } + + //apply bs3 size class also to buttons (to fit size of control) + var $btn = this.$form.find('.editable-buttons'); + var classes = emptyInputClass ? [defaultClass] : this.input.options.inputclass.split(' '); + for(var i=0; i'; + $.fn.editableform.buttons = + ''+ + ''; //error classes - $.fn.editableform.errorGroupClass = 'error'; - $.fn.editableform.errorBlockClass = null; - + $.fn.editableform.errorGroupClass = 'has-error'; + $.fn.editableform.errorBlockClass = null; + //engine + $.fn.editableform.engine = 'bs3'; }(window.jQuery)); /** -* Editable Popover +* Editable Popover3 (for Bootstrap 3) * --------------------- * requires bootstrap-popover.js */ @@ -4500,15 +4554,16 @@ Editableform based on Twitter Bootstrap //extend methods $.extend($.fn.editableContainer.Popup.prototype, { containerName: 'popover', - //for compatibility with bootstrap <= 2.2.1 (content inserted into

instead of directly .popover-content) - innerCss: $.fn.popover && $($.fn.popover.defaults.template).find('p').length ? '.popover-content p' : '.popover-content', + containerDataName: 'bs.popover', + innerCss: '.popover-content', + defaults: $.fn.popover.Constructor.DEFAULTS, initContainer: function(){ $.extend(this.containerOptions, { trigger: 'manual', selector: false, content: ' ', - template: $.fn.popover.defaults.template + template: this.defaults.template }); //as template property is used in inputs, hide it from popover @@ -4548,10 +4603,11 @@ Editableform based on Twitter Bootstrap /** * move popover to new position. This function mainly copied from bootstrap-popover. */ - /*jshint laxcomma: true*/ + /*jshint laxcomma: true, eqeqeq: false*/ setPosition: function () { - (function() { + (function() { + /* var $tip = this.tip() , inside , pos @@ -4661,9 +4717,27 @@ Editableform based on Twitter Bootstrap .offset(tp) .addClass(placement) .addClass('in'); + */ + + + var $tip = this.tip(); + + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement; + + + var pos = this.getPosition(); + var actualWidth = $tip[0].offsetWidth; + var actualHeight = $tip[0].offsetHeight; + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight); + + this.applyPlacement(calculatedOffset, placement); + + }).call(this.container()); - /*jshint laxcomma: false*/ + /*jshint laxcomma: false, eqeqeq: true*/ } }); @@ -6555,273 +6629,4 @@ Automatically shown in inline mode. $.fn.editabletypes.datetimefield = DateTimeField; -}(window.jQuery)); -/** -Typeahead input (bootstrap only). Based on Twitter Bootstrap [typeahead](http://twitter.github.com/bootstrap/javascript.html#typeahead). -Depending on `source` format typeahead operates in two modes: - -* **strings**: - When `source` defined as array of strings, e.g. `['text1', 'text2', 'text3' ...]`. - User can submit one of these strings or any text entered in input (even if it is not matching source). - -* **objects**: - When `source` defined as array of objects, e.g. `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`. - User can submit only values that are in source (otherwise `null` is submitted). This is more like *dropdown* behavior. - -@class typeahead -@extends list -@since 1.4.1 -@final -@example - - -**/ -(function ($) { - "use strict"; - - var Constructor = function (options) { - this.init('typeahead', options, Constructor.defaults); - - //overriding objects in config (as by default jQuery extend() is not recursive) - this.options.typeahead = $.extend({}, Constructor.defaults.typeahead, { - //set default methods for typeahead to work with objects - matcher: this.matcher, - sorter: this.sorter, - highlighter: this.highlighter, - updater: this.updater - }, options.typeahead); - }; - - $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.list); - - $.extend(Constructor.prototype, { - renderList: function() { - this.$input = this.$tpl.is('input') ? this.$tpl : this.$tpl.find('input[type="text"]'); - - //set source of typeahead - this.options.typeahead.source = this.sourceData; - - //apply typeahead - this.$input.typeahead(this.options.typeahead); - - //patch some methods in typeahead - var ta = this.$input.data('typeahead'); - ta.render = $.proxy(this.typeaheadRender, ta); - ta.select = $.proxy(this.typeaheadSelect, ta); - ta.move = $.proxy(this.typeaheadMove, ta); - - this.renderClear(); - this.setClass(); - this.setAttr('placeholder'); - }, - - value2htmlFinal: function(value, element) { - if(this.getIsObjects()) { - var items = $.fn.editableutils.itemsByValue(value, this.sourceData); - $(element).text(items.length ? items[0].text : ''); - } else { - $(element).text(value); - } - }, - - html2value: function (html) { - return html ? html : null; - }, - - value2input: function(value) { - if(this.getIsObjects()) { - var items = $.fn.editableutils.itemsByValue(value, this.sourceData); - this.$input.data('value', value).val(items.length ? items[0].text : ''); - } else { - this.$input.val(value); - } - }, - - input2value: function() { - if(this.getIsObjects()) { - var value = this.$input.data('value'), - items = $.fn.editableutils.itemsByValue(value, this.sourceData); - - if(items.length && items[0].text.toLowerCase() === this.$input.val().toLowerCase()) { - return value; - } else { - return null; //entered string not found in source - } - } else { - return this.$input.val(); - } - }, - - /* - if in sourceData values <> texts, typeahead in "objects" mode: - user must pick some value from list, otherwise `null` returned. - if all values == texts put typeahead in "strings" mode: - anything what entered is submited. - */ - getIsObjects: function() { - if(this.isObjects === undefined) { - this.isObjects = false; - for(var i=0; i - **/ - tpl:'', - /** - Configuration of typeahead. [Full list of options](http://twitter.github.com/bootstrap/javascript.html#typeahead). - - @property typeahead - @type object - @default null - **/ - typeahead: null, - /** - Whether to show `clear` button - - @property clear - @type boolean - @default true - **/ - clear: true - }); - - $.fn.editabletypes.typeahead = Constructor; - }(window.jQuery)); \ No newline at end of file diff --git a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js b/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js index 13df29e24..7cd887651 100755 --- a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js +++ b/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js @@ -1,5 +1,7 @@ -/*! X-editable - v1.4.6 +/*! X-editable - v1.4.7 * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * http://github.com/vitalets/x-editable * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ -(function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.editableform.defaults,n),this.$div=e(t),this.options.scope||(this.options.scope=this)};t.prototype={constructor:t,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value)},initTemplate:function(){this.$form=e(e.fn.editableform.template)},initButtons:function(){var t=this.$form.find(".editable-buttons");t.append(e.fn.editableform.buttons),this.options.showbuttons==="bottom"&&t.addClass("editable-buttons-bottom")},render:function(){this.$loading=e(e.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.isSaving=!1,this.$div.triggerHandler("rendering"),this.initInput(),this.input.prerender(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),e.when(this.input.render()).then(e.proxy(function(){this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(e.proxy(this.cancel,this));if(this.input.error)this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(e){e.preventDefault()});else{this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled");var t=this.value===null||this.value===undefined||this.value===""?this.options.defaultValue:this.value;this.input.value2input(t),this.$form.submit(e.proxy(this.submit,this))}this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var e,t;this.$form?(e=this.$form.outerWidth(),t=this.$form.outerHeight(),e&&this.$loading.width(e),t&&this.$loading.height(t),this.$form.hide()):(e=this.$loading.parent().width(),e&&this.$loading.width(e)),this.$loading.show()},showForm:function(e){this.$loading.hide(),this.$form.show(),e!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(t){var n=this.$form.find(".control-group"),r=this.$form.find(".editable-error-block"),i;if(t===!1)n.removeClass(e.fn.editableform.errorGroupClass),r.removeClass(e.fn.editableform.errorBlockClass).empty().hide();else{if(t){i=t.split("\n");for(var s=0;s").text(i[s]).html();t=i.join("
")}n.addClass(e.fn.editableform.errorGroupClass),r.addClass(e.fn.editableform.errorBlockClass).html(t).show()}},submit:function(t){t.stopPropagation(),t.preventDefault();var n,r=this.input.input2value();if(n=this.validate(r)){this.error(n),this.showForm();return}if(!this.options.savenochange&&this.input.value2str(r)==this.input.value2str(this.value)){this.$div.triggerHandler("nochange");return}var i=this.input.value2submit(r);this.isSaving=!0,e.when(this.save(i)).done(e.proxy(function(e){this.isSaving=!1;var t=typeof this.options.success=="function"?this.options.success.call(this.options.scope,e,r):null;if(t===!1){this.error(!1),this.showForm(!1);return}if(typeof t=="string"){this.error(t),this.showForm();return}t&&typeof t=="object"&&t.hasOwnProperty("newValue")&&(r=t.newValue),this.error(!1),this.value=r,this.$div.triggerHandler("save",{newValue:r,submitValue:i,response:e})},this)).fail(e.proxy(function(e){this.isSaving=!1;var t;typeof this.options.error=="function"?t=this.options.error.call(this.options.scope,e,r):t=typeof e=="string"?e:e.responseText||e.statusText||"Unknown error!",this.error(t),this.showForm()},this))},save:function(t){this.options.pk=e.fn.editableutils.tryParseJson(this.options.pk,!0);var n=typeof this.options.pk=="function"?this.options.pk.call(this.options.scope):this.options.pk,r=!!(typeof this.options.url=="function"||this.options.url&&(this.options.send==="always"||this.options.send==="auto"&&n!==null&&n!==undefined)),i;if(r)return this.showLoading(),i={name:this.options.name||"",value:t,pk:n},typeof this.options.params=="function"?i=this.options.params.call(this.options.scope,i):(this.options.params=e.fn.editableutils.tryParseJson(this.options.params,!0),e.extend(i,this.options.params)),typeof this.options.url=="function"?this.options.url.call(this.options.scope,i):e.ajax(e.extend({url:this.options.url,data:i,type:"POST"},this.options.ajaxOptions))},validate:function(e){e===undefined&&(e=this.value);if(typeof this.options.validate=="function")return this.options.validate.call(this.options.scope,e)},option:function(e,t){e in this.options&&(this.options[e]=t),e==="value"&&this.setValue(t)},setValue:function(e,t){t?this.value=this.input.str2value(e):this.value=e,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},e.fn.editableform=function(n){var r=arguments;return this.each(function(){var i=e(this),s=i.data("editableform"),o=typeof n=="object"&&n;s||i.data("editableform",s=new t(this,o)),typeof n=="string"&&s[n].apply(s,Array.prototype.slice.call(r,1))})},e.fn.editableform.Constructor=t,e.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,defaultValue:null,send:"auto",validate:null,success:null,error:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},e.fn.editableform.template='

',e.fn.editableform.loading='
',e.fn.editableform.buttons='',e.fn.editableform.errorGroupClass=null,e.fn.editableform.errorBlockClass="editable-error"})(window.jQuery),function(e){"use strict";e.fn.editableutils={inherit:function(e,t){var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e,e.superclass=t.prototype},setCursorPosition:function(e,t){if(e.setSelectionRange)e.setSelectionRange(t,t);else if(e.createTextRange){var n=e.createTextRange();n.collapse(!0),n.moveEnd("character",t),n.moveStart("character",t),n.select()}},tryParseJson:function(e,t){if(typeof e=="string"&&e.length&&e.match(/^[\{\[].*[\}\]]$/))if(t)try{e=(new Function("return "+e))()}catch(n){}finally{return e}else e=(new Function("return "+e))();return e},sliceObj:function(t,n,r){var i,s,o={};if(!e.isArray(n)||!n.length)return o;for(var u=0;u").text(t).html()},itemsByValue:function(t,n,r){if(!n||t===null)return[];if(typeof r!="function"){var i=r||"value";r=function(e){return e[i]}}var s=e.isArray(t),o=[],u=this;return e.each(n,function(n,i){if(i.children)o=o.concat(u.itemsByValue(t,i.children,r));else if(s)e.grep(t,function(e){return e==(i&&typeof i==="object"?r(i):i)}).length&&o.push(i);else{var a=i&&typeof i=="object"?r(i):i;t==a&&o.push(i)}}),o},createInput:function(t){var n,r,i,s=t.type;return s==="date"&&(t.mode==="inline"?e.fn.editabletypes.datefield?s="datefield":e.fn.editabletypes.dateuifield&&(s="dateuifield"):e.fn.editabletypes.date?s="date":e.fn.editabletypes.dateui&&(s="dateui"),s==="date"&&!e.fn.editabletypes.date&&(s="combodate")),s==="datetime"&&t.mode==="inline"&&(s="datetimefield"),s==="wysihtml5"&&!e.fn.editabletypes[s]&&(s="textarea"),typeof e.fn.editabletypes[s]=="function"?(n=e.fn.editabletypes[s],r=this.sliceObj(t,this.objectKeys(n.defaults)),i=new n(r),i):(e.error("Unknown type: "+s),!1)},supportsTransitions:function(){var e=document.body||document.documentElement,t=e.style,n="transition",r=["Moz","Webkit","Khtml","O","ms"];if(typeof t[n]=="string")return!0;n=n.charAt(0).toUpperCase()+n.substr(1);for(var i=0;i"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(e){if(!this.tip()||!this.tip().is(":visible")||!this.$element.hasClass("editable-open"))return;if(this.$form.data("editableform").isSaving){this.delayedHide={reason:e};return}this.delayedHide=!1,this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",e||"manual")},innerShow:function(){},innerHide:function(){},toggle:function(e){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(e)},setPosition:function(){},save:function(e,t){this.$element.triggerHandler("save",t),this.hide("save")},option:function(e,t){this.options[e]=t,e in this.containerOptions?(this.containerOptions[e]=t,this.setContainerOption(e,t)):(this.formOptions[e]=t,this.$form&&this.$form.editableform("option",e,t))},setContainerOption:function(e,t){this.call("option",e,t)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(t){e(".editable-open").each(function(n,r){if(r===t||e(r).find(t).length)return;var i=e(r),s=i.data("editableContainer");if(!s)return;s.options.onblur==="cancel"?i.data("editableContainer").hide("onblur"):s.options.onblur==="submit"&&i.data("editableContainer").tip().find("form").submit()})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},e.fn.editableContainer=function(r){var i=arguments;return this.each(function(){var s=e(this),o="editableContainer",u=s.data(o),a=typeof r=="object"&&r,f=a.mode==="inline"?n:t;u||s.data(o,u=new f(this,a)),typeof r=="string"&&u[r].apply(u,Array.prototype.slice.call(i,1))})},e.fn.editableContainer.Popup=t,e.fn.editableContainer.Inline=n,e.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:!1,mode:"popup"},jQuery.event.special.destroyed={remove:function(e){e.handler&&e.handler()}}}(window.jQuery),function(e){"use strict";e.extend(e.fn.editableContainer.Inline.prototype,e.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=e(""),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,e.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.editable.defaults,n,e.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init(),this.options.highlight&&!e.fn.editableutils.supportsTransitions()&&(this.options.highlight=!1)};t.prototype={constructor:t,init:function(){var t=!1,n,r;this.options.name=this.options.name||this.$element.attr("id"),this.options.scope=this.$element[0],this.input=e.fn.editableutils.createInput(this.options);if(!this.input)return;this.options.value===undefined||this.options.value===null?(this.value=this.input.html2value(e.trim(this.$element.html())),t=!0):(this.options.value=e.fn.editableutils.tryParseJson(this.options.value,!0),typeof this.options.value=="string"?this.value=this.input.str2value(this.options.value):this.value=this.options.value),this.$element.addClass("editable"),this.input.type==="textarea"&&this.$element.addClass("editable-pre-wrapped"),this.options.toggle!=="manual"?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",e.proxy(function(e){this.options.disabled||e.preventDefault();if(this.options.toggle==="mouseenter")this.show();else{var t=this.options.toggle!=="click";this.toggle(t)}},this))):this.$element.attr("tabindex",-1),typeof this.options.display=="function"&&(this.options.autotext="always");switch(this.options.autotext){case"always":n=!0;break;case"auto":n=!e.trim(this.$element.text()).length&&this.value!==null&&this.value!==undefined&&!t;break;default:n=!1}e.when(n?this.render():!0).then(e.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))},initLive:function(){var t=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",t,e.proxy(function(t){var n=e(t.target);n.data("editable")||(n.hasClass(this.options.emptyclass)&&n.empty(),n.editable(this.options).trigger(t))},this))},render:function(e){if(this.options.display===!1)return;return this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,e):typeof this.options.display=="function"?this.options.display.call(this.$element[0],this.value,e):this.input.value2html(this.value,this.$element[0])},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.options.toggle!=="manual"&&this.$element.attr("tabindex")==="-1"&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(t,n){if(t&&typeof t=="object"){e.each(t,e.proxy(function(t,n){this.option(e.trim(t),n)},this));return}this.options[t]=n;if(t==="disabled")return n?this.disable():this.enable();t==="value"&&this.setValue(n),this.container&&this.container.option(t,n),this.input.option&&this.input.option(t,n)},handleEmpty:function(t){if(this.options.display===!1)return;t!==undefined?this.isEmpty=t:e.trim(this.$element.html())===""?this.isEmpty=!0:e.trim(this.$element.text())!==""?this.isEmpty=!1:this.isEmpty=!this.$element.height()||!this.$element.width(),this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.html(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)},show:function(t){if(this.options.disabled)return;if(!this.container){var n=e.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(n),this.$element.on("save.internal",e.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}else if(this.container.tip().is(":visible"))return;this.container.show(t)},hide:function(){this.container&&this.container.hide()},toggle:function(e){this.container&&this.container.tip().is(":visible")?this.hide():this.show(e)},save:function(e,t){if(this.options.unsavedclass){var n=!1;n=n||typeof this.options.url=="function",n=n||this.options.display===!1,n=n||t.response!==undefined,n=n||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(t.newValue),n?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}if(this.options.highlight){var r=this.$element,i=r.css("background-color");r.css("background-color",this.options.highlight),setTimeout(function(){i==="transparent"&&(i=""),r.css("background-color",i),r.addClass("editable-bg-transition"),setTimeout(function(){r.removeClass("editable-bg-transition")},1700)},10)}this.setValue(t.newValue,!1,t.response)},validate:function(){if(typeof this.options.validate=="function")return this.options.validate.call(this,this.value)},setValue:function(t,n,r){n?this.value=this.input.str2value(t):this.value=t,this.container&&this.container.option("value",this.value),e.when(this.render(r)).then(e.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.disable(),this.container&&this.container.destroy(),this.input.destroy(),this.options.toggle!=="manual"&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable editable-open editable-disabled"),this.$element.removeData("editable")}},e.fn.editable=function(n){var r={},i=arguments,s="editable";switch(n){case"validate":return this.each(function(){var t=e(this),n=t.data(s),i;n&&(i=n.validate())&&(r[n.options.name]=i)}),r;case"getValue":return arguments.length===2&&arguments[1]===!0?r=this.eq(0).data(s).value:this.each(function(){var t=e(this),n=t.data(s);n&&n.value!==undefined&&n.value!==null&&(r[n.options.name]=n.input.value2submit(n.value))}),r;case"submit":var o=arguments[1]||{},u=this,a=this.editable("validate"),f;return e.isEmptyObject(a)?(f=this.editable("getValue"),o.data&&e.extend(f,o.data),e.ajax(e.extend({url:o.url,data:f,type:"POST"},o.ajaxOptions)).success(function(e){typeof o.success=="function"&&o.success.call(u,e,o)}).error(function(){typeof o.error=="function"&&o.error.apply(u,arguments)})):typeof o.error=="function"&&o.error.call(u,a),this}return this.each(function(){var r=e(this),o=r.data(s),u=typeof n=="object"&&n;if(u&&u.selector){o=new t(this,u);return}o||r.data(s,o=new t(this,u)),typeof n=="string"&&o[n].apply(o,Array.prototype.slice.call(i,1))})},e.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null,highlight:"#FFFF80"}}(window.jQuery),function(e){"use strict";e.fn.editabletypes={};var t=function(){};t.prototype={init:function(t,n,r){this.type=t,this.options=e.extend({},r,n)},prerender:function(){this.$tpl=e(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(t,n){e(n).text(e.trim(t))},html2value:function(t){return e("
").html(t).text()},value2str:function(e){return e},str2value:function(e){return e},value2submit:function(e){return e},value2input:function(e){this.$input.val(e)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(t){return e("
").text(t).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(e){this.options[e]!==undefined&&this.options[e]!==null&&this.$input.attr(e,this.options[e])},option:function(e,t){this.options[e]=t}},t.defaults={tpl:"",inputclass:"input-medium",scope:null,showbuttons:!0},e.extend(e.fn.editabletypes,{abstractinput:t})}(window.jQuery),function(e){"use strict";var t=function(e){};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){var t=e.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),t.resolve()},function(){this.error=this.options.sourceError,t.resolve()}),t.promise()},html2value:function(e){return null},value2html:function(t,n,r,i){var s=e.Deferred(),o=function(){typeof r=="function"?r.call(n,t,this.sourceData,i):this.value2htmlFinal(t,n),s.resolve()};return t===null?o.call(this):this.onSourceReady(o,function(){s.resolve()}),s.promise()},onSourceReady:function(t,n){var r;e.isFunction(this.options.source)?(r=this.options.source.call(this.options.scope),this.sourceData=null):r=this.options.source;if(this.options.sourceCache&&e.isArray(this.sourceData)){t.call(this);return}try{r=e.fn.editableutils.tryParseJson(r,!1)}catch(i){n.call(this);return}if(typeof r=="string"){if(this.options.sourceCache){var s=r,o;e(document).data(s)||e(document).data(s,{}),o=e(document).data(s);if(o.loading===!1&&o.sourceData){this.sourceData=o.sourceData,this.doPrepend(),t.call(this);return}if(o.loading===!0){o.callbacks.push(e.proxy(function(){this.sourceData=o.sourceData,this.doPrepend(),t.call(this)},this)),o.err_callbacks.push(e.proxy(n,this));return}o.loading=!0,o.callbacks=[],o.err_callbacks=[]}e.ajax({url:r,type:"get",cache:!1,dataType:"json",success:e.proxy(function(r){o&&(o.loading=!1),this.sourceData=this.makeArray(r),e.isArray(this.sourceData)?(o&&(o.sourceData=this.sourceData,e.each(o.callbacks,function(){this.call()})),this.doPrepend(),t.call(this)):(n.call(this),o&&e.each(o.err_callbacks,function(){this.call()}))},this),error:e.proxy(function(){n.call(this),o&&(o.loading=!1,e.each(o.err_callbacks,function(){this.call()}))},this)})}else this.sourceData=this.makeArray(r),e.isArray(this.sourceData)?(this.doPrepend(),t.call(this)):n.call(this)},doPrepend:function(){if(this.options.prepend===null||this.options.prepend===undefined)return;e.isArray(this.prependData)||(e.isFunction(this.options.prepend)&&(this.options.prepend=this.options.prepend.call(this.options.scope)),this.options.prepend=e.fn.editableutils.tryParseJson(this.options.prepend,!0),typeof this.options.prepend=="string"&&(this.options.prepend={"":this.options.prepend}),this.prependData=this.makeArray(this.options.prepend)),e.isArray(this.prependData)&&e.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData))},renderList:function(){},value2htmlFinal:function(e,t){},makeArray:function(t){var n,r,i=[],s,o;if(!t||typeof t=="string")return null;if(e.isArray(t)){o=function(e,t){r={value:e,text:t};if(n++>=2)return!1};for(var u=0;u1&&(s.children&&(s.children=this.makeArray(s.children)),i.push(s))):i.push({value:s,text:s})}else e.each(t,function(e,t){i.push({value:e,text:t})});return i},option:function(e,t){this.options[e]=t,e==="source"&&(this.sourceData=null),e==="prepend"&&(this.prependData=null)}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0}),e.fn.editabletypes.list=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("text",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),e.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=e(''),this.$input.after(this.$clear).css("padding-right",24).keyup(e.proxy(function(t){if(~e.inArray(t.keyCode,[40,38,9,13,27]))return;clearTimeout(this.t);var n=this;this.t=setTimeout(function(){n.toggleClear(t)},100)},this)).parent().css("position","relative"),this.$clear.click(e.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(e){if(!this.$clear)return;var t=this.$input.val().length,n=this.$clear.is(":visible");t&&!n&&this.$clear.show(),!t&&n&&this.$clear.hide()},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),e.fn.editabletypes.text=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("textarea",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(t){t.ctrlKey&&t.which===13&&e(this).closest("form").submit()})},activate:function(){e.fn.editabletypes.text.prototype.activate.call(this)}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),e.fn.editabletypes.textarea=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("select",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.list),e.extend(t.prototype,{renderList:function(){this.$input.empty();var t=function(n,r){var i;if(e.isArray(r))for(var s=0;s",i),r[s].children))):(i.value=r[s].value,r[s].disabled&&(i.disabled=!0),n.append(e("
";if(this.o.calendarWeeks){var n='';t+=n,this.picker.find(".datepicker-days thead tr:first-child").prepend(n)}while(e'+c[this.o.language].daysMin[e++%7]+"";t+="",this.picker.find(".datepicker-days thead").append(t)},fillMonths:function(){var e="",t=0;while(t<12)e+=''+c[this.o.language].monthsShort[t++]+"";this.picker.find(".datepicker-months td").html(e)},setRange:function(t){!t||!t.length?delete this.range:this.range=e.map(t,function(e){return e.valueOf()}),this.fill()},getClassNames:function(t){var n=[],r=this.viewDate.getUTCFullYear(),i=this.viewDate.getUTCMonth(),s=this.date.valueOf(),o=new Date;return t.getUTCFullYear()r||t.getUTCFullYear()==r&&t.getUTCMonth()>i)&&n.push("new"),this.o.todayHighlight&&t.getUTCFullYear()==o.getFullYear()&&t.getUTCMonth()==o.getMonth()&&t.getUTCDate()==o.getDate()&&n.push("today"),s&&t.valueOf()==s&&n.push("active"),(t.valueOf()this.o.endDate||e.inArray(t.getUTCDay(),this.o.daysOfWeekDisabled)!==-1)&&n.push("disabled"),this.range&&(t>this.range[0]&&t");if(this.o.calendarWeeks){var y=new Date(+p+(this.o.weekStart-p.getUTCDay()-7)%7*864e5),b=new Date(+y+(11-y.getUTCDay())%7*864e5),w=new Date(+(w=t(b.getUTCFullYear(),0,1))+(11-w.getUTCDay())%7*864e5),E=(b-w)/864e5/7+1;m.push('")}}g=this.getClassNames(p),g.push("day");var S=this.o.beforeShowDay(p);S===undefined?S={}:typeof S=="boolean"?S={enabled:S}:typeof S=="string"&&(S={classes:S}),S.enabled===!1&&g.push("disabled"),S.classes&&(g=g.concat(S.classes.split(/\s+/))),S.tooltip&&(l=S.tooltip),g=e.unique(g),m.push('"),p.getUTCDay()==this.o.weekEnd&&m.push(""),p.setUTCDate(p.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(m.join(""));var x=this.date&&this.date.getUTCFullYear(),T=this.picker.find(".datepicker-months").find("th:eq(1)").text(r).end().find("span").removeClass("active");x&&x==r&&T.eq(this.date.getUTCMonth()).addClass("active"),(ru)&&T.addClass("disabled"),r==s&&T.slice(0,o).addClass("disabled"),r==u&&T.slice(a+1).addClass("disabled"),m="",r=parseInt(r/10,10)*10;var N=this.picker.find(".datepicker-years").find("th:eq(1)").text(r+"-"+(r+9)).end().find("td");r-=1;for(var C=-1;C<11;C++)m+='u?" disabled":"")+'">'+r+"",r+=1;N.html(m)},updateNavArrows:function(){if(!this._allow_update)return;var e=new Date(this.viewDate),t=e.getUTCFullYear(),n=e.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-Infinity&&t<=this.o.startDate.getUTCFullYear()&&n<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.o.endDate!==Infinity&&t>=this.o.endDate.getUTCFullYear()&&n>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-Infinity&&t<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.o.endDate!==Infinity&&t>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}},click:function(n){n.preventDefault();var r=e(n.target).closest("span, td, th");if(r.length==1)switch(r[0].nodeName.toLowerCase()){case"th":switch(r[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var i=h.modes[this.viewMode].navStep*(r[0].className=="prev"?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,i);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,i)}this.fill();break;case"today":var s=new Date;s=t(s.getFullYear(),s.getMonth(),s.getDate(),0,0,0),this.showMode(-2);var o=this.o.todayBtn=="linked"?null:"view";this._setDate(s,o);break;case"clear":var u;this.isInput?u=this.element:this.component&&(u=this.element.find("input")),u&&u.val("").change(),this._trigger("changeDate"),this.update(),this.o.autoclose&&this.hide()}break;case"span":if(!r.is(".disabled")){this.viewDate.setUTCDate(1);if(r.is(".month")){var a=1,f=r.parent().find("span").index(r),l=this.viewDate.getUTCFullYear();this.viewDate.setUTCMonth(f),this._trigger("changeMonth",this.viewDate),this.o.minViewMode===1&&this._setDate(t(l,f,a,0,0,0,0))}else{var l=parseInt(r.text(),10)||0,a=1,f=0;this.viewDate.setUTCFullYear(l),this._trigger("changeYear",this.viewDate),this.o.minViewMode===2&&this._setDate(t(l,f,a,0,0,0,0))}this.showMode(-1),this.fill()}break;case"td":if(r.is(".day")&&!r.is(".disabled")){var a=parseInt(r.text(),10)||1,l=this.viewDate.getUTCFullYear(),f=this.viewDate.getUTCMonth();r.is(".old")?f===0?(f=11,l-=1):f-=1:r.is(".new")&&(f==11?(f=0,l+=1):f+=1),this._setDate(t(l,f,a,0,0,0,0))}}},_setDate:function(e,t){if(!t||t=="date")this.date=new Date(e);if(!t||t=="view")this.viewDate=new Date(e);this.fill(),this.setValue(),this._trigger("changeDate");var n;this.isInput?n=this.element:this.component&&(n=this.element.find("input")),n&&(n.change(),this.o.autoclose&&(!t||t=="date")&&this.hide())},moveMonth:function(e,t){if(!t)return e;var n=new Date(e.valueOf()),r=n.getUTCDate(),i=n.getUTCMonth(),s=Math.abs(t),o,u;t=t>0?1:-1;if(s==1){u=t==-1?function(){return n.getUTCMonth()==i}:function(){return n.getUTCMonth()!=o},o=i+t,n.setUTCMonth(o);if(o<0||o>11)o=(o+12)%12}else{for(var a=0;a=this.o.startDate&&e<=this.o.endDate},keydown:function(e){if(this.picker.is(":not(:visible)")){e.keyCode==27&&this.show();return}var t=!1,n,r,i,s,o;switch(e.keyCode){case 27:this.hide(),e.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;n=e.keyCode==37?-1:1,e.ctrlKey?(s=this.moveYear(this.date,n),o=this.moveYear(this.viewDate,n)):e.shiftKey?(s=this.moveMonth(this.date,n),o=this.moveMonth(this.viewDate,n)):(s=new Date(this.date),s.setUTCDate(this.date.getUTCDate()+n),o=new Date(this.viewDate),o.setUTCDate(this.viewDate.getUTCDate()+n)),this.dateWithinRange(s)&&(this.date=s,this.viewDate=o,this.setValue(),this.update(),e.preventDefault(),t=!0);break;case 38:case 40:if(!this.o.keyboardNavigation)break;n=e.keyCode==38?-1:1,e.ctrlKey?(s=this.moveYear(this.date,n),o=this.moveYear(this.viewDate,n)):e.shiftKey?(s=this.moveMonth(this.date,n),o=this.moveMonth(this.viewDate,n)):(s=new Date(this.date),s.setUTCDate(this.date.getUTCDate()+n*7),o=new Date(this.viewDate),o.setUTCDate(this.viewDate.getUTCDate()+n*7)),this.dateWithinRange(s)&&(this.date=s,this.viewDate=o,this.setValue(),this.update(),e.preventDefault(),t=!0);break;case 13:this.hide(),e.preventDefault();break;case 9:this.hide()}if(t){this._trigger("changeDate");var u;this.isInput?u=this.element:this.component&&(u=this.element.find("input")),u&&u.change()}},showMode:function(e){e&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+e))),this.picker.find(">div").hide().filter(".datepicker-"+h.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()}};var i=function(t,n){this.element=e(t),this.inputs=e.map(n.inputs,function(e){return e.jquery?e[0]:e}),delete n.inputs,e(this.inputs).datepicker(n).bind("changeDate",e.proxy(this.dateUpdated,this)),this.pickers=e.map(this.inputs,function(t){return e(t).data("datepicker")}),this.updateDates()};i.prototype={updateDates:function(){this.dates=e.map(this.pickers,function(e){return e.date}),this.updateRanges()},updateRanges:function(){var t=e.map(this.dates,function(e){return e.valueOf()});e.each(this.pickers,function(e,n){n.setRange(t)})},dateUpdated:function(t){var n=e(t.target).data("datepicker"),r=n.getUTCDate(),i=e.inArray(t.target,this.inputs),s=this.inputs.length;if(i==-1)return;if(r=0&&rthis.dates[i])while(ithis.dates[i])this.pickers[i++].setUTCDate(r);this.updateDates()},remove:function(){e.map(this.pickers,function(e){e.remove()}),delete this.element.data().datepicker}};var u=e.fn.datepicker,a=e.fn.datepicker=function(t){var n=Array.apply(null,arguments);n.shift();var u,a;return this.each(function(){var a=e(this),l=a.data("datepicker"),c=typeof t=="object"&&t;if(!l){var h=s(this,"date"),p=e.extend({},f,h,c),d=o(p.language),v=e.extend({},f,d,h,c);if(a.is(".input-daterange")||v.inputs){var m={inputs:v.inputs||a.find("input").toArray()};a.data("datepicker",l=new i(this,e.extend(v,m)))}else a.data("datepicker",l=new r(this,v))}if(typeof t=="string"&&typeof l[t]=="function"){u=l[t].apply(l,n);if(u!==undefined)return!1}}),u!==undefined?u:this},f=e.fn.datepicker.defaults={autoclose:!1,beforeShowDay:e.noop,calendarWeeks:!1,clearBtn:!1,daysOfWeekDisabled:[],endDate:Infinity,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,rtl:!1,startDate:-Infinity,startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0},l=e.fn.datepicker.locale_opts=["format","rtl","weekStart"];e.fn.datepicker.Constructor=r;var c=e.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},h={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(e){return e%4===0&&e%100!==0||e%400===0},getDaysInMonth:function(e,t){return[31,h.isLeapYear(e)?29:28,31,30,31,30,31,31,30,31,30,31][t]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(e){var t=e.replace(this.validParts,"\0").split("\0"),n=e.match(this.validParts);if(!t||!t.length||!n||n.length===0)throw new Error("Invalid date format.");return{separators:t,parts:n}},parseDate:function(n,i,s){if(n instanceof Date)return n;typeof i=="string"&&(i=h.parseFormat(i));if(/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(n)){var o=/([\-+]\d+)([dmwy])/,u=n.match(/([\-+]\d+)([dmwy])/g),a,f;n=new Date;for(var l=0;l',contTemplate:'',footTemplate:''};h.template='
 
'+E+""+p.getUTCDate()+"
'+h.headTemplate+""+h.footTemplate+"
"+"
"+'
'+''+h.headTemplate+h.contTemplate+h.footTemplate+"
"+"
"+'
'+''+h.headTemplate+h.contTemplate+h.footTemplate+"
"+"
"+"
",e.fn.datepicker.DPGlobal=h,e.fn.datepicker.noConflict=function(){return e.fn.datepicker=u,this},e(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(t){var n=e(this);if(n.data("datepicker"))return;t.preventDefault(),a.call(n,"show")}),e(function(){a.call(e('[data-provide="datepicker-inline"]'))})}(window.jQuery),function(e){"use strict";e.fn.bdatepicker=e.fn.datepicker.noConflict(),e.fn.datepicker||(e.fn.datepicker=e.fn.bdatepicker);var t=function(e){this.init("date",e,t.defaults),this.initPicker(e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{initPicker:function(t,n){this.options.viewformat||(this.options.viewformat=this.options.format),t.datepicker=e.fn.editableutils.tryParseJson(t.datepicker,!0),this.options.datepicker=e.extend({},n.datepicker,t.datepicker,{format:this.options.viewformat}),this.options.datepicker.language=this.options.datepicker.language||"en",this.dpg=e.fn.bdatepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat)},render:function(){this.$input.bdatepicker(this.options.datepicker),this.options.clear&&(this.$clear=e('').html(this.options.clear).click(e.proxy(function(e){e.preventDefault(),e.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(e('
').append(this.$clear)))},value2html:function(e,n){var r=e?this.dpg.formatDate(e,this.parsedViewFormat,this.options.datepicker.language):"";t.superclass.value2html(r,n)},html2value:function(e){return this.parseDate(e,this.parsedViewFormat)},value2str:function(e){return e?this.dpg.formatDate(e,this.parsedFormat,this.options.datepicker.language):""},str2value:function(e){return this.parseDate(e,this.parsedFormat)},value2submit:function(e){return this.value2str(e)},value2input:function(e){this.$input.bdatepicker("update",e)},input2value:function(){return this.$input.data("datepicker").date},activate:function(){},clear:function(){this.$input.data("datepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".day",function(t){if(e(t.currentTarget).is(".old")||e(t.currentTarget).is(".new"))return;var n=e(this).closest("form");setTimeout(function(){n.submit()},200)})},parseDate:function(e,t){var n=null,r;return e&&(n=this.dpg.parseDate(e,t,this.options.datepicker.language),typeof e=="string"&&(r=this.dpg.formatDate(n,t,this.options.datepicker.language),e!==r&&(n=null))),n}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd",viewformat:null,datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!1},clear:"× clear"}),e.fn.editabletypes.date=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("datefield",e,t.defaults),this.initPicker(e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.date),e.extend(t.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.bdatepicker(this.options.datepicker),this.$input.off("focus keydown"),this.$input.keyup(e.proxy(function(){this.$tpl.removeData("date"),this.$tpl.bdatepicker("update")},this))},value2input:function(e){this.$input.val(e?this.dpg.formatDate(e,this.parsedViewFormat,this.options.datepicker.language):""),this.$tpl.bdatepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){e.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),t.defaults=e.extend({},e.fn.editabletypes.date.defaults,{tpl:'
',inputclass:"input-small",datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!0}}),e.fn.editabletypes.datefield=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("datetime",e,t.defaults),this.initPicker(e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{initPicker:function(t,n){this.options.viewformat||(this.options.viewformat=this.options.format),t.datetimepicker=e.fn.editableutils.tryParseJson(t.datetimepicker,!0),this.options.datetimepicker=e.extend({},n.datetimepicker,t.datetimepicker,{format:this.options.viewformat}),this.options.datetimepicker.language=this.options.datetimepicker.language||"en",this.dpg=e.fn.datetimepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format,this.options.formatType),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat,this.options.formatType)},render:function(){this.$input.datetimepicker(this.options.datetimepicker),this.$input.on("changeMode",function(t){var n=e(this).closest("form").parent();setTimeout(function(){n.triggerHandler("resize")},0)}),this.options.clear&&(this.$clear=e('').html(this.options.clear).click(e.proxy(function(e){e.preventDefault(),e.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(e('
').append(this.$clear)))},value2html:function(e,n){var r=e?this.dpg.formatDate(this.toUTC(e),this.parsedViewFormat,this.options.datetimepicker.language,this.options.formatType):"";if(!n)return r;t.superclass.value2html(r,n)},html2value:function(e){var t=this.parseDate(e,this.parsedViewFormat);return t?this.fromUTC(t):null},value2str:function(e){return e?this.dpg.formatDate(this.toUTC(e),this.parsedFormat,this.options.datetimepicker.language,this.options.formatType):""},str2value:function(e){var t=this.parseDate(e,this.parsedFormat);return t?this.fromUTC(t):null},value2submit:function(e){return this.value2str(e)},value2input:function(e){e&&this.$input.data("datetimepicker").setDate(e)},input2value:function(){var e=this.$input.data("datetimepicker");return e.date?e.getDate():null},activate:function(){},clear:function(){this.$input.data("datetimepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".minute",function(t){var n=e(this).closest("form");setTimeout(function(){n.submit()},200)})},toUTC:function(e){return e?new Date(e.valueOf()-e.getTimezoneOffset()*6e4):e},fromUTC:function(e){return e?new Date(e.valueOf()+e.getTimezoneOffset()*6e4):e},parseDate:function(e,t){var n=null,r;return e&&(n=this.dpg.parseDate(e,t,this.options.datetimepicker.language,this.options.formatType),typeof e=="string"&&(r=this.dpg.formatDate(n,t,this.options.datetimepicker.language,this.options.formatType),e!==r&&(n=null))),n}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd hh:ii",formatType:"standard",viewformat:null,datetimepicker:{todayHighlight:!1,autoclose:!1},clear:"× clear"}),e.fn.editabletypes.datetime=t}(window.jQuery),function(e){"use strict";var t=function(e){this.init("datetimefield",e,t.defaults),this.initPicker(e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.datetime),e.extend(t.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.datetimepicker(this.options.datetimepicker),this.$input.off("focus keydown"),this.$input.keyup(e.proxy(function(){this.$tpl.removeData("date"),this.$tpl.datetimepicker("update")},this))},value2input:function(e){this.$input.val(this.value2html(e)),this.$tpl.datetimepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){e.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),t.defaults=e.extend({},e.fn.editabletypes.datetime.defaults,{tpl:'
',inputclass:"input-medium",datetimepicker:{todayHighlight:!1,autoclose:!0}}),e.fn.editabletypes.datetimefield=t}(window.jQuery),function(e){"use strict";var t=function(n){this.init("typeahead",n,t.defaults),this.options.typeahead=e.extend({},t.defaults.typeahead,{matcher:this.matcher,sorter:this.sorter,highlighter:this.highlighter,updater:this.updater},n.typeahead)};e.fn.editableutils.inherit(t,e.fn.editabletypes.list),e.extend(t.prototype,{renderList:function(){this.$input=this.$tpl.is("input")?this.$tpl:this.$tpl.find('input[type="text"]'),this.options.typeahead.source=this.sourceData,this.$input.typeahead(this.options.typeahead);var t=this.$input.data("typeahead");t.render=e.proxy(this.typeaheadRender,t),t.select=e.proxy(this.typeaheadSelect,t),t.move=e.proxy(this.typeaheadMove,t),this.renderClear(),this.setClass(),this.setAttr("placeholder")},value2htmlFinal:function(t,n){if(this.getIsObjects()){var r=e.fn.editableutils.itemsByValue(t,this.sourceData);e(n).text(r.length?r[0].text:"")}else e(n).text(t)},html2value:function(e){return e?e:null},value2input:function(t){if(this.getIsObjects()){var n=e.fn.editableutils.itemsByValue(t,this.sourceData);this.$input.data("value",t).val(n.length?n[0].text:"")}else this.$input.val(t)},input2value:function(){if(this.getIsObjects()){var t=this.$input.data("value"),n=e.fn.editableutils.itemsByValue(t,this.sourceData);return n.length&&n[0].text.toLowerCase()===this.$input.val().toLowerCase()?t:null}return this.$input.val()},getIsObjects:function(){if(this.isObjects===undefined){this.isObjects=!1;for(var e=0;e',typeahead:null,clear:!0}),e.fn.editabletypes.typeahead=t}(window.jQuery); \ No newline at end of file +!function(a){"use strict";var b=function(b,c){this.options=a.extend({},a.fn.editableform.defaults,c),this.$div=a(b),this.options.scope||(this.options.scope=this)};b.prototype={constructor:b,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value),this.input.prerender()},initTemplate:function(){this.$form=a(a.fn.editableform.template)},initButtons:function(){var b=this.$form.find(".editable-buttons");b.append(a.fn.editableform.buttons),"bottom"===this.options.showbuttons&&b.addClass("editable-buttons-bottom")},render:function(){this.$loading=a(a.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.isSaving=!1,this.$div.triggerHandler("rendering"),this.initInput(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),a.when(this.input.render()).then(a.proxy(function(){if(this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(a.proxy(this.cancel,this)),this.input.error)this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(a){a.preventDefault()});else{this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled");var b=null===this.value||void 0===this.value||""===this.value?this.options.defaultValue:this.value;this.input.value2input(b),this.$form.submit(a.proxy(this.submit,this))}this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var a,b;this.$form?(a=this.$form.outerWidth(),b=this.$form.outerHeight(),a&&this.$loading.width(a),b&&this.$loading.height(b),this.$form.hide()):(a=this.$loading.parent().width(),a&&this.$loading.width(a)),this.$loading.show()},showForm:function(a){this.$loading.hide(),this.$form.show(),a!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(b){var c,d=this.$form.find(".control-group"),e=this.$form.find(".editable-error-block");if(b===!1)d.removeClass(a.fn.editableform.errorGroupClass),e.removeClass(a.fn.editableform.errorBlockClass).empty().hide();else{if(b){c=b.split("\n");for(var f=0;f").text(c[f]).html();b=c.join("
")}d.addClass(a.fn.editableform.errorGroupClass),e.addClass(a.fn.editableform.errorBlockClass).html(b).show()}},submit:function(b){b.stopPropagation(),b.preventDefault();var c,d=this.input.input2value();if(c=this.validate(d))return this.error(c),this.showForm(),void 0;if(!this.options.savenochange&&this.input.value2str(d)==this.input.value2str(this.value))return this.$div.triggerHandler("nochange"),void 0;var e=this.input.value2submit(d);this.isSaving=!0,a.when(this.save(e)).done(a.proxy(function(a){this.isSaving=!1;var b="function"==typeof this.options.success?this.options.success.call(this.options.scope,a,d):null;return b===!1?(this.error(!1),this.showForm(!1),void 0):"string"==typeof b?(this.error(b),this.showForm(),void 0):(b&&"object"==typeof b&&b.hasOwnProperty("newValue")&&(d=b.newValue),this.error(!1),this.value=d,this.$div.triggerHandler("save",{newValue:d,submitValue:e,response:a}),void 0)},this)).fail(a.proxy(function(a){this.isSaving=!1;var b;b="function"==typeof this.options.error?this.options.error.call(this.options.scope,a,d):"string"==typeof a?a:a.responseText||a.statusText||"Unknown error!",this.error(b),this.showForm()},this))},save:function(b){this.options.pk=a.fn.editableutils.tryParseJson(this.options.pk,!0);var c,d="function"==typeof this.options.pk?this.options.pk.call(this.options.scope):this.options.pk,e=!!("function"==typeof this.options.url||this.options.url&&("always"===this.options.send||"auto"===this.options.send&&null!==d&&void 0!==d));return e?(this.showLoading(),c={name:this.options.name||"",value:b,pk:d},"function"==typeof this.options.params?c=this.options.params.call(this.options.scope,c):(this.options.params=a.fn.editableutils.tryParseJson(this.options.params,!0),a.extend(c,this.options.params)),"function"==typeof this.options.url?this.options.url.call(this.options.scope,c):a.ajax(a.extend({url:this.options.url,data:c,type:"POST"},this.options.ajaxOptions))):void 0},validate:function(a){return void 0===a&&(a=this.value),"function"==typeof this.options.validate?this.options.validate.call(this.options.scope,a):void 0},option:function(a,b){a in this.options&&(this.options[a]=b),"value"===a&&this.setValue(b)},setValue:function(a,b){this.value=b?this.input.str2value(a):a,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},a.fn.editableform=function(c){var d=arguments;return this.each(function(){var e=a(this),f=e.data("editableform"),g="object"==typeof c&&c;f||e.data("editableform",f=new b(this,g)),"string"==typeof c&&f[c].apply(f,Array.prototype.slice.call(d,1))})},a.fn.editableform.Constructor=b,a.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,defaultValue:null,send:"auto",validate:null,success:null,error:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},a.fn.editableform.template='
',a.fn.editableform.loading='
',a.fn.editableform.buttons='',a.fn.editableform.errorGroupClass=null,a.fn.editableform.errorBlockClass="editable-error",a.fn.editableform.engine="jqeury"}(window.jQuery),function(a){"use strict";a.fn.editableutils={inherit:function(a,b){var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a,a.superclass=b.prototype},setCursorPosition:function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var c=a.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",b),c.select()}},tryParseJson:function(a,b){if("string"==typeof a&&a.length&&a.match(/^[\{\[].*[\}\]]$/))if(b)try{a=new Function("return "+a)()}catch(c){}finally{return a}else a=new Function("return "+a)();return a},sliceObj:function(b,c,d){var e,f,g={};if(!a.isArray(c)||!c.length)return g;for(var h=0;h").text(b).html()},itemsByValue:function(b,c,d){if(!c||null===b)return[];if("function"!=typeof d){var e=d||"value";d=function(a){return a[e]}}var f=a.isArray(b),g=[],h=this;return a.each(c,function(c,e){if(e.children)g=g.concat(h.itemsByValue(b,e.children,d));else if(f)a.grep(b,function(a){return a==(e&&"object"==typeof e?d(e):e)}).length&&g.push(e);else{var i=e&&"object"==typeof e?d(e):e;b==i&&g.push(e)}}),g},createInput:function(b){var c,d,e,f=b.type;return"date"===f&&("inline"===b.mode?a.fn.editabletypes.datefield?f="datefield":a.fn.editabletypes.dateuifield&&(f="dateuifield"):a.fn.editabletypes.date?f="date":a.fn.editabletypes.dateui&&(f="dateui"),"date"!==f||a.fn.editabletypes.date||(f="combodate")),"datetime"===f&&"inline"===b.mode&&(f="datetimefield"),"wysihtml5"!==f||a.fn.editabletypes[f]||(f="textarea"),"function"==typeof a.fn.editabletypes[f]?(c=a.fn.editabletypes[f],d=this.sliceObj(b,this.objectKeys(c.defaults)),e=new c(d)):(a.error("Unknown type: "+f),!1)},supportsTransitions:function(){var a=document.body||document.documentElement,b=a.style,c="transition",d=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof b[c])return!0;c=c.charAt(0).toUpperCase()+c.substr(1);for(var e=0;e"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(a){if(this.tip()&&this.tip().is(":visible")&&this.$element.hasClass("editable-open")){if(this.$form.data("editableform").isSaving)return this.delayedHide={reason:a},void 0;this.delayedHide=!1,this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",a||"manual")}},innerShow:function(){},innerHide:function(){},toggle:function(a){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(a)},setPosition:function(){},save:function(a,b){this.$element.triggerHandler("save",b),this.hide("save")},option:function(a,b){this.options[a]=b,a in this.containerOptions?(this.containerOptions[a]=b,this.setContainerOption(a,b)):(this.formOptions[a]=b,this.$form&&this.$form.editableform("option",a,b))},setContainerOption:function(a,b){this.call("option",a,b)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(b){a(".editable-open").each(function(c,d){if(d!==b&&!a(d).find(b).length){var e=a(d),f=e.data("editableContainer");f&&("cancel"===f.options.onblur?e.data("editableContainer").hide("onblur"):"submit"===f.options.onblur&&e.data("editableContainer").tip().find("form").submit())}})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},a.fn.editableContainer=function(d){var e=arguments;return this.each(function(){var f=a(this),g="editableContainer",h=f.data(g),i="object"==typeof d&&d,j="inline"===i.mode?c:b;h||f.data(g,h=new j(this,i)),"string"==typeof d&&h[d].apply(h,Array.prototype.slice.call(e,1))})},a.fn.editableContainer.Popup=b,a.fn.editableContainer.Inline=c,a.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:!1,mode:"popup"},jQuery.event.special.destroyed={remove:function(a){a.handler&&a.handler()}}}(window.jQuery),function(a){"use strict";a.extend(a.fn.editableContainer.Inline.prototype,a.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=a(""),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,a.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.editable.defaults,c,a.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init(),this.options.highlight&&!a.fn.editableutils.supportsTransitions()&&(this.options.highlight=!1)};b.prototype={constructor:b,init:function(){var b,c=!1;if(this.options.name=this.options.name||this.$element.attr("id"),this.options.scope=this.$element[0],this.input=a.fn.editableutils.createInput(this.options),this.input){switch(void 0===this.options.value||null===this.options.value?(this.value=this.input.html2value(a.trim(this.$element.html())),c=!0):(this.options.value=a.fn.editableutils.tryParseJson(this.options.value,!0),this.value="string"==typeof this.options.value?this.input.str2value(this.options.value):this.options.value),this.$element.addClass("editable"),"textarea"===this.input.type&&this.$element.addClass("editable-pre-wrapped"),"manual"!==this.options.toggle?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",a.proxy(function(a){if(this.options.disabled||a.preventDefault(),"mouseenter"===this.options.toggle)this.show();else{var b="click"!==this.options.toggle;this.toggle(b)}},this))):this.$element.attr("tabindex",-1),"function"==typeof this.options.display&&(this.options.autotext="always"),this.options.autotext){case"always":b=!0;break;case"auto":b=!a.trim(this.$element.text()).length&&null!==this.value&&void 0!==this.value&&!c;break;default:b=!1}a.when(b?this.render():!0).then(a.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))}},initLive:function(){var b=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",b,a.proxy(function(b){var c=a(b.target);c.data("editable")||(c.hasClass(this.options.emptyclass)&&c.empty(),c.editable(this.options).trigger(b))},this))},render:function(a){return this.options.display!==!1?this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,a):"function"==typeof this.options.display?this.options.display.call(this.$element[0],this.value,a):this.input.value2html(this.value,this.$element[0]):void 0},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),"manual"!==this.options.toggle&&"-1"===this.$element.attr("tabindex")&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(b,c){return b&&"object"==typeof b?(a.each(b,a.proxy(function(b,c){this.option(a.trim(b),c)},this)),void 0):(this.options[b]=c,"disabled"===b?c?this.disable():this.enable():("value"===b&&this.setValue(c),this.container&&this.container.option(b,c),this.input.option&&this.input.option(b,c),void 0))},handleEmpty:function(b){this.options.display!==!1&&(this.isEmpty=void 0!==b?b:""===a.trim(this.$element.html())?!0:""!==a.trim(this.$element.text())?!1:!this.$element.height()||!this.$element.width(),this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.html(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass))},show:function(b){if(!this.options.disabled){if(this.container){if(this.container.tip().is(":visible"))return}else{var c=a.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(c),this.$element.on("save.internal",a.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}this.container.show(b)}},hide:function(){this.container&&this.container.hide()},toggle:function(a){this.container&&this.container.tip().is(":visible")?this.hide():this.show(a)},save:function(a,b){if(this.options.unsavedclass){var c=!1;c=c||"function"==typeof this.options.url,c=c||this.options.display===!1,c=c||void 0!==b.response,c=c||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(b.newValue),c?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}if(this.options.highlight){var d=this.$element,e=d.css("background-color");d.css("background-color",this.options.highlight),setTimeout(function(){"transparent"===e&&(e=""),d.css("background-color",e),d.addClass("editable-bg-transition"),setTimeout(function(){d.removeClass("editable-bg-transition")},1700)},10)}this.setValue(b.newValue,!1,b.response)},validate:function(){return"function"==typeof this.options.validate?this.options.validate.call(this,this.value):void 0},setValue:function(b,c,d){this.value=c?this.input.str2value(b):b,this.container&&this.container.option("value",this.value),a.when(this.render(d)).then(a.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.disable(),this.container&&this.container.destroy(),this.input.destroy(),"manual"!==this.options.toggle&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable editable-open editable-disabled"),this.$element.removeData("editable")}},a.fn.editable=function(c){var d={},e=arguments,f="editable";switch(c){case"validate":return this.each(function(){var b,c=a(this),e=c.data(f);e&&(b=e.validate())&&(d[e.options.name]=b)}),d;case"getValue":return 2===arguments.length&&arguments[1]===!0?d=this.eq(0).data(f).value:this.each(function(){var b=a(this),c=b.data(f);c&&void 0!==c.value&&null!==c.value&&(d[c.options.name]=c.input.value2submit(c.value))}),d;case"submit":var g,h=arguments[1]||{},i=this,j=this.editable("validate");return a.isEmptyObject(j)?(g=this.editable("getValue"),h.data&&a.extend(g,h.data),a.ajax(a.extend({url:h.url,data:g,type:"POST"},h.ajaxOptions)).success(function(a){"function"==typeof h.success&&h.success.call(i,a,h)}).error(function(){"function"==typeof h.error&&h.error.apply(i,arguments)})):"function"==typeof h.error&&h.error.call(i,j),this}return this.each(function(){var d=a(this),g=d.data(f),h="object"==typeof c&&c;return h&&h.selector?(g=new b(this,h),void 0):(g||d.data(f,g=new b(this,h)),"string"==typeof c&&g[c].apply(g,Array.prototype.slice.call(e,1)),void 0)})},a.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null,highlight:"#FFFF80"}}(window.jQuery),function(a){"use strict";a.fn.editabletypes={};var b=function(){};b.prototype={init:function(b,c,d){this.type=b,this.options=a.extend({},d,c)},prerender:function(){this.$tpl=a(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(b,c){a(c).text(a.trim(b))},html2value:function(b){return a("
").html(b).text()},value2str:function(a){return a},str2value:function(a){return a},value2submit:function(a){return a},value2input:function(a){this.$input.val(a)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(b){return a("
").text(b).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(a){void 0!==this.options[a]&&null!==this.options[a]&&this.$input.attr(a,this.options[a])},option:function(a,b){this.options[a]=b}},b.defaults={tpl:"",inputclass:null,scope:null,showbuttons:!0},a.extend(a.fn.editabletypes,{abstractinput:b})}(window.jQuery),function(a){"use strict";var b=function(){};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){var b=a.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),b.resolve()},function(){this.error=this.options.sourceError,b.resolve()}),b.promise()},html2value:function(){return null},value2html:function(b,c,d,e){var f=a.Deferred(),g=function(){"function"==typeof d?d.call(c,b,this.sourceData,e):this.value2htmlFinal(b,c),f.resolve()};return null===b?g.call(this):this.onSourceReady(g,function(){f.resolve()}),f.promise()},onSourceReady:function(b,c){var d;if(a.isFunction(this.options.source)?(d=this.options.source.call(this.options.scope),this.sourceData=null):d=this.options.source,this.options.sourceCache&&a.isArray(this.sourceData))return b.call(this),void 0;try{d=a.fn.editableutils.tryParseJson(d,!1)}catch(e){return c.call(this),void 0}if("string"==typeof d){if(this.options.sourceCache){var f,g=d;if(a(document).data(g)||a(document).data(g,{}),f=a(document).data(g),f.loading===!1&&f.sourceData)return this.sourceData=f.sourceData,this.doPrepend(),b.call(this),void 0;if(f.loading===!0)return f.callbacks.push(a.proxy(function(){this.sourceData=f.sourceData,this.doPrepend(),b.call(this)},this)),f.err_callbacks.push(a.proxy(c,this)),void 0;f.loading=!0,f.callbacks=[],f.err_callbacks=[]}a.ajax({url:d,type:"get",cache:!1,dataType:"json",success:a.proxy(function(d){f&&(f.loading=!1),this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(f&&(f.sourceData=this.sourceData,a.each(f.callbacks,function(){this.call()})),this.doPrepend(),b.call(this)):(c.call(this),f&&a.each(f.err_callbacks,function(){this.call()}))},this),error:a.proxy(function(){c.call(this),f&&(f.loading=!1,a.each(f.err_callbacks,function(){this.call()}))},this)})}else this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(this.doPrepend(),b.call(this)):c.call(this)},doPrepend:function(){null!==this.options.prepend&&void 0!==this.options.prepend&&(a.isArray(this.prependData)||(a.isFunction(this.options.prepend)&&(this.options.prepend=this.options.prepend.call(this.options.scope)),this.options.prepend=a.fn.editableutils.tryParseJson(this.options.prepend,!0),"string"==typeof this.options.prepend&&(this.options.prepend={"":this.options.prepend}),this.prependData=this.makeArray(this.options.prepend)),a.isArray(this.prependData)&&a.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData)))},renderList:function(){},value2htmlFinal:function(){},makeArray:function(b){var c,d,e,f,g=[];if(!b||"string"==typeof b)return null;if(a.isArray(b)){f=function(a,b){return d={value:a,text:b},c++>=2?!1:void 0};for(var h=0;h1&&(e.children&&(e.children=this.makeArray(e.children)),g.push(e))):g.push({value:e,text:e})}else a.each(b,function(a,b){g.push({value:a,text:b})});return g},option:function(a,b){this.options[a]=b,"source"===a&&(this.sourceData=null),"prepend"===a&&(this.prependData=null)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0}),a.fn.editabletypes.list=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("text",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),a.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=a(''),this.$input.after(this.$clear).css("padding-right",24).keyup(a.proxy(function(b){if(!~a.inArray(b.keyCode,[40,38,9,13,27])){clearTimeout(this.t);var c=this;this.t=setTimeout(function(){c.toggleClear(b)},100)}},this)).parent().css("position","relative"),this.$clear.click(a.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(){if(this.$clear){var a=this.$input.val().length,b=this.$clear.is(":visible");a&&!b&&this.$clear.show(),!a&&b&&this.$clear.hide()}},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),a.fn.editabletypes.text=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("textarea",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(b){b.ctrlKey&&13===b.which&&a(this).closest("form").submit()})},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),a.fn.editabletypes.textarea=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("select",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.list),a.extend(b.prototype,{renderList:function(){this.$input.empty();var b=function(c,d){var e;if(a.isArray(d))for(var f=0;f",e),d[f].children))):(e.value=d[f].value,d[f].disabled&&(e.disabled=!0),c.append(a("
 
'+u+""+m.getUTCDate()+"
'+l.headTemplate+""+l.footTemplate+"
"+"
"+'
'+''+l.headTemplate+l.contTemplate+l.footTemplate+"
"+"
"+'
'+''+l.headTemplate+l.contTemplate+l.footTemplate+"
"+"
"+"
",a.fn.datepicker.DPGlobal=l,a.fn.datepicker.noConflict=function(){return a.fn.datepicker=g,this},a(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(b){var c=a(this);c.data("datepicker")||(b.preventDefault(),h.call(c,"show"))}),a(function(){h.call(a('[data-provide="datepicker-inline"]'))})}(window.jQuery),function(a){"use strict";a.fn.bdatepicker=a.fn.datepicker.noConflict(),a.fn.datepicker||(a.fn.datepicker=a.fn.bdatepicker);var b=function(a){this.init("date",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datepicker=a.fn.editableutils.tryParseJson(b.datepicker,!0),this.options.datepicker=a.extend({},c.datepicker,b.datepicker,{format:this.options.viewformat}),this.options.datepicker.language=this.options.datepicker.language||"en",this.dpg=a.fn.bdatepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat)},render:function(){this.$input.bdatepicker(this.options.datepicker),this.options.clear&&(this.$clear=a('').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('
').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):"";b.superclass.value2html(d,c)},html2value:function(a){return this.parseDate(a,this.parsedViewFormat)},value2str:function(a){return a?this.dpg.formatDate(a,this.parsedFormat,this.options.datepicker.language):""},str2value:function(a){return this.parseDate(a,this.parsedFormat)},value2submit:function(a){return this.value2str(a)},value2input:function(a){this.$input.bdatepicker("update",a)},input2value:function(){return this.$input.data("datepicker").date},activate:function(){},clear:function(){this.$input.data("datepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".day",function(b){if(!a(b.currentTarget).is(".old")&&!a(b.currentTarget).is(".new")){var c=a(this).closest("form");setTimeout(function(){c.submit()},200)}})},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datepicker.language),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datepicker.language),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd",viewformat:null,datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!1},clear:"× clear"}),a.fn.editabletypes.date=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.date),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.bdatepicker(this.options.datepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.bdatepicker("update")},this))},value2input:function(a){this.$input.val(a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):""),this.$tpl.bdatepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.date.defaults,{tpl:'
',inputclass:"input-small",datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!0}}),a.fn.editabletypes.datefield=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetime",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datetimepicker=a.fn.editableutils.tryParseJson(b.datetimepicker,!0),this.options.datetimepicker=a.extend({},c.datetimepicker,b.datetimepicker,{format:this.options.viewformat}),this.options.datetimepicker.language=this.options.datetimepicker.language||"en",this.dpg=a.fn.datetimepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format,this.options.formatType),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat,this.options.formatType)},render:function(){this.$input.datetimepicker(this.options.datetimepicker),this.$input.on("changeMode",function(){var b=a(this).closest("form").parent();setTimeout(function(){b.triggerHandler("resize")},0)}),this.options.clear&&(this.$clear=a('').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('
').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(this.toUTC(a),this.parsedViewFormat,this.options.datetimepicker.language,this.options.formatType):"";return c?(b.superclass.value2html(d,c),void 0):d},html2value:function(a){var b=this.parseDate(a,this.parsedViewFormat);return b?this.fromUTC(b):null},value2str:function(a){return a?this.dpg.formatDate(this.toUTC(a),this.parsedFormat,this.options.datetimepicker.language,this.options.formatType):""},str2value:function(a){var b=this.parseDate(a,this.parsedFormat);return b?this.fromUTC(b):null},value2submit:function(a){return this.value2str(a)},value2input:function(a){a&&this.$input.data("datetimepicker").setDate(a)},input2value:function(){var a=this.$input.data("datetimepicker");return a.date?a.getDate():null},activate:function(){},clear:function(){this.$input.data("datetimepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".minute",function(){var b=a(this).closest("form");setTimeout(function(){b.submit()},200)})},toUTC:function(a){return a?new Date(a.valueOf()-6e4*a.getTimezoneOffset()):a},fromUTC:function(a){return a?new Date(a.valueOf()+6e4*a.getTimezoneOffset()):a},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datetimepicker.language,this.options.formatType),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datetimepicker.language,this.options.formatType),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd hh:ii",formatType:"standard",viewformat:null,datetimepicker:{todayHighlight:!1,autoclose:!1},clear:"× clear"}),a.fn.editabletypes.datetime=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetimefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.datetime),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.datetimepicker(this.options.datetimepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.datetimepicker("update")},this))},value2input:function(a){this.$input.val(this.value2html(a)),this.$tpl.datetimepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.datetime.defaults,{tpl:'
',inputclass:"input-medium",datetimepicker:{todayHighlight:!1,autoclose:!0}}),a.fn.editabletypes.datetimefield=b}(window.jQuery); \ No newline at end of file diff --git a/templates/admin/default/currencies.html b/templates/admin/default/currencies.html index d446de776..4876e2a08 100644 --- a/templates/admin/default/currencies.html +++ b/templates/admin/default/currencies.html @@ -189,149 +189,157 @@ {* Adding a new currency *} -
 '+dates[this.o.language].daysMin[(dowCnt++)%7]+'
'+ calWeek +''+prevMonth.getUTCDate() + '
'+ - DPGlobal.headTemplate+ - ''+ - DPGlobal.footTemplate+ - '
'+ - '
'+ - '
'+ - ''+ - DPGlobal.headTemplate+ - DPGlobal.contTemplate+ - DPGlobal.footTemplate+ - '
'+ - '
'+ - '
'+ - ''+ - DPGlobal.headTemplate+ - DPGlobal.contTemplate+ - DPGlobal.footTemplate+ - '
'+ - '
'+ - '
'; - - $.fn.datepicker.DPGlobal = DPGlobal; - - - /* DATEPICKER NO CONFLICT - * =================== */ - - $.fn.datepicker.noConflict = function(){ - $.fn.datepicker = old; - return this; - }; - - - /* DATEPICKER DATA-API - * ================== */ - - $(document).on( - 'focus.datepicker.data-api click.datepicker.data-api', - '[data-provide="datepicker"]', - function(e){ - var $this = $(this); - if ($this.data('datepicker')) return; - e.preventDefault(); - // component click requires us to explicitly show it - datepicker.call($this, 'show'); - } - ); - $(function(){ - //$('[data-provide="datepicker-inline"]').datepicker(); - //vit: changed to support noConflict() - datepicker.call($('[data-provide="datepicker-inline"]')); - }); - -}( window.jQuery )); - -/** -Bootstrap-datepicker. -Description and examples: https://github.com/eternicode/bootstrap-datepicker. -For **i18n** you should include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales -and set `language` option. -Since 1.4.0 date has different appearance in **popup** and **inline** modes. - -@class date -@extends abstractinput -@final -@example -15/05/1984 - -**/ -(function ($) { - "use strict"; - - //store bootstrap-datepicker as bdateicker to exclude conflict with jQuery UI one - $.fn.bdatepicker = $.fn.datepicker.noConflict(); - if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name - $.fn.datepicker = $.fn.bdatepicker; - } - - var Date = function (options) { - this.init('date', options, Date.defaults); - this.initPicker(options, Date.defaults); - }; - - $.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput); - - $.extend(Date.prototype, { - initPicker: function(options, defaults) { - //'format' is set directly from settings or data-* attributes - - //by default viewformat equals to format - if(!this.options.viewformat) { - this.options.viewformat = this.options.format; - } - - //try parse datepicker config defined as json string in data-datepicker - options.datepicker = $.fn.editableutils.tryParseJson(options.datepicker, true); - - //overriding datepicker config (as by default jQuery extend() is not recursive) - //since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only - this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, { - format: this.options.viewformat - }); - - //language - this.options.datepicker.language = this.options.datepicker.language || 'en'; - - //store DPglobal - this.dpg = $.fn.bdatepicker.DPGlobal; - - //store parsed formats - this.parsedFormat = this.dpg.parseFormat(this.options.format); - this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat); - }, - - render: function () { - this.$input.bdatepicker(this.options.datepicker); - - //"clear" link - if(this.options.clear) { - this.$clear = $('').html(this.options.clear).click($.proxy(function(e){ - e.preventDefault(); - e.stopPropagation(); - this.clear(); - }, this)); - - this.$tpl.parent().append($('
').append(this.$clear)); - } - }, - - value2html: function(value, element) { - var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : ''; - Date.superclass.value2html(text, element); - }, - - html2value: function(html) { - return this.parseDate(html, this.parsedViewFormat); - }, - - value2str: function(value) { - return value ? this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language) : ''; - }, - - str2value: function(str) { - return this.parseDate(str, this.parsedFormat); - }, - - value2submit: function(value) { - return this.value2str(value); - }, - - value2input: function(value) { - this.$input.bdatepicker('update', value); - }, - - input2value: function() { - return this.$input.data('datepicker').date; - }, - - activate: function() { - }, - - clear: function() { - this.$input.data('datepicker').date = null; - this.$input.find('.active').removeClass('active'); - if(!this.options.showbuttons) { - this.$input.closest('form').submit(); - } - }, - - autosubmit: function() { - this.$input.on('mouseup', '.day', function(e){ - if($(e.currentTarget).is('.old') || $(e.currentTarget).is('.new')) { - return; - } - var $form = $(this).closest('form'); - setTimeout(function() { - $form.submit(); - }, 200); - }); - //changedate is not suitable as it triggered when showing datepicker. see #149 - /* - this.$input.on('changeDate', function(e){ - var $form = $(this).closest('form'); - setTimeout(function() { - $form.submit(); - }, 200); - }); - */ - }, - - /* - For incorrect date bootstrap-datepicker returns current date that is not suitable - for datefield. - This function returns null for incorrect date. - */ - parseDate: function(str, format) { - var date = null, formattedBack; - if(str) { - date = this.dpg.parseDate(str, format, this.options.datepicker.language); - if(typeof str === 'string') { - formattedBack = this.dpg.formatDate(date, format, this.options.datepicker.language); - if(str !== formattedBack) { - date = null; - } - } - } - return date; - } - - }); - - Date.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { - /** - @property tpl - @default
- **/ - tpl:'
', - /** - @property inputclass - @default null - **/ - inputclass: null, - /** - Format used for sending value to server. Also applied when converting date from data-value attribute.
- Possible tokens are: d, dd, m, mm, yy, yyyy - - @property format - @type string - @default yyyy-mm-dd - **/ - format:'yyyy-mm-dd', - /** - Format used for displaying date. Also applied when converting date from element's text on init. - If not specified equals to format - - @property viewformat - @type string - @default null - **/ - viewformat: null, - /** - Configuration of datepicker. - Full list of options: http://vitalets.github.com/bootstrap-datepicker - - @property datepicker - @type object - @default { - weekStart: 0, - startView: 0, - minViewMode: 0, - autoclose: false - } - **/ - datepicker:{ - weekStart: 0, - startView: 0, - minViewMode: 0, - autoclose: false - }, - /** - Text shown as clear date button. - If false clear button will not be rendered. - - @property clear - @type boolean|string - @default 'x clear' - **/ - clear: '× clear' - }); - - $.fn.editabletypes.date = Date; - -}(window.jQuery)); - -/** -Bootstrap datefield input - modification for inline mode. -Shows normal and binds popup datepicker. -Automatically shown in inline mode. - -@class datefield -@extends date - -@since 1.4.0 -**/ -(function ($) { - "use strict"; - - var DateField = function (options) { - this.init('datefield', options, DateField.defaults); - this.initPicker(options, DateField.defaults); - }; - - $.fn.editableutils.inherit(DateField, $.fn.editabletypes.date); - - $.extend(DateField.prototype, { - render: function () { - this.$input = this.$tpl.find('input'); - this.setClass(); - this.setAttr('placeholder'); - - //bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js) - this.$tpl.bdatepicker(this.options.datepicker); - - //need to disable original event handlers - this.$input.off('focus keydown'); - - //update value of datepicker - this.$input.keyup($.proxy(function(){ - this.$tpl.removeData('date'); - this.$tpl.bdatepicker('update'); - }, this)); - - }, - - value2input: function(value) { - this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : ''); - this.$tpl.bdatepicker('update'); - }, - - input2value: function() { - return this.html2value(this.$input.val()); - }, - - activate: function() { - $.fn.editabletypes.text.prototype.activate.call(this); - }, - - autosubmit: function() { - //reset autosubmit to empty - } - }); - - DateField.defaults = $.extend({}, $.fn.editabletypes.date.defaults, { - /** - @property tpl - **/ - tpl:'
', - /** - @property inputclass - @default 'input-small' - **/ - inputclass: 'input-small', - - /* datepicker config */ - datepicker: { - weekStart: 0, - startView: 0, - minViewMode: 0, - autoclose: true - } - }); - - $.fn.editabletypes.datefield = DateField; - -}(window.jQuery)); -/** -Bootstrap-datetimepicker. -Based on [smalot bootstrap-datetimepicker plugin](https://github.com/smalot/bootstrap-datetimepicker). -Before usage you should manually include dependent js and css: - - - - -For **i18n** you should include js file from here: https://github.com/smalot/bootstrap-datetimepicker/tree/master/js/locales -and set `language` option. - -@class datetime -@extends abstractinput -@final -@since 1.4.4 -@example -15/03/2013 12:45 - -**/ -(function ($) { - "use strict"; - - var DateTime = function (options) { - this.init('datetime', options, DateTime.defaults); - this.initPicker(options, DateTime.defaults); - }; - - $.fn.editableutils.inherit(DateTime, $.fn.editabletypes.abstractinput); - - $.extend(DateTime.prototype, { - initPicker: function(options, defaults) { - //'format' is set directly from settings or data-* attributes - - //by default viewformat equals to format - if(!this.options.viewformat) { - this.options.viewformat = this.options.format; - } - - //try parse datetimepicker config defined as json string in data-datetimepicker - options.datetimepicker = $.fn.editableutils.tryParseJson(options.datetimepicker, true); - - //overriding datetimepicker config (as by default jQuery extend() is not recursive) - //since 1.4 datetimepicker internally uses viewformat instead of format. Format is for submit only - this.options.datetimepicker = $.extend({}, defaults.datetimepicker, options.datetimepicker, { - format: this.options.viewformat - }); - - //language - this.options.datetimepicker.language = this.options.datetimepicker.language || 'en'; - - //store DPglobal - this.dpg = $.fn.datetimepicker.DPGlobal; - - //store parsed formats - this.parsedFormat = this.dpg.parseFormat(this.options.format, this.options.formatType); - this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat, this.options.formatType); - }, - - render: function () { - this.$input.datetimepicker(this.options.datetimepicker); - - //adjust container position when viewMode changes - //see https://github.com/smalot/bootstrap-datetimepicker/pull/80 - this.$input.on('changeMode', function(e) { - var f = $(this).closest('form').parent(); - //timeout here, otherwise container changes position before form has new size - setTimeout(function(){ - f.triggerHandler('resize'); - }, 0); - }); - - //"clear" link - if(this.options.clear) { - this.$clear = $('').html(this.options.clear).click($.proxy(function(e){ - e.preventDefault(); - e.stopPropagation(); - this.clear(); - }, this)); - - this.$tpl.parent().append($('
').append(this.$clear)); - } - }, - - value2html: function(value, element) { - //formatDate works with UTCDate! - var text = value ? this.dpg.formatDate(this.toUTC(value), this.parsedViewFormat, this.options.datetimepicker.language, this.options.formatType) : ''; - if(element) { - DateTime.superclass.value2html(text, element); - } else { - return text; - } - }, - - html2value: function(html) { - //parseDate return utc date! - var value = this.parseDate(html, this.parsedViewFormat); - return value ? this.fromUTC(value) : null; - }, - - value2str: function(value) { - //formatDate works with UTCDate! - return value ? this.dpg.formatDate(this.toUTC(value), this.parsedFormat, this.options.datetimepicker.language, this.options.formatType) : ''; - }, - - str2value: function(str) { - //parseDate return utc date! - var value = this.parseDate(str, this.parsedFormat); - return value ? this.fromUTC(value) : null; - }, - - value2submit: function(value) { - return this.value2str(value); - }, - - value2input: function(value) { - if(value) { - this.$input.data('datetimepicker').setDate(value); - } - }, - - input2value: function() { - //date may be cleared, in that case getDate() triggers error - var dt = this.$input.data('datetimepicker'); - return dt.date ? dt.getDate() : null; - }, - - activate: function() { - }, - - clear: function() { - this.$input.data('datetimepicker').date = null; - this.$input.find('.active').removeClass('active'); - if(!this.options.showbuttons) { - this.$input.closest('form').submit(); - } - }, - - autosubmit: function() { - this.$input.on('mouseup', '.minute', function(e){ - var $form = $(this).closest('form'); - setTimeout(function() { - $form.submit(); - }, 200); - }); - }, - - //convert date from local to utc - toUTC: function(value) { - return value ? new Date(value.valueOf() - value.getTimezoneOffset() * 60000) : value; - }, - - //convert date from utc to local - fromUTC: function(value) { - return value ? new Date(value.valueOf() + value.getTimezoneOffset() * 60000) : value; - }, - - /* - For incorrect date bootstrap-datetimepicker returns current date that is not suitable - for datetimefield. - This function returns null for incorrect date. - */ - parseDate: function(str, format) { - var date = null, formattedBack; - if(str) { - date = this.dpg.parseDate(str, format, this.options.datetimepicker.language, this.options.formatType); - if(typeof str === 'string') { - formattedBack = this.dpg.formatDate(date, format, this.options.datetimepicker.language, this.options.formatType); - if(str !== formattedBack) { - date = null; - } - } - } - return date; - } - - }); - - DateTime.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { - /** - @property tpl - @default
- **/ - tpl:'
', - /** - @property inputclass - @default null - **/ - inputclass: null, - /** - Format used for sending value to server. Also applied when converting date from data-value attribute.
- Possible tokens are: d, dd, m, mm, yy, yyyy, h, i - - @property format - @type string - @default yyyy-mm-dd hh:ii - **/ - format:'yyyy-mm-dd hh:ii', - formatType:'standard', - /** - Format used for displaying date. Also applied when converting date from element's text on init. - If not specified equals to format - - @property viewformat - @type string - @default null - **/ - viewformat: null, - /** - Configuration of datetimepicker. - Full list of options: https://github.com/smalot/bootstrap-datetimepicker - - @property datetimepicker - @type object - @default { } - **/ - datetimepicker:{ - todayHighlight: false, - autoclose: false - }, - /** - Text shown as clear date button. - If false clear button will not be rendered. - - @property clear - @type boolean|string - @default 'x clear' - **/ - clear: '× clear' - }); - - $.fn.editabletypes.datetime = DateTime; - -}(window.jQuery)); -/** -Bootstrap datetimefield input - datetime input for inline mode. -Shows normal and binds popup datetimepicker. -Automatically shown in inline mode. - -@class datetimefield -@extends datetime - -**/ -(function ($) { - "use strict"; - - var DateTimeField = function (options) { - this.init('datetimefield', options, DateTimeField.defaults); - this.initPicker(options, DateTimeField.defaults); - }; - - $.fn.editableutils.inherit(DateTimeField, $.fn.editabletypes.datetime); - - $.extend(DateTimeField.prototype, { - render: function () { - this.$input = this.$tpl.find('input'); - this.setClass(); - this.setAttr('placeholder'); - - this.$tpl.datetimepicker(this.options.datetimepicker); - - //need to disable original event handlers - this.$input.off('focus keydown'); - - //update value of datepicker - this.$input.keyup($.proxy(function(){ - this.$tpl.removeData('date'); - this.$tpl.datetimepicker('update'); - }, this)); - - }, - - value2input: function(value) { - this.$input.val(this.value2html(value)); - this.$tpl.datetimepicker('update'); - }, - - input2value: function() { - return this.html2value(this.$input.val()); - }, - - activate: function() { - $.fn.editabletypes.text.prototype.activate.call(this); - }, - - autosubmit: function() { - //reset autosubmit to empty - } - }); - - DateTimeField.defaults = $.extend({}, $.fn.editabletypes.datetime.defaults, { - /** - @property tpl - **/ - tpl:'
', - /** - @property inputclass - @default 'input-medium' - **/ - inputclass: 'input-medium', - - /* datetimepicker config */ - datetimepicker:{ - todayHighlight: false, - autoclose: true - } - }); - - $.fn.editabletypes.datetimefield = DateTimeField; - -}(window.jQuery)); \ No newline at end of file diff --git a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js b/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js deleted file mode 100755 index 7cd887651..000000000 --- a/templates/admin/default/assets/bootstrap-editable/js/bootstrap-editable.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! X-editable - v1.4.7 -* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery -* http://github.com/vitalets/x-editable -* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ -!function(a){"use strict";var b=function(b,c){this.options=a.extend({},a.fn.editableform.defaults,c),this.$div=a(b),this.options.scope||(this.options.scope=this)};b.prototype={constructor:b,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value),this.input.prerender()},initTemplate:function(){this.$form=a(a.fn.editableform.template)},initButtons:function(){var b=this.$form.find(".editable-buttons");b.append(a.fn.editableform.buttons),"bottom"===this.options.showbuttons&&b.addClass("editable-buttons-bottom")},render:function(){this.$loading=a(a.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.isSaving=!1,this.$div.triggerHandler("rendering"),this.initInput(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),a.when(this.input.render()).then(a.proxy(function(){if(this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(a.proxy(this.cancel,this)),this.input.error)this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(a){a.preventDefault()});else{this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled");var b=null===this.value||void 0===this.value||""===this.value?this.options.defaultValue:this.value;this.input.value2input(b),this.$form.submit(a.proxy(this.submit,this))}this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var a,b;this.$form?(a=this.$form.outerWidth(),b=this.$form.outerHeight(),a&&this.$loading.width(a),b&&this.$loading.height(b),this.$form.hide()):(a=this.$loading.parent().width(),a&&this.$loading.width(a)),this.$loading.show()},showForm:function(a){this.$loading.hide(),this.$form.show(),a!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(b){var c,d=this.$form.find(".control-group"),e=this.$form.find(".editable-error-block");if(b===!1)d.removeClass(a.fn.editableform.errorGroupClass),e.removeClass(a.fn.editableform.errorBlockClass).empty().hide();else{if(b){c=b.split("\n");for(var f=0;f").text(c[f]).html();b=c.join("
")}d.addClass(a.fn.editableform.errorGroupClass),e.addClass(a.fn.editableform.errorBlockClass).html(b).show()}},submit:function(b){b.stopPropagation(),b.preventDefault();var c,d=this.input.input2value();if(c=this.validate(d))return this.error(c),this.showForm(),void 0;if(!this.options.savenochange&&this.input.value2str(d)==this.input.value2str(this.value))return this.$div.triggerHandler("nochange"),void 0;var e=this.input.value2submit(d);this.isSaving=!0,a.when(this.save(e)).done(a.proxy(function(a){this.isSaving=!1;var b="function"==typeof this.options.success?this.options.success.call(this.options.scope,a,d):null;return b===!1?(this.error(!1),this.showForm(!1),void 0):"string"==typeof b?(this.error(b),this.showForm(),void 0):(b&&"object"==typeof b&&b.hasOwnProperty("newValue")&&(d=b.newValue),this.error(!1),this.value=d,this.$div.triggerHandler("save",{newValue:d,submitValue:e,response:a}),void 0)},this)).fail(a.proxy(function(a){this.isSaving=!1;var b;b="function"==typeof this.options.error?this.options.error.call(this.options.scope,a,d):"string"==typeof a?a:a.responseText||a.statusText||"Unknown error!",this.error(b),this.showForm()},this))},save:function(b){this.options.pk=a.fn.editableutils.tryParseJson(this.options.pk,!0);var c,d="function"==typeof this.options.pk?this.options.pk.call(this.options.scope):this.options.pk,e=!!("function"==typeof this.options.url||this.options.url&&("always"===this.options.send||"auto"===this.options.send&&null!==d&&void 0!==d));return e?(this.showLoading(),c={name:this.options.name||"",value:b,pk:d},"function"==typeof this.options.params?c=this.options.params.call(this.options.scope,c):(this.options.params=a.fn.editableutils.tryParseJson(this.options.params,!0),a.extend(c,this.options.params)),"function"==typeof this.options.url?this.options.url.call(this.options.scope,c):a.ajax(a.extend({url:this.options.url,data:c,type:"POST"},this.options.ajaxOptions))):void 0},validate:function(a){return void 0===a&&(a=this.value),"function"==typeof this.options.validate?this.options.validate.call(this.options.scope,a):void 0},option:function(a,b){a in this.options&&(this.options[a]=b),"value"===a&&this.setValue(b)},setValue:function(a,b){this.value=b?this.input.str2value(a):a,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},a.fn.editableform=function(c){var d=arguments;return this.each(function(){var e=a(this),f=e.data("editableform"),g="object"==typeof c&&c;f||e.data("editableform",f=new b(this,g)),"string"==typeof c&&f[c].apply(f,Array.prototype.slice.call(d,1))})},a.fn.editableform.Constructor=b,a.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,defaultValue:null,send:"auto",validate:null,success:null,error:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},a.fn.editableform.template='
',a.fn.editableform.loading='
',a.fn.editableform.buttons='',a.fn.editableform.errorGroupClass=null,a.fn.editableform.errorBlockClass="editable-error",a.fn.editableform.engine="jqeury"}(window.jQuery),function(a){"use strict";a.fn.editableutils={inherit:function(a,b){var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a,a.superclass=b.prototype},setCursorPosition:function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var c=a.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",b),c.select()}},tryParseJson:function(a,b){if("string"==typeof a&&a.length&&a.match(/^[\{\[].*[\}\]]$/))if(b)try{a=new Function("return "+a)()}catch(c){}finally{return a}else a=new Function("return "+a)();return a},sliceObj:function(b,c,d){var e,f,g={};if(!a.isArray(c)||!c.length)return g;for(var h=0;h").text(b).html()},itemsByValue:function(b,c,d){if(!c||null===b)return[];if("function"!=typeof d){var e=d||"value";d=function(a){return a[e]}}var f=a.isArray(b),g=[],h=this;return a.each(c,function(c,e){if(e.children)g=g.concat(h.itemsByValue(b,e.children,d));else if(f)a.grep(b,function(a){return a==(e&&"object"==typeof e?d(e):e)}).length&&g.push(e);else{var i=e&&"object"==typeof e?d(e):e;b==i&&g.push(e)}}),g},createInput:function(b){var c,d,e,f=b.type;return"date"===f&&("inline"===b.mode?a.fn.editabletypes.datefield?f="datefield":a.fn.editabletypes.dateuifield&&(f="dateuifield"):a.fn.editabletypes.date?f="date":a.fn.editabletypes.dateui&&(f="dateui"),"date"!==f||a.fn.editabletypes.date||(f="combodate")),"datetime"===f&&"inline"===b.mode&&(f="datetimefield"),"wysihtml5"!==f||a.fn.editabletypes[f]||(f="textarea"),"function"==typeof a.fn.editabletypes[f]?(c=a.fn.editabletypes[f],d=this.sliceObj(b,this.objectKeys(c.defaults)),e=new c(d)):(a.error("Unknown type: "+f),!1)},supportsTransitions:function(){var a=document.body||document.documentElement,b=a.style,c="transition",d=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof b[c])return!0;c=c.charAt(0).toUpperCase()+c.substr(1);for(var e=0;e"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(a){if(this.tip()&&this.tip().is(":visible")&&this.$element.hasClass("editable-open")){if(this.$form.data("editableform").isSaving)return this.delayedHide={reason:a},void 0;this.delayedHide=!1,this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",a||"manual")}},innerShow:function(){},innerHide:function(){},toggle:function(a){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(a)},setPosition:function(){},save:function(a,b){this.$element.triggerHandler("save",b),this.hide("save")},option:function(a,b){this.options[a]=b,a in this.containerOptions?(this.containerOptions[a]=b,this.setContainerOption(a,b)):(this.formOptions[a]=b,this.$form&&this.$form.editableform("option",a,b))},setContainerOption:function(a,b){this.call("option",a,b)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(b){a(".editable-open").each(function(c,d){if(d!==b&&!a(d).find(b).length){var e=a(d),f=e.data("editableContainer");f&&("cancel"===f.options.onblur?e.data("editableContainer").hide("onblur"):"submit"===f.options.onblur&&e.data("editableContainer").tip().find("form").submit())}})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},a.fn.editableContainer=function(d){var e=arguments;return this.each(function(){var f=a(this),g="editableContainer",h=f.data(g),i="object"==typeof d&&d,j="inline"===i.mode?c:b;h||f.data(g,h=new j(this,i)),"string"==typeof d&&h[d].apply(h,Array.prototype.slice.call(e,1))})},a.fn.editableContainer.Popup=b,a.fn.editableContainer.Inline=c,a.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:!1,mode:"popup"},jQuery.event.special.destroyed={remove:function(a){a.handler&&a.handler()}}}(window.jQuery),function(a){"use strict";a.extend(a.fn.editableContainer.Inline.prototype,a.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=a(""),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,a.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.editable.defaults,c,a.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init(),this.options.highlight&&!a.fn.editableutils.supportsTransitions()&&(this.options.highlight=!1)};b.prototype={constructor:b,init:function(){var b,c=!1;if(this.options.name=this.options.name||this.$element.attr("id"),this.options.scope=this.$element[0],this.input=a.fn.editableutils.createInput(this.options),this.input){switch(void 0===this.options.value||null===this.options.value?(this.value=this.input.html2value(a.trim(this.$element.html())),c=!0):(this.options.value=a.fn.editableutils.tryParseJson(this.options.value,!0),this.value="string"==typeof this.options.value?this.input.str2value(this.options.value):this.options.value),this.$element.addClass("editable"),"textarea"===this.input.type&&this.$element.addClass("editable-pre-wrapped"),"manual"!==this.options.toggle?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",a.proxy(function(a){if(this.options.disabled||a.preventDefault(),"mouseenter"===this.options.toggle)this.show();else{var b="click"!==this.options.toggle;this.toggle(b)}},this))):this.$element.attr("tabindex",-1),"function"==typeof this.options.display&&(this.options.autotext="always"),this.options.autotext){case"always":b=!0;break;case"auto":b=!a.trim(this.$element.text()).length&&null!==this.value&&void 0!==this.value&&!c;break;default:b=!1}a.when(b?this.render():!0).then(a.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))}},initLive:function(){var b=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",b,a.proxy(function(b){var c=a(b.target);c.data("editable")||(c.hasClass(this.options.emptyclass)&&c.empty(),c.editable(this.options).trigger(b))},this))},render:function(a){return this.options.display!==!1?this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,a):"function"==typeof this.options.display?this.options.display.call(this.$element[0],this.value,a):this.input.value2html(this.value,this.$element[0]):void 0},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),"manual"!==this.options.toggle&&"-1"===this.$element.attr("tabindex")&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(b,c){return b&&"object"==typeof b?(a.each(b,a.proxy(function(b,c){this.option(a.trim(b),c)},this)),void 0):(this.options[b]=c,"disabled"===b?c?this.disable():this.enable():("value"===b&&this.setValue(c),this.container&&this.container.option(b,c),this.input.option&&this.input.option(b,c),void 0))},handleEmpty:function(b){this.options.display!==!1&&(this.isEmpty=void 0!==b?b:""===a.trim(this.$element.html())?!0:""!==a.trim(this.$element.text())?!1:!this.$element.height()||!this.$element.width(),this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.html(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass))},show:function(b){if(!this.options.disabled){if(this.container){if(this.container.tip().is(":visible"))return}else{var c=a.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(c),this.$element.on("save.internal",a.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}this.container.show(b)}},hide:function(){this.container&&this.container.hide()},toggle:function(a){this.container&&this.container.tip().is(":visible")?this.hide():this.show(a)},save:function(a,b){if(this.options.unsavedclass){var c=!1;c=c||"function"==typeof this.options.url,c=c||this.options.display===!1,c=c||void 0!==b.response,c=c||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(b.newValue),c?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}if(this.options.highlight){var d=this.$element,e=d.css("background-color");d.css("background-color",this.options.highlight),setTimeout(function(){"transparent"===e&&(e=""),d.css("background-color",e),d.addClass("editable-bg-transition"),setTimeout(function(){d.removeClass("editable-bg-transition")},1700)},10)}this.setValue(b.newValue,!1,b.response)},validate:function(){return"function"==typeof this.options.validate?this.options.validate.call(this,this.value):void 0},setValue:function(b,c,d){this.value=c?this.input.str2value(b):b,this.container&&this.container.option("value",this.value),a.when(this.render(d)).then(a.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.disable(),this.container&&this.container.destroy(),this.input.destroy(),"manual"!==this.options.toggle&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable editable-open editable-disabled"),this.$element.removeData("editable")}},a.fn.editable=function(c){var d={},e=arguments,f="editable";switch(c){case"validate":return this.each(function(){var b,c=a(this),e=c.data(f);e&&(b=e.validate())&&(d[e.options.name]=b)}),d;case"getValue":return 2===arguments.length&&arguments[1]===!0?d=this.eq(0).data(f).value:this.each(function(){var b=a(this),c=b.data(f);c&&void 0!==c.value&&null!==c.value&&(d[c.options.name]=c.input.value2submit(c.value))}),d;case"submit":var g,h=arguments[1]||{},i=this,j=this.editable("validate");return a.isEmptyObject(j)?(g=this.editable("getValue"),h.data&&a.extend(g,h.data),a.ajax(a.extend({url:h.url,data:g,type:"POST"},h.ajaxOptions)).success(function(a){"function"==typeof h.success&&h.success.call(i,a,h)}).error(function(){"function"==typeof h.error&&h.error.apply(i,arguments)})):"function"==typeof h.error&&h.error.call(i,j),this}return this.each(function(){var d=a(this),g=d.data(f),h="object"==typeof c&&c;return h&&h.selector?(g=new b(this,h),void 0):(g||d.data(f,g=new b(this,h)),"string"==typeof c&&g[c].apply(g,Array.prototype.slice.call(e,1)),void 0)})},a.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null,highlight:"#FFFF80"}}(window.jQuery),function(a){"use strict";a.fn.editabletypes={};var b=function(){};b.prototype={init:function(b,c,d){this.type=b,this.options=a.extend({},d,c)},prerender:function(){this.$tpl=a(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(b,c){a(c).text(a.trim(b))},html2value:function(b){return a("
").html(b).text()},value2str:function(a){return a},str2value:function(a){return a},value2submit:function(a){return a},value2input:function(a){this.$input.val(a)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(b){return a("
").text(b).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(a){void 0!==this.options[a]&&null!==this.options[a]&&this.$input.attr(a,this.options[a])},option:function(a,b){this.options[a]=b}},b.defaults={tpl:"",inputclass:null,scope:null,showbuttons:!0},a.extend(a.fn.editabletypes,{abstractinput:b})}(window.jQuery),function(a){"use strict";var b=function(){};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){var b=a.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),b.resolve()},function(){this.error=this.options.sourceError,b.resolve()}),b.promise()},html2value:function(){return null},value2html:function(b,c,d,e){var f=a.Deferred(),g=function(){"function"==typeof d?d.call(c,b,this.sourceData,e):this.value2htmlFinal(b,c),f.resolve()};return null===b?g.call(this):this.onSourceReady(g,function(){f.resolve()}),f.promise()},onSourceReady:function(b,c){var d;if(a.isFunction(this.options.source)?(d=this.options.source.call(this.options.scope),this.sourceData=null):d=this.options.source,this.options.sourceCache&&a.isArray(this.sourceData))return b.call(this),void 0;try{d=a.fn.editableutils.tryParseJson(d,!1)}catch(e){return c.call(this),void 0}if("string"==typeof d){if(this.options.sourceCache){var f,g=d;if(a(document).data(g)||a(document).data(g,{}),f=a(document).data(g),f.loading===!1&&f.sourceData)return this.sourceData=f.sourceData,this.doPrepend(),b.call(this),void 0;if(f.loading===!0)return f.callbacks.push(a.proxy(function(){this.sourceData=f.sourceData,this.doPrepend(),b.call(this)},this)),f.err_callbacks.push(a.proxy(c,this)),void 0;f.loading=!0,f.callbacks=[],f.err_callbacks=[]}a.ajax({url:d,type:"get",cache:!1,dataType:"json",success:a.proxy(function(d){f&&(f.loading=!1),this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(f&&(f.sourceData=this.sourceData,a.each(f.callbacks,function(){this.call()})),this.doPrepend(),b.call(this)):(c.call(this),f&&a.each(f.err_callbacks,function(){this.call()}))},this),error:a.proxy(function(){c.call(this),f&&(f.loading=!1,a.each(f.err_callbacks,function(){this.call()}))},this)})}else this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(this.doPrepend(),b.call(this)):c.call(this)},doPrepend:function(){null!==this.options.prepend&&void 0!==this.options.prepend&&(a.isArray(this.prependData)||(a.isFunction(this.options.prepend)&&(this.options.prepend=this.options.prepend.call(this.options.scope)),this.options.prepend=a.fn.editableutils.tryParseJson(this.options.prepend,!0),"string"==typeof this.options.prepend&&(this.options.prepend={"":this.options.prepend}),this.prependData=this.makeArray(this.options.prepend)),a.isArray(this.prependData)&&a.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData)))},renderList:function(){},value2htmlFinal:function(){},makeArray:function(b){var c,d,e,f,g=[];if(!b||"string"==typeof b)return null;if(a.isArray(b)){f=function(a,b){return d={value:a,text:b},c++>=2?!1:void 0};for(var h=0;h1&&(e.children&&(e.children=this.makeArray(e.children)),g.push(e))):g.push({value:e,text:e})}else a.each(b,function(a,b){g.push({value:a,text:b})});return g},option:function(a,b){this.options[a]=b,"source"===a&&(this.sourceData=null),"prepend"===a&&(this.prependData=null)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0}),a.fn.editabletypes.list=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("text",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),a.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=a(''),this.$input.after(this.$clear).css("padding-right",24).keyup(a.proxy(function(b){if(!~a.inArray(b.keyCode,[40,38,9,13,27])){clearTimeout(this.t);var c=this;this.t=setTimeout(function(){c.toggleClear(b)},100)}},this)).parent().css("position","relative"),this.$clear.click(a.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(){if(this.$clear){var a=this.$input.val().length,b=this.$clear.is(":visible");a&&!b&&this.$clear.show(),!a&&b&&this.$clear.hide()}},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),a.fn.editabletypes.text=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("textarea",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(b){b.ctrlKey&&13===b.which&&a(this).closest("form").submit()})},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),a.fn.editabletypes.textarea=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("select",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.list),a.extend(b.prototype,{renderList:function(){this.$input.empty();var b=function(c,d){var e;if(a.isArray(d))for(var f=0;f",e),d[f].children))):(e.value=d[f].value,d[f].disabled&&(e.disabled=!0),c.append(a("
 
'+u+""+m.getUTCDate()+"
'+l.headTemplate+""+l.footTemplate+"
"+"
"+'
'+''+l.headTemplate+l.contTemplate+l.footTemplate+"
"+"
"+'
'+''+l.headTemplate+l.contTemplate+l.footTemplate+"
"+"
"+"
",a.fn.datepicker.DPGlobal=l,a.fn.datepicker.noConflict=function(){return a.fn.datepicker=g,this},a(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(b){var c=a(this);c.data("datepicker")||(b.preventDefault(),h.call(c,"show"))}),a(function(){h.call(a('[data-provide="datepicker-inline"]'))})}(window.jQuery),function(a){"use strict";a.fn.bdatepicker=a.fn.datepicker.noConflict(),a.fn.datepicker||(a.fn.datepicker=a.fn.bdatepicker);var b=function(a){this.init("date",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datepicker=a.fn.editableutils.tryParseJson(b.datepicker,!0),this.options.datepicker=a.extend({},c.datepicker,b.datepicker,{format:this.options.viewformat}),this.options.datepicker.language=this.options.datepicker.language||"en",this.dpg=a.fn.bdatepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat)},render:function(){this.$input.bdatepicker(this.options.datepicker),this.options.clear&&(this.$clear=a('').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('
').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):"";b.superclass.value2html(d,c)},html2value:function(a){return this.parseDate(a,this.parsedViewFormat)},value2str:function(a){return a?this.dpg.formatDate(a,this.parsedFormat,this.options.datepicker.language):""},str2value:function(a){return this.parseDate(a,this.parsedFormat)},value2submit:function(a){return this.value2str(a)},value2input:function(a){this.$input.bdatepicker("update",a)},input2value:function(){return this.$input.data("datepicker").date},activate:function(){},clear:function(){this.$input.data("datepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".day",function(b){if(!a(b.currentTarget).is(".old")&&!a(b.currentTarget).is(".new")){var c=a(this).closest("form");setTimeout(function(){c.submit()},200)}})},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datepicker.language),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datepicker.language),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd",viewformat:null,datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!1},clear:"× clear"}),a.fn.editabletypes.date=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.date),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.bdatepicker(this.options.datepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.bdatepicker("update")},this))},value2input:function(a){this.$input.val(a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):""),this.$tpl.bdatepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.date.defaults,{tpl:'
',inputclass:"input-small",datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!0}}),a.fn.editabletypes.datefield=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetime",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datetimepicker=a.fn.editableutils.tryParseJson(b.datetimepicker,!0),this.options.datetimepicker=a.extend({},c.datetimepicker,b.datetimepicker,{format:this.options.viewformat}),this.options.datetimepicker.language=this.options.datetimepicker.language||"en",this.dpg=a.fn.datetimepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format,this.options.formatType),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat,this.options.formatType)},render:function(){this.$input.datetimepicker(this.options.datetimepicker),this.$input.on("changeMode",function(){var b=a(this).closest("form").parent();setTimeout(function(){b.triggerHandler("resize")},0)}),this.options.clear&&(this.$clear=a('').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('
').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(this.toUTC(a),this.parsedViewFormat,this.options.datetimepicker.language,this.options.formatType):"";return c?(b.superclass.value2html(d,c),void 0):d},html2value:function(a){var b=this.parseDate(a,this.parsedViewFormat);return b?this.fromUTC(b):null},value2str:function(a){return a?this.dpg.formatDate(this.toUTC(a),this.parsedFormat,this.options.datetimepicker.language,this.options.formatType):""},str2value:function(a){var b=this.parseDate(a,this.parsedFormat);return b?this.fromUTC(b):null},value2submit:function(a){return this.value2str(a)},value2input:function(a){a&&this.$input.data("datetimepicker").setDate(a)},input2value:function(){var a=this.$input.data("datetimepicker");return a.date?a.getDate():null},activate:function(){},clear:function(){this.$input.data("datetimepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".minute",function(){var b=a(this).closest("form");setTimeout(function(){b.submit()},200)})},toUTC:function(a){return a?new Date(a.valueOf()-6e4*a.getTimezoneOffset()):a},fromUTC:function(a){return a?new Date(a.valueOf()+6e4*a.getTimezoneOffset()):a},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datetimepicker.language,this.options.formatType),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datetimepicker.language,this.options.formatType),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd hh:ii",formatType:"standard",viewformat:null,datetimepicker:{todayHighlight:!1,autoclose:!1},clear:"× clear"}),a.fn.editabletypes.datetime=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetimefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.datetime),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.datetimepicker(this.options.datetimepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.datetimepicker("update")},this))},value2input:function(a){this.$input.val(this.value2html(a)),this.$tpl.datetimepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.datetime.defaults,{tpl:'
',inputclass:"input-medium",datetimepicker:{todayHighlight:!1,autoclose:!0}}),a.fn.editabletypes.datetimefield=b}(window.jQuery); \ No newline at end of file diff --git a/templates/admin/default/assets/css/admin.less b/templates/admin/default/assets/css/admin.less deleted file mode 100755 index 4b5369a80..000000000 --- a/templates/admin/default/assets/css/admin.less +++ /dev/null @@ -1,811 +0,0 @@ -// -- Tools -------------------------------------------------------------------- - -.rounded(@radius: 2px) { - -webkit-border-radius: @radius; - -moz-border-radius: @radius; - border-radius: @radius; -} - -.border-radius(@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { - -webkit-border-top-right-radius: @topright; - -webkit-border-bottom-right-radius: @bottomright; - -webkit-border-bottom-left-radius: @bottomleft; - -webkit-border-top-left-radius: @topleft; - -moz-border-radius-topright: @topright; - -moz-border-radius-bottomright: @bottomright; - -moz-border-radius-bottomleft: @bottomleft; - -moz-border-radius-topleft: @topleft; - border-top-right-radius: @topright; - border-bottom-right-radius: @bottomright; - border-bottom-left-radius: @bottomleft; - border-top-left-radius: @topleft; - .background-clip(padding-box); -} - -.background-clip(@argument: padding-box) { - -moz-background-clip: @argument; - -webkit-background-clip: @argument; - background-clip: @argument; -} - -.box-shadow(@shadow: 0 1px 2px rgba(0,0,0,.05)) { - -webkit-box-shadow: @shadow; - -moz-box-shadow: @shadow; - box-shadow: @shadow; -} - -// -- Base styling ------------------------------------------------------------ - -html, body { - height: 100%; - margin: 0; - padding: 0; -} - -body { - background: url("img/bg.jpg") repeat; - font-size: 13px; -} - -h3, h4 { - color: #5a6876; - background: -webkit-gradient(linear, left top, left bottom, from(#42505d), to(#72808e)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; -} - -h3 { - padding: 0px; - margin: 0px 0px 20px 0px; - text-align: left; - font-size : 18px; -} - -h4 { - padding: 0px 0px 20px 0px; - margin: 0px; - text-align: left; -} - -#wrapper { - padding-top: 20px; -} - -a { - color: #e9720f; - font-weight: bold; - - &.btn { - font-weight: normal; - } -} - -// Bootstrap Adjustements ------------------------------------------------------ - -hr { - border: 0; - border-top: 1px solid rgba(0, 0, 0, 0.1); - border-bottom: 1px solid rgba(250, 250, 250, 0.1); - width: 90%; - margin: 0 auto; - clear: both; - margin-top: 20px; -} - -.btn-primary, .btn-large { - background: #e9730f; - background-image: linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -o-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -moz-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -webkit-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -ms-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -webkit-gradient( - linear, - left bottom, - left top, - color-stop(0, rgb(227,83,11)), - color-stop(1, rgb(243,153,34)) - ); - box-shadow: inset 0px 0px 2px rgba(250,250,250,0.5), 0px 1px 3px rgba(0,0,0,0.2); - color: white; -} - -.btn-large:hover, .btn-primary:hover { - background: #e9730f; - background-image: linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -o-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -moz-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -webkit-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -ms-linear-gradient(bottom, rgb(227,83,11) 0%, rgb(243,153,34) 100%); - background-image: -webkit-gradient( - linear, - left bottom, - left top, - color-stop(0, rgb(227,83,11)), - color-stop(1, rgb(243,153,34)) - ); - box-shadow: inset 0px 0px 2px rgba(250,250,250,0.8), 0px 1px 3px rgba(0,0,0,0.2); - color: white; -} - -.footer { - background: none repeat scroll 0 0 transparent; - border: medium none; - box-shadow: none; - color: #7D756A; - margin-bottom: 0; - padding: 35px 15px 15px; - text-align: left; -} - -// -- Top bar ----------------------------------------------------------------- - -.topbar { - - @top-bar-height: 50px; - - background: url("img/top.jpg") repeat-x; - color: #6d737b; - font-size: 13px; - font-weight: bold; - text-shadow: 0px 1px 1px black; - - .form-search { - - position: relative; - float: right; - margin: 0px; - - .control-group { - margin-bottom: 0px; - } - - input.search-query { - background: url("img/search.png") no-repeat; - width: 212px; - height: 20px; - outline: none; - border: none; - padding: 5px 20px 5px 20px; - .rounded(0px); - font-size: 12px; - color: #eee; - - &:focus { - box-shadow: none; - color: white; - } - } - - button.btn { - position: absolute; - right: 5px; - text-indent: -13337px; - background: url("img/search-icon.png") no-repeat; - width: 16px; - height: 15px; - display: block; - cursor: pointer; - outline: none; - border: none; - top: 17px; - box-shadow: none; - .rounded(0px); - z-index: 1337; - } - } - - .container { - line-height: @top-bar-height; - } - - .version-info { - float: left; - line-height: @top-bar-height; - background: url("img/top-bar-logo.png") left -3px no-repeat; - padding-left: 100px; - - } - - .user-info { - float: right; - line-height: @top-bar-height; - margin-left: 20px; - color: #fff; - - a.logout { - text-indent: -13337px; - display: inline-block; - background: url("img/logout.png") left center no-repeat; - width: 23px; - height: @top-bar-height; - } - - a.profile { - color: #fff; - } - } - - .view-shop { - line-height: @top-bar-height; - margin-right: 20px; - float: right; - a { - color: #fff; - text-decoration: none; - } - } -} - -// -- Brandbar ---------------------------------------------------------------- - -.loginpage { - - .hero-unit { - background-color: transparent !important; - - h1 { - margin-bottom: 25px; - } - } - - .well { - background-color: #E4E3DE; - border: 1px solid rgba(0, 0, 0, 0.2); - box-shadow: 0 -4px 0 rgba(0, 0, 0, 0.05) inset; - } -} - -.brandbar { - - background: url("img/header.jpg") repeat-x; - height: 90px; - - a.brand { - text-indent: -133337px; - display: block; - float: left; - margin-right: 20px; - background: url("img/logo.png") 0px 12px no-repeat; - width: 124px; - height: 63px; - } - - .breadcrumb { - .rounded(0px); - padding: 25px 0px 25px 30px; - background: url("img/logo-light.png") left center no-repeat; - float: left; - margin: 12px 0px 0px 0px; - - a { - color: #949aa1; - text-shadow: 0px 1px 0px rgba(0,0,0,0.8); - } - - .active { - color: #FFF; - text-shadow: 0px 1px 0px rgba(0,0,0,0.8); - border-bottom: 1px dotted white; - } - } - - .Blocmoncompte { - float: right; - margin: 0px; - padding: 0px; - margin-top: 35px; - - color: white; - font-size: 13px; - text-shadow: 0px 1px 0px rgba(0,0,0,0.8); - } - - dt { - float: left; - margin-right: 15px; - } - - .deconnexion { - float: right; - margin: 0px; - - a { - text-indent: -13337px; - display: block; - background: url("img/deconnexion.png") no-repeat; - width: 23px; - height: 24px; - } - } -} - -.brandbar-wide { - width: 100%; -} - -// -- Navigation bar ---------------------------------------------------------- - -.navbar { - margin-bottom: 0px; -} - -.navbar-inner { - border-top: none; - .border-radius(0, 4px, 4px, 0); - - .container{ - width: 1170px; - } -} - -// -- Breadcrumb -------------------------------------------------------------- - -.breadcrumb { - margin-top: 0; - background-color: transparent; - padding: 0 15px; - - - > li > .divider { - color: inherit; - } - - > .active { - color: inherit; - } -} - -// -- Feed list on home page -------------------------------------------------- - -.feed-list { - h2 { - font-size: 24px; - line-height: 120%; - color: #E9730F; - - a { - &:hover { - color: inherit; - text-decoration: none; - } - } - } - - h3 { - margin-bottom: 0; - padding-bottom: 0; - font-size: 90%; - line-height: 100%; - } - - .feed-list-item{ - padding: 10px 20px; - } -} - -// -- Login form -------------------------------------------------------------- - -.form-signin { - max-width: 400px; - padding: 19px 29px 29px; - margin: 0 auto 20px; - background-color: #fff; - border: 1px solid #e5e5e5; - .rounded(5px); - .box-shadow; -} - -textarea:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, .uneditable-input:focus { - border: 1px solid #E9730F; - box-shadow: 0px 0px 8px #FFA65A; -} - -// -- Allow inline forms validation states ------------------------------------ - -form .warning .control-label, -form .warning .help-block, -form .warning .help-inline { - color: #c09853; -} - -form .warning .checkbox, -form .warning .radio, -form .warning input, -form .warning select, -form .warning textarea { - color: #c09853; -} - -form .warning input, -form .warning select, -form .warning textarea { - border-color: #c09853; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -form .warning input:focus, -form .warning select:focus, -form .warning textarea:focus { - border-color: #a47e3c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; -} - -form .warning .input-prepend .add-on, -form .warning .input-append .add-on { - color: #c09853; - background-color: #fcf8e3; - border-color: #c09853; -} - -form .error .control-label, -form .error .help-block, -form .error .help-inline { - color: #b94a48; -} - -form .error .checkbox, -form .error .radio, -form .error input, -form .error select, -form .error textarea { - color: #b94a48; -} - -form .error input, -form .error select, -form .error textarea { - border-color: #b94a48; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -form .error input:focus, -form .error select:focus, -form .error textarea:focus { - border-color: #953b39; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; -} - -form .error .input-prepend .add-on, -form .error .input-append .add-on { - color: #b94a48; - background-color: #f2dede; - border-color: #b94a48; -} - -form .success .control-label, -form .success .help-block, -form .success .help-inline { - color: #468847; -} - -form .success .checkbox, -form .success .radio, -form .success input, -form .success select, -form .success textarea { - color: #468847; -} - -form .success input, -form .success select, -form .success textarea { - border-color: #468847; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -form .success input:focus, -form .success select:focus, -form .success textarea:focus { - border-color: #356635; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; -} - -form .success .input-prepend .add-on, -form .success .input-append .add-on { - color: #468847; - background-color: #dff0d8; - border-color: #468847; -} - -form .info .control-label, -form .info .help-block, -form .info .help-inline { - color: #3a87ad; -} - -form .info .checkbox, -form .info .radio, -form .info input, -form .info select, -form .info textarea { - color: #3a87ad; -} - -form .info input, -form .info select, -form .info textarea { - border-color: #3a87ad; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -form .info input:focus, -form .info select:focus, -form .info textarea:focus { - border-color: #2d6987; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; -} - -form .info .input-prepend .add-on, -form .info .input-append .add-on { - color: #3a87ad; - background-color: #d9edf7; - border-color: #3a87ad; -} - -// -- General decoration of back-office boxes --------------------------------- - -.general-block-decorator { - background: none repeat scroll 0 0 white; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 4px 4px 4px 4px; - box-shadow: 0 -4px 0 rgba(0, 0, 0, 0.05) inset, 0 2px 3px rgba(0, 0, 0, 0.1); - padding: 1em; - margin-bottom: 20px; - - // The block title - .title { - color: #5A6876; - text-transform: uppercase; - font-weight: bold; - padding-bottom: 0.5em; - - line-height: 30px; - } - - .title-without-tabs { - border-bottom: 2px solid #A5CED8; - margin-bottom: 0.5em; - } - - // The action bar on the right - .actions { - text-align: right; - } - - .form { - margin-bottom: 0; - } -} - -// Reduce bottom margin of admin tabs. -.admin-tabs { - margin-bottom: 1em; -} - -// The overall form container -.form-container { - - // The inner toolbar (flags & save buttons) - .inner-toolbar { - - line-height: 30px; - margin-bottom: 1em; - border-bottom: 1px dotted #A5CED8; - padding-bottom: 0.5em; - - .inner-actions { - text-align: right; - } - - .nav-pills { - margin-bottom: 0; - - li a { - padding: 4px; - opacity: 0.3; - } - - li.active a { - opacity: 1; - background-color: #E7E7E7; - border: 1px solid #E9720F; - } - } - } -} - -// Modal dialog tweaking ------------------------------------------------------ - -.modal { - form { - margin-bottom: 0; - } -} -// -- Admin forms tweaking ---------------------------------------------------- - -label { - font-weight: bold; - - &.checkbox { - font-weight: normal; - } -} - -.input-append.input-block-level .add-on img { - max-height: 16px; -} - -// Information in field label -.label-help-block, .help-block { - color: lighten(#595959, 20); - display: block; - font-size: 80%; - font-style: italic; - line-height: 130%; - font-weight: normal; -} - - -.form-horizontal input + .help-block, -.form-horizontal select + .help-block, -.form-horizontal textarea + .help-block, -.form-horizontal .uneditable-input + .help-block, -.form-horizontal .input-prepend + .help-block, -.form-horizontal .input-append + .help-block -.help-block, .form-horizontal .help-block { - margin-top: 5px; -} - - -// Fix for append-fields shorter than others -// see http://stackoverflow.com/questions/13306670/bootstrap-prepended-and-appended-input-how-to-max-input-field-width -.input-append.input-block-level, -.input-prepend.input-block-level { - display: table; -} - -.input-append.input-block-level .add-on, -.input-prepend.input-block-level .add-on { - display: table-cell; - width: 1%; /* remove this if you want default bootstrap button width */ -} - -.input-append.input-block-level > input, -.input-prepend.input-block-level > input { - box-sizing: border-box; /* use bootstrap mixin or include vendor variants */ - display: table; /* table-cell is not working well in Chrome for small widths */ - min-height: inherit; - width: 100%; -} - -.input-append.input-block-level > input { - border-right: 0; -} - -.input-prepend.input-block-level > input { - border-left: 0; -} - -// -- Catalog Tables ---------------------------------------------------------- - -.table-striped { - - background: white; - margin-bottom: 1em; - - caption { - text-align: left; - color: #5A6876; - text-transform: uppercase; - font-weight: bold; - background-color: #fff; - padding-bottom: 0.5em; - border-bottom: 2px solid #A5CED8; - - line-height: 30px; - - .action-btn { - display: block; - float: right; - margin-left: 10px; - - text-transform: none; - } - } - - td, th { - text-align: center; - - &.text-center { - text-align: center; - } - &.text-left { - text-align: left; - } - &.text-right { - text-align: right; - } - - } - - td.object-title, th.object-title { - text-align: left; - } - - td.message { - // Center the alert box (20px bottom margin) in the table cell - padding: 20px 20px 0 20px; - } - - th { - a { - color: inherit; - } - } - - td { - vertical-align: middle; - - img { - border: 2px solid white; - border-radius: 4px 4px 4px 4px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); - } - - &.actions { - text-align: right; - } - } -} - -.menu-list-table .table-striped { - td, th { - text-align: left; - } - - td:nth-child(2) { - text-align: right; - } - - caption { - background-color: #FFFFFF; - border-bottom: 2px solid #A5CED8; - color: #5A6876; - font-weight: bold; - line-height: 30px; - text-align: left; - text-transform: uppercase; - } -} - -.table-left-aligned { - th, td { - text-align: left; - } - - select, textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"], .uneditable-input { - margin-bottom: 0; - } -} - -// Modal is no longer limited -.modal-body { - max-height: none; -} \ No newline at end of file diff --git a/templates/admin/default/assets/less/thelia/tables.less b/templates/admin/default/assets/less/thelia/tables.less index 060979487..d8b3a9e4e 100755 --- a/templates/admin/default/assets/less/thelia/tables.less +++ b/templates/admin/default/assets/less/thelia/tables.less @@ -17,9 +17,9 @@ } } - td, th { - text-align: center; - } + // td, th { + // text-align: center; + // } td.object-title, th.object-title { text-align: left; diff --git a/templates/admin/default/assets/less/thelia/thelia.less b/templates/admin/default/assets/less/thelia/thelia.less index 0d1074e5b..560f78bc1 100644 --- a/templates/admin/default/assets/less/thelia/thelia.less +++ b/templates/admin/default/assets/less/thelia/thelia.less @@ -8,6 +8,7 @@ @import "modals.less"; @import "tables.less"; @import "tablesorter.less"; +@import "bootstrap-editable.less"; // -- Base styling ------------------------------------------------------------ diff --git a/templates/admin/default/currencies.html b/templates/admin/default/currencies.html index 4876e2a08..97fac58c8 100644 --- a/templates/admin/default/currencies.html +++ b/templates/admin/default/currencies.html @@ -4,404 +4,384 @@ {block name="check-permissions"}admin.configuration.currencies.view{/block} -{block name="after-admin-css"} - {stylesheets file='assets/bootstrap-editable/css/bootstrap-editable.css' filters='cssembed'} - - {/stylesheets} -{/block} - {block name="main-content"} -
+
-
+
- + - {module_include location='currencies_top'} + {module_include location='currencies_top'} -
+
+
-
-
-
- - - - +
-
+
- {intl l='Currencies'} - {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.currencies.create"} - - - - - {/loop} + -
- {admin_sortable_header - current_order=$order - order='id' - reverse_order='id_reverse' - path='/admin/configuration/currencies' - label="{intl l='ID'}" - } - - {admin_sortable_header - current_order=$order - order='alpha' - reverse_order='alpha_reverse' - path='/admin/configuration/currencies' - label="{intl l='Name'}" - } -
+ + + + - + - + - + - + - + - {module_include location='currencies_table_header'} + - - + {module_include location='currencies_table_header'} - {loop name="currencies" type="currency" backend_context="1" lang=$lang_id order=$order} - - + + + + + + {loop name="currencies" type="currency" backend_context="1" lang=$lang_id order=$order} + + - + - + - + - + - + - + - {module_include location='currencies_table_row'} + {module_include location='currencies_table_row'} - - - {/loop} + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.currencies.delete"} + + + + {/loop} + + + + {/loop} + {elseloop rel="currencies"} + + + + {/elseloop} + +
+ {intl l='Currencies'} + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.currencies.create"} + + + + + + + {/loop} +
+ {admin_sortable_header + current_order=$order + order='id' + reverse_order='id_reverse' + path='/admin/configuration/currencies' + label="{intl l='ID'}" + } + - {admin_sortable_header - current_order=$order - order='code' - reverse_order='code_reverse' - path='/admin/configuration/currencies' - label="{intl l="ISO 4217 Code"}" - } - - + {admin_sortable_header + current_order=$order + order='alpha' + reverse_order='alpha_reverse' + path='/admin/configuration/currencies' + label="{intl l='Name'}" + } + - {admin_sortable_header - current_order=$order - order='symbol' - reverse_order='symbol_reverse' - path='/admin/configuration/currencies' - label="{intl l="Symbol"}" - } - + {admin_sortable_header + current_order=$order + order='code' + reverse_order='code_reverse' + path='/admin/configuration/currencies' + label="{intl l="ISO 4217 Code"}" + } + + - {admin_sortable_header - current_order=$order - order='rate' - reverse_order='rate_reverse' - path='/admin/configuration/currencies' - label="{intl l="Rate in €"}" - } - + {admin_sortable_header + current_order=$order + order='symbol' + reverse_order='symbol_reverse' + path='/admin/configuration/currencies' + label="{intl l="Symbol"}" + } + - {admin_sortable_header - current_order=$order - order='manual' - reverse_order='manual_reverse' - path='/admin/configuration/currencies' - label="{intl l="Position"}" - } - + {admin_sortable_header + current_order=$order + order='rate' + reverse_order='rate_reverse' + path='/admin/configuration/currencies' + label="{intl l="Rate in €"}" + } + - {admin_sortable_header - current_order=$order - order='is_default' - reverse_order='is_default_reverse' - path='/admin/configuration/currencies' - label="{intl l="Default"}" - } - + {admin_sortable_header + current_order=$order + order='manual' + reverse_order='manual_reverse' + path='/admin/configuration/currencies' + label="{intl l="Position"}" + } + + {admin_sortable_header + current_order=$order + order='is_default' + reverse_order='is_default_reverse' + path='/admin/configuration/currencies' + label="{intl l="Default"}" + } +  
{$ID}{intl l='Actions'}
{$ID} - {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} - {$NAME} - {/loop} - {elseloop rel="can_change"} - {$NAME} - {/elseloop} - + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} + {$NAME} + {/loop} + {elseloop rel="can_change"} + {$NAME} + {/elseloop} + {$ISOCODE}{$ISOCODE}{$SYMBOL}{$SYMBOL}{format_number number="$RATE" decimals="4"}{format_number number="$RATE" decimals="4"} - {admin_position_block - permission="admin.currencies.edit" - path="/admin/configuration/currencies" - url_parameter="currency_id" - in_place_edit_class="currencyPositionChange" - position="$POSITION" - id="$ID" - } - + {admin_position_block + permission="admin.currencies.edit" + path="/admin/configuration/currencies" + url_parameter="currency_id" + in_place_edit_class="currencyPositionChange" + position="$POSITION" + id="$ID" + } + - - + + -
- {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} - - {/loop} +
+
+ {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.currencies.change"} + + + + {/loop} - {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.currencies.delete"} - - {/loop} -
-
+
+ {intl l="No currency has been created yet. Click the + button to create one."} +
+
- {elseloop rel="currencies"} - - -
- {intl l="No currency has been created yet. Click the + button to create one."} -
- - - {/elseloop} - -
-
+
+ + + +
+
+ + {module_include location='currencies_bottom'} + +
+
+ + + {* Adding a new currency *} + + -
-{* Adding a new currency *} + {* Delete confirmation dialog *} -