diff --git a/core/lib/Thelia/Action/Administrator.php b/core/lib/Thelia/Action/Administrator.php index 2bbfce8a8..15940082a 100644 --- a/core/lib/Thelia/Action/Administrator.php +++ b/core/lib/Thelia/Action/Administrator.php @@ -25,6 +25,7 @@ namespace Thelia\Action; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\Administrator\AdministratorEvent; +use Thelia\Core\Event\Administrator\AdministratorUpdatePasswordEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Model\Admin as AdminModel; use Thelia\Model\AdminQuery; @@ -92,15 +93,23 @@ class Administrator extends BaseAction implements EventSubscriberInterface } } + public function updatePassword(AdministratorUpdatePasswordEvent $event) + { + $admin = $event->getAdmin(); + $admin->setPassword($event->getPassword()) + ->save(); + } + /** * {@inheritDoc} */ public static function getSubscribedEvents() { return array( - TheliaEvents::ADMINISTRATOR_CREATE => array("create", 128), - TheliaEvents::ADMINISTRATOR_UPDATE => array("update", 128), - TheliaEvents::ADMINISTRATOR_DELETE => array("delete", 128), + TheliaEvents::ADMINISTRATOR_CREATE => array('create', 128), + TheliaEvents::ADMINISTRATOR_UPDATE => array('update', 128), + TheliaEvents::ADMINISTRATOR_DELETE => array('delete', 128), + TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD => array('updatePassword', 128) ); } } diff --git a/core/lib/Thelia/Action/BaseAction.php b/core/lib/Thelia/Action/BaseAction.php index 33deddf2b..e1edab07d 100755 --- a/core/lib/Thelia/Action/BaseAction.php +++ b/core/lib/Thelia/Action/BaseAction.php @@ -52,8 +52,10 @@ class BaseAction /** * Changes object position, selecting absolute ou relative change. * - * @param $query the query to retrieve the object to move + * @param ModelCriteria $query * @param UpdatePositionEvent $event + * + * @return mixed */ protected function genericUpdatePosition(ModelCriteria $query, UpdatePositionEvent $event) { @@ -71,18 +73,4 @@ class BaseAction return $object->movePositionDown(); } } - - /** - * Helper to append a message to the admin log. - * - * @param string $message - */ - public function adminLogAppend($message) - { - AdminLog::append( - $message, - $this->container->get('request'), - $this->container->get('thelia.securityContext')->getAdminUser() - ); - } } diff --git a/core/lib/Thelia/Action/Document.php b/core/lib/Thelia/Action/Document.php index f048c208e..e38604733 100644 --- a/core/lib/Thelia/Action/Document.php +++ b/core/lib/Thelia/Action/Document.php @@ -143,18 +143,6 @@ class Document extends BaseCachedFile implements EventSubscriberInterface */ public function saveDocument(DocumentCreateOrUpdateEvent $event) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Saving documents for %parentName% parent id %parentId% (%parentType%)', - array( - '%parentName%' => $event->getParentName(), - '%parentId%' => $event->getParentId(), - '%parentType%' => $event->getDocumentType() - ), - 'document' - ) - ); - $fileManager = new FileManager($this->container); $model = $event->getModelDocument(); @@ -187,18 +175,6 @@ class Document extends BaseCachedFile implements EventSubscriberInterface */ public function updateDocument(DocumentCreateOrUpdateEvent $event) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Updating documents for %parentName% parent id %parentId% (%parentType%)', - array( - '%parentName%' => $event->getParentName(), - '%parentId%' => $event->getParentId(), - '%parentType%' => $event->getDocumentType() - ), - 'image' - ) - ); - if (null !== $event->getUploadedFile()) { $event->getModelDocument()->setTitle($event->getUploadedFile()->getClientOriginalName()); } @@ -231,33 +207,7 @@ class Document extends BaseCachedFile implements EventSubscriberInterface { $fileManager = new FileManager($this->container); - try { - $fileManager->deleteFile($event->getDocumentToDelete(), $event->getDocumentType(), FileManager::FILE_TYPE_DOCUMENTS); - - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Deleting document for %id% with parent id %parentId%', - array( - '%id%' => $event->getDocumentToDelete()->getId(), - '%parentId%' => $event->getDocumentToDelete()->getParentId(), - ), - 'document' - ) - ); - } catch (\Exception $e) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Fail to delete document for %id% with parent id %parentId% (Exception : %e%)', - array( - '%id%' => $event->getDocumentToDelete()->getId(), - '%parentId%' => $event->getDocumentToDelete()->getParentId(), - '%e%' => $e->getMessage() - ), - 'document' - ) - ); - throw $e; - } + $fileManager->deleteFile($event->getDocumentToDelete(), $event->getDocumentType(), FileManager::FILE_TYPE_DOCUMENTS); } public static function getSubscribedEvents() diff --git a/core/lib/Thelia/Action/Image.php b/core/lib/Thelia/Action/Image.php index 97d4bd095..ed7010a09 100755 --- a/core/lib/Thelia/Action/Image.php +++ b/core/lib/Thelia/Action/Image.php @@ -254,18 +254,6 @@ class Image extends BaseCachedFile implements EventSubscriberInterface */ public function saveImage(ImageCreateOrUpdateEvent $event) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Saving images for %parentName% parent id %parentId% (%parentType%)', - array( - '%parentName%' => $event->getParentName(), - '%parentId%' => $event->getParentId(), - '%parentType%' => $event->getImageType() - ), - 'image' - ) - ); - $fileManager = new FileManager($this->container); $model = $event->getModelImage(); @@ -297,18 +285,6 @@ class Image extends BaseCachedFile implements EventSubscriberInterface */ public function updateImage(ImageCreateOrUpdateEvent $event) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Updating images for %parentName% parent id %parentId% (%parentType%)', - array( - '%parentName%' => $event->getParentName(), - '%parentId%' => $event->getParentId(), - '%parentType%' => $event->getImageType() - ), - 'image' - ) - ); - $fileManager = new FileManager($this->container); // Copy and save file if ($event->getUploadedFile()) { @@ -337,33 +313,7 @@ class Image extends BaseCachedFile implements EventSubscriberInterface { $fileManager = new FileManager($this->container); - try { - $fileManager->deleteFile($event->getImageToDelete(), $event->getImageType(), FileManager::FILE_TYPE_IMAGES); - - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Deleting image for %id% with parent id %parentId%', - array( - '%id%' => $event->getImageToDelete()->getId(), - '%parentId%' => $event->getImageToDelete()->getParentId(), - ), - 'image' - ) - ); - } catch (\Exception $e) { - $this->adminLogAppend( - $this->container->get('thelia.translator')->trans( - 'Fail to delete image for %id% with parent id %parentId% (Exception : %e%)', - array( - '%id%' => $event->getImageToDelete()->getId(), - '%parentId%' => $event->getImageToDelete()->getParentId(), - '%e%' => $e->getMessage() - ), - 'image' - ) - ); - throw $e; - } + $fileManager->deleteFile($event->getImageToDelete(), $event->getImageType(), FileManager::FILE_TYPE_IMAGES); } /** diff --git a/core/lib/Thelia/Command/AdminUpdatePasswordCommand.php b/core/lib/Thelia/Command/AdminUpdatePasswordCommand.php new file mode 100644 index 000000000..cab25d13f --- /dev/null +++ b/core/lib/Thelia/Command/AdminUpdatePasswordCommand.php @@ -0,0 +1,102 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Command; + +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Thelia\Core\Event\Administrator\AdministratorUpdatePasswordEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\AdminQuery; +use Thelia\Tools\Password; + + +/** + * command line for updating admin password + * + * php Thelia admin:updatePassword + * + * Class AdminUpdatePasswordCommand + * @package Thelia\Command + * @author Manuel Raynaud + */ +class AdminUpdatePasswordCommand extends ContainerAwareCommand +{ + + /** + * Configures the current command. + */ + protected function configure() + { + $this + ->setName('admin:updatePassword') + ->setDescription('change administrator password') + ->setHelp('The admin:updatePassword command allows you to change the password for a given administrator') + ->addArgument( + 'login', + InputArgument::REQUIRED, + 'Login for administrator you want to change the password' + ) + ->addOption( + 'password', + null, + InputOption::VALUE_REQUIRED, + 'Desired password. If this option is omitted, a random password is generated and shown in this prompt after' + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $login = $input->getArgument('login'); + + + if (null === $admin = AdminQuery::create()->filterByLogin($login)->findOne()) { + throw new \RuntimeException(sprintf('Admin with login %s does not exists', $login)); + } + + + $password = $input->getOption('password') ?: Password::generateRandom(); + + $event = new AdministratorUpdatePasswordEvent($admin); + $event->setPassword($password); + + + $this-> + getContainer() + ->get('event_dispatcher') + ->dispatch(TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD, $event); + + $output->writeln(array( + '', + sprintf('admin %s password updated', $login), + sprintf('new password is : %s', $password), + '' + )); + + } + +} + diff --git a/core/lib/Thelia/Command/BaseModuleGenerate.php b/core/lib/Thelia/Command/BaseModuleGenerate.php index b26db435b..1a27d9e4c 100755 --- a/core/lib/Thelia/Command/BaseModuleGenerate.php +++ b/core/lib/Thelia/Command/BaseModuleGenerate.php @@ -35,13 +35,14 @@ abstract class BaseModuleGenerate extends ContainerAwareCommand protected $moduleDirectory; protected $reservedKeyWords = array( - "thelia" + 'thelia' ); protected $neededDirectories = array( - "Config", - "Model", - "Loop" + 'Config', + 'Model', + 'Loop', + 'AdminModule' ); protected function verifyExistingModule() diff --git a/core/lib/Thelia/Command/CreateAdminUser.php b/core/lib/Thelia/Command/CreateAdminUser.php index 857790141..988122e7a 100644 --- a/core/lib/Thelia/Command/CreateAdminUser.php +++ b/core/lib/Thelia/Command/CreateAdminUser.php @@ -38,9 +38,9 @@ class CreateAdminUser extends ContainerAwareCommand protected function configure() { $this - ->setName("thelia:create-admin") - ->setDescription("Create a new adminsitration user") - ->setHelp("The thelia:create-admin command create a new administration user.") + ->setName("admin:create") + ->setDescription("Create a new administrator user") + ->setHelp("The admin:create command create a new administration user.") ->addOption( 'login_name', null, diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 84e9ef92e..185568516 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -184,6 +184,7 @@ + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 64bf37541..7805f4e05 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -832,6 +832,18 @@ + + + + Thelia\Controller\Admin\AdminLogsController::defaultAction + + + + Thelia\Controller\Admin\AdminLogsController::loadLoggerAjaxAction + + + + diff --git a/core/lib/Thelia/Controller/Admin/AbstractCrudController.php b/core/lib/Thelia/Controller/Admin/AbstractCrudController.php index e38e08a7a..46760eba9 100644 --- a/core/lib/Thelia/Controller/Admin/AbstractCrudController.php +++ b/core/lib/Thelia/Controller/Admin/AbstractCrudController.php @@ -303,7 +303,7 @@ abstract class AbstractCrudController extends BaseAdminController if (null !== $createdObject = $this->getObjectFromEvent($createEvent)) { // Log object creation - $this->adminLogAppend(sprintf("%s %s (ID %s) created", ucfirst($this->objectName), $this->getObjectLabel($createdObject), $this->getObjectId($createdObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::CREATE, sprintf("%s %s (ID %s) created", ucfirst($this->objectName), $this->getObjectLabel($createdObject), $this->getObjectId($createdObject))); } $response = $this->performAdditionalCreateAction($createEvent); @@ -391,7 +391,7 @@ abstract class AbstractCrudController extends BaseAdminController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($changeEvent)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } $response = $this->performAdditionalUpdateAction($changeEvent); @@ -530,7 +530,8 @@ abstract class AbstractCrudController extends BaseAdminController if (null !== $deletedObject = $this->getObjectFromEvent($deleteEvent)) { $this->adminLogAppend( - sprintf("%s %s (ID %s) deleted", ucfirst($this->objectName), $this->getObjectLabel($deletedObject), $this->getObjectId($deletedObject))); + $this->resourceCode, AccessManager::DELETE, + sprintf("%s %s (ID %s) deleted", ucfirst($this->objectName), $this->getObjectLabel($deletedObject), $this->getObjectId($deletedObject))); } $response = $this->performAdditionalDeleteAction($deleteEvent); diff --git a/core/lib/Thelia/Controller/Admin/AddressController.php b/core/lib/Thelia/Controller/Admin/AddressController.php index f934b3279..26f97c9b3 100644 --- a/core/lib/Thelia/Controller/Admin/AddressController.php +++ b/core/lib/Thelia/Controller/Admin/AddressController.php @@ -74,9 +74,9 @@ class AddressController extends AbstractCrudController $this->dispatch(TheliaEvents::ADDRESS_DEFAULT, $addressEvent); - $this->adminLogAppend(sprintf("address %d for customer %d removal", $address_id, $address->getCustomerId())); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("address %d for customer %d set as default address", $address_id, $address->getCustomerId())); } catch (\Exception $e) { - \Thelia\Log\Tlog::getInstance()->error(sprintf("error during address removal with message %s", $e->getMessage())); + \Thelia\Log\Tlog::getInstance()->error(sprintf("error during address setting as default with message %s", $e->getMessage())); } $this->redirectToRoute('admin.customer.update.view', array(), array('customer_id' => $address->getCustomerId())); diff --git a/core/lib/Thelia/Controller/Admin/AdminLogsController.php b/core/lib/Thelia/Controller/Admin/AdminLogsController.php new file mode 100644 index 000000000..1c7b6542f --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/AdminLogsController.php @@ -0,0 +1,72 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +use Thelia\Core\Security\AccessManager; +use Thelia\Model\AdminLogQuery; + +class AdminLogsController extends BaseAdminController +{ + const RESOURCE_CODE = "admin.admin-logs"; + + public function defaultAction() + { + if (null !== $response = $this->checkAuth(self::RESOURCE_CODE, AccessManager::VIEW)) return $response; + + // Render the edition template. + return $this->render('admin-logs'); + } + + public function loadLoggerAjaxAction() + { + $entries = array(); + + foreach( AdminLogQuery::getEntries( + $this->getRequest()->request->get('admins', array()), + $this->getRequest()->request->get('fromDate', null), + $this->getRequest()->request->get('toDate', null), + array_merge($this->getRequest()->request->get('resources', array()), $this->getRequest()->request->get('modules', array())), + null + ) as $entry) { + + $entries[] = array( + "head" => sprintf( + "[%s][%s][%s:%s]", + date('Y-m-d H:i:s', $entry->getCreatedAt()->getTimestamp()), + $entry->getAdminLogin(), + $entry->getResource(), + $entry->getAction() + ), + "data" => $entry->getMessage(), + ); + } + + return $this->render( + 'ajax/logger', + array( + 'entries' => $entries, + ) + ); + } +} diff --git a/core/lib/Thelia/Controller/Admin/AreaController.php b/core/lib/Thelia/Controller/Admin/AreaController.php index 4126ef741..79c549201 100644 --- a/core/lib/Thelia/Controller/Admin/AreaController.php +++ b/core/lib/Thelia/Controller/Admin/AreaController.php @@ -249,7 +249,7 @@ class AreaController extends AbstractCrudController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($event)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified, new country added", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified, new country added", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } // Redirect to the success URL @@ -303,7 +303,7 @@ class AreaController extends AbstractCrudController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($event)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified, country remove", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified, country remove", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } // Redirect to the success URL diff --git a/core/lib/Thelia/Controller/Admin/BaseAdminController.php b/core/lib/Thelia/Controller/Admin/BaseAdminController.php index e4d9550d3..ad8d46ba0 100755 --- a/core/lib/Thelia/Controller/Admin/BaseAdminController.php +++ b/core/lib/Thelia/Controller/Admin/BaseAdminController.php @@ -51,18 +51,20 @@ class BaseAdminController extends BaseController /** * Helper to append a message to the admin log. * + * @param string $resource + * @param string $action * @param string $message */ - public function adminLogAppend($message) + public function adminLogAppend($resource, $action, $message) { - AdminLog::append($message, $this->getRequest(), $this->getSecurityContext()->getAdminUser()); + AdminLog::append($resource, $action, $message, $this->getRequest(), $this->getSecurityContext()->getAdminUser()); } /** * This method process the rendering of view called from an admin page * * @param unknown $template - * @return Response the reponse which contains the rendered view + * @return Response the response which contains the rendered view */ public function processTemplateAction($template) { @@ -131,7 +133,7 @@ class BaseAdminController extends BaseController } // Log the problem - $this->adminLogAppend("User is not granted for resources %s with accesses %s", implode(", ", $resources), implode(", ", $accesses)); + $this->adminLogAppend(implode(",", $resources), implode(",", $accesses), "User is not granted for resources %s with accesses %s", implode(", ", $resources), implode(", ", $accesses)); // Generate the proper response $response = new Response(); diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php index da0ec200a..5cc71ac00 100755 --- a/core/lib/Thelia/Controller/Admin/CouponController.php +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -356,6 +356,7 @@ class CouponController extends BaseAdminController ); $this->adminLogAppend( + AdminResources::COUPON, AccessManager::UPDATE, sprintf( 'Coupon %s (ID %s) conditions updated', $couponEvent->getCouponModel()->getTitle(), @@ -468,6 +469,7 @@ class CouponController extends BaseAdminController ); $this->adminLogAppend( + AdminResources::COUPON, AccessManager::UPDATE, sprintf( 'Coupon %s (ID ) ' . $log, $couponEvent->getTitle(), diff --git a/core/lib/Thelia/Controller/Admin/CustomerController.php b/core/lib/Thelia/Controller/Admin/CustomerController.php index 814008b7a..93a007426 100644 --- a/core/lib/Thelia/Controller/Admin/CustomerController.php +++ b/core/lib/Thelia/Controller/Admin/CustomerController.php @@ -87,7 +87,7 @@ class CustomerController extends BaseAdminController $customerUpdated = $event->getCustomer(); - $this->adminLogAppend(sprintf("Customer with Ref %s (ID %d) modified", $customerUpdated->getRef() , $customerUpdated->getId())); + $this->adminLogAppend(AdminResources::CUSTOMER, AccessManager::UPDATE, sprintf("Customer with Ref %s (ID %d) modified", $customerUpdated->getRef() , $customerUpdated->getId())); if ($this->getRequest()->get("save_mode") == "close") { $this->redirectToRoute("admin.customers"); diff --git a/core/lib/Thelia/Controller/Admin/FileController.php b/core/lib/Thelia/Controller/Admin/FileController.php index 3c2ad0ba9..38b8d74fb 100755 --- a/core/lib/Thelia/Controller/Admin/FileController.php +++ b/core/lib/Thelia/Controller/Admin/FileController.php @@ -130,6 +130,20 @@ class FileController extends BaseAdminController $imageCreateOrUpdateEvent ); + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Saving images for %parentName% parent id %parentId% (%parentType%)', + array( + '%parentName%' => $event->getParentName(), + '%parentId%' => $event->getParentId(), + '%parentType%' => $event->getImageType() + ), + 'image' + ) + ); + return new ResponseRest(array('status' => true, 'message' => '')); } } @@ -194,6 +208,20 @@ class FileController extends BaseAdminController $documentCreateOrUpdateEvent ); + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Saving documents for %parentName% parent id %parentId% (%parentType%)', + array( + '%parentName%' => $event->getParentName(), + '%parentId%' => $event->getParentId(), + '%parentType%' => $event->getDocumentType() + ), + 'document' + ) + ); + return new ResponseRest(array('status' => true, 'message' => '')); } } @@ -368,7 +396,7 @@ class FileController extends BaseAdminController $imageUpdated = $event->getModelImage(); - $this->adminLogAppend(sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId())); + $this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId())); if ($this->getRequest()->get('save_mode') == 'close') { $this->redirectToRoute('admin.images'); @@ -445,7 +473,7 @@ class FileController extends BaseAdminController $documentUpdated = $event->getModelDocument(); - $this->adminLogAppend(sprintf('Document with Ref %s (ID %d) modified', $documentUpdated->getTitle(), $documentUpdated->getId())); + $this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Document with Ref %s (ID %d) modified', $documentUpdated->getTitle(), $documentUpdated->getId())); if ($this->getRequest()->get('save_mode') == 'close') { $this->redirectToRoute('admin.documents'); @@ -509,10 +537,39 @@ class FileController extends BaseAdminController ); // Dispatch Event to the Action - $this->dispatch( - TheliaEvents::IMAGE_DELETE, - $imageDeleteEvent - ); + try { + $this->dispatch( + TheliaEvents::IMAGE_DELETE, + $imageDeleteEvent + ); + + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Deleting image for %id% with parent id %parentId%', + array( + '%id%' => $event->getDocumentToDelete()->getId(), + '%parentId%' => $event->getDocumentToDelete()->getParentId(), + ), + 'image' + ) + ); + } catch (\Exception $e) { + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Fail to delete image for %id% with parent id %parentId% (Exception : %e%)', + array( + '%id%' => $event->getDocumentToDelete()->getId(), + '%parentId%' => $event->getDocumentToDelete()->getParentId(), + '%e%' => $e->getMessage() + ), + 'image' + ) + ); + } $message = $this->getTranslator() ->trans( @@ -552,10 +609,39 @@ class FileController extends BaseAdminController ); // Dispatch Event to the Action - $this->dispatch( - TheliaEvents::DOCUMENT_DELETE, - $documentDeleteEvent - ); + try { + $this->dispatch( + TheliaEvents::DOCUMENT_DELETE, + $documentDeleteEvent + ); + + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Deleting document for %id% with parent id %parentId%', + array( + '%id%' => $event->getDocumentToDelete()->getId(), + '%parentId%' => $event->getDocumentToDelete()->getParentId(), + ), + 'document' + ) + ); + } catch (\Exception $e) { + $this->adminLogAppend( + AdminResources::retrieve($parentType), + AccessManager::UPDATE, + $this->container->get('thelia.translator')->trans( + 'Fail to delete document for %id% with parent id %parentId% (Exception : %e%)', + array( + '%id%' => $event->getDocumentToDelete()->getId(), + '%parentId%' => $event->getDocumentToDelete()->getParentId(), + '%e%' => $e->getMessage() + ), + 'document' + ) + ); + } $message = $this->getTranslator() ->trans( diff --git a/core/lib/Thelia/Controller/Admin/LangController.php b/core/lib/Thelia/Controller/Admin/LangController.php index 8e0ca5d1c..7c9eefad5 100644 --- a/core/lib/Thelia/Controller/Admin/LangController.php +++ b/core/lib/Thelia/Controller/Admin/LangController.php @@ -116,7 +116,7 @@ class LangController extends BaseAdminController } $changedObject = $event->getLang(); - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", 'Lang', $changedObject->getTitle(), $changedObject->getId())); + $this->adminLogAppend(AdminResources::LANGUAGE, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", 'Lang', $changedObject->getTitle(), $changedObject->getId())); $this->redirectToRoute('/admin/configuration/languages'); } catch (\Exception $e) { $error_msg = $e->getMessage(); @@ -153,7 +153,7 @@ class LangController extends BaseAdminController } $changedObject = $event->getLang(); - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", 'Lang', $changedObject->getTitle(), $changedObject->getId())); + $this->adminLogAppend(AdminResources::LANGUAGE, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", 'Lang', $changedObject->getTitle(), $changedObject->getId())); } catch (\Exception $e) { \Thelia\Log\Tlog::getInstance()->error(sprintf("Error on changing default languages with message : %s", $e->getMessage())); @@ -189,7 +189,7 @@ class LangController extends BaseAdminController } $createdObject = $createEvent->getLang(); - $this->adminLogAppend(sprintf("%s %s (ID %s) created", 'Lang', $createdObject->getTitle(), $createdObject->getId())); + $this->adminLogAppend(AdminResources::LANGUAGE, AccessManager::CREATE, sprintf("%s %s (ID %s) created", 'Lang', $createdObject->getTitle(), $createdObject->getId())); $this->redirectToRoute('admin.configuration.languages'); diff --git a/core/lib/Thelia/Controller/Admin/ProductController.php b/core/lib/Thelia/Controller/Admin/ProductController.php index 5540c529b..1279dbff7 100644 --- a/core/lib/Thelia/Controller/Admin/ProductController.php +++ b/core/lib/Thelia/Controller/Admin/ProductController.php @@ -933,7 +933,7 @@ class ProductController extends AbstractCrudController // Log object modification if (null !== $changedObject = $event->getProductSaleElement()) { - $this->adminLogAppend(sprintf("Product Sale Element (ID %s) for product reference %s modified", $changedObject->getId(), $event->getProduct()->getRef())); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("Product Sale Element (ID %s) for product reference %s modified", $changedObject->getId(), $event->getProduct()->getRef())); } } diff --git a/core/lib/Thelia/Controller/Admin/ProfileController.php b/core/lib/Thelia/Controller/Admin/ProfileController.php index 9db4e9315..909d055b8 100644 --- a/core/lib/Thelia/Controller/Admin/ProfileController.php +++ b/core/lib/Thelia/Controller/Admin/ProfileController.php @@ -330,7 +330,7 @@ class ProfileController extends AbstractCrudController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($changeEvent)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } if ($response == null) { @@ -379,7 +379,7 @@ class ProfileController extends AbstractCrudController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($changeEvent)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } if ($response == null) { diff --git a/core/lib/Thelia/Controller/Admin/SessionController.php b/core/lib/Thelia/Controller/Admin/SessionController.php index 6d8d14416..0f6f1a105 100755 --- a/core/lib/Thelia/Controller/Admin/SessionController.php +++ b/core/lib/Thelia/Controller/Admin/SessionController.php @@ -50,7 +50,7 @@ class SessionController extends BaseAdminController $this->getSecurityContext()->setAdminUser($user); - $this->adminLogAppend("Successful token authentication"); + $this->adminLogAppend("admin", "LOGIN", "Successful token authentication"); // Update the cookie $cookie = $this->createAdminRememberMeCookie($user); @@ -58,7 +58,7 @@ class SessionController extends BaseAdminController // Render the home page return $this->render("home"); } catch (TokenAuthenticationException $ex) { - $this->adminLogAppend("Token based authentication failed."); + $this->adminLogAppend("admin", "LOGIN", "Token based authentication failed."); // Clear the cookie $this->clearRememberMeCookie(); @@ -99,7 +99,7 @@ class SessionController extends BaseAdminController $this->getSecurityContext()->setAdminUser($user); // Log authentication success - AdminLog::append("Authentication successful", $request, $user); + AdminLog::append("admin", "LOGIN", "Authentication successful", $request, $user); /** * FIXME: we have tou find a way to send cookie @@ -122,13 +122,13 @@ class SessionController extends BaseAdminController } catch (AuthenticationException $ex) { // Log authentication failure - AdminLog::append(sprintf("Authentication failure for username '%s'", $authenticator->getUsername()), $request); + AdminLog::append("admin", "LOGIN", sprintf("Authentication failure for username '%s'", $authenticator->getUsername()), $request); $message = $this->getTranslator()->trans("Login failed. Please check your username and password."); } catch (\Exception $ex) { // Log authentication failure - AdminLog::append(sprintf("Undefined error: %s", $ex->getMessage()), $request); + AdminLog::append("admin", "LOGIN", sprintf("Undefined error: %s", $ex->getMessage()), $request); $message = $this->getTranslator()->trans( "Unable to process your request. Please try again (%err).", diff --git a/core/lib/Thelia/Controller/Admin/TaxRuleController.php b/core/lib/Thelia/Controller/Admin/TaxRuleController.php index db3eca4b4..2e6cb2b70 100644 --- a/core/lib/Thelia/Controller/Admin/TaxRuleController.php +++ b/core/lib/Thelia/Controller/Admin/TaxRuleController.php @@ -279,7 +279,7 @@ class TaxRuleController extends AbstractCrudController // Log object modification if (null !== $changedObject = $this->getObjectFromEvent($changeEvent)) { - $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); + $this->adminLogAppend($this->resourceCode, AccessManager::UPDATE, sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } if ($response == null) { diff --git a/core/lib/Thelia/Core/Event/Administrator/AdministratorUpdatePasswordEvent.php b/core/lib/Thelia/Core/Event/Administrator/AdministratorUpdatePasswordEvent.php new file mode 100644 index 000000000..f155a9dce --- /dev/null +++ b/core/lib/Thelia/Core/Event/Administrator/AdministratorUpdatePasswordEvent.php @@ -0,0 +1,85 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event\Administrator; +use Thelia\Core\Event\ActionEvent; +use Thelia\Model\Admin; + + +/** + * Class AdministratorUpdatePasswordEvent + * @package Thelia\Core\Event\Administrator + * @author Manuel Raynaud + */ +class AdministratorUpdatePasswordEvent extends ActionEvent +{ + + /** + * @var \Thelia\Model\Admin + */ + protected $admin; + + /** + * @var string new administrator password + */ + protected $password; + + public function __construct(Admin $admin) + { + $this->admin = $admin; + } + + /** + * @param string $password + */ + public function setPassword($password) + { + $this->password = $password; + } + + /** + * @return string + */ + public function getPassword() + { + return $this->password; + } + + /** + * @param \Thelia\Model\Admin $admin + */ + public function setAdmin(Admin $admin) + { + $this->admin = $admin; + } + + /** + * @return \Thelia\Model\Admin + */ + public function getAdmin() + { + return $this->admin; + } + +} + diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index dfd2d27aa..f72668fc3 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -567,6 +567,7 @@ final class TheliaEvents const ADMINISTRATOR_CREATE = "action.createAdministrator"; const ADMINISTRATOR_UPDATE = "action.updateAdministrator"; const ADMINISTRATOR_DELETE = "action.deleteAdministrator"; + const ADMINISTRATOR_UPDATEPASSWORD = 'action.generatePassword'; // -- Mailing System management --------------------------------------------- diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Assetic.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Assetic.php index 93dbb6f86..76d9e1c66 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Assetic.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Assetic.php @@ -43,7 +43,17 @@ class Assetic extends AbstractSmartyPlugin public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat) { - return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat); + try { + return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat); + } catch(\Exception $e) { + $catchException = $this->getNormalizedParam($params, array('catchException')); + if($catchException == "true") { + $repeat = false; + return null; + } else { + throw $e; + } + } } public function blockImages($params, $content, \Smarty_Internal_Template $template, &$repeat) diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Module.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Module.php index 52feae096..1c6ab4fd1 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Module.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Module.php @@ -25,6 +25,7 @@ namespace Thelia\Core\Template\Smarty\Plugins; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; use Thelia\Core\Template\Smarty\AbstractSmartyPlugin; +use Thelia\Model\ModuleQuery; class Module extends AbstractSmartyPlugin { @@ -32,13 +33,27 @@ class Module extends AbstractSmartyPlugin * Process theliaModule template inclusion function * * @param unknown $params - * @param unknown $smarty + * @param \Smarty_Internal_Template $template + * @internal param \Thelia\Core\Template\Smarty\Plugins\unknown $smarty + * * @return string */ - public function theliaModule($params, &$smarty) + public function theliaModule($params, \Smarty_Internal_Template $template) { - // TODO - return ""; + $content = null; + if (array_key_exists('location', $params)) { + $location = $params['location']; + $modules = ModuleQuery::getActivated(); + + foreach ($modules as $module) { + + $file = THELIA_MODULE_DIR . "/". ucfirst($module->getCode()) . "/ModuleAdmin/".$location.".html"; + if(file_exists($file)) { + $content .= file_get_contents($file); + } + } + } + return $template->fetch(sprintf("string:%s", $content)); } /** diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index 68da0af12..92c1377ce 100755 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -70,8 +70,14 @@ class SmartyParser extends Smarty implements ParserInterface $this->error_reporting = E_ALL ^ E_NOTICE; // Si on n'est pas en mode debug, activer le cache, avec une lifetime de 15mn, et en vérifiant que les templates sources n'ont pas été modifiés. - $this->caching = Smarty::CACHING_OFF; - $this->force_compile = true; + + if($debug) { + $this->setCaching(Smarty::CACHING_OFF); + $this->setForceCompile(true); + } else { + $this->setForceCompile(false); + } + // The default HTTP status $this->status = 200; diff --git a/core/lib/Thelia/Model/AdminLog.php b/core/lib/Thelia/Model/AdminLog.php index e5720fb35..018fa00d3 100755 --- a/core/lib/Thelia/Model/AdminLog.php +++ b/core/lib/Thelia/Model/AdminLog.php @@ -7,16 +7,18 @@ use Thelia\Core\HttpFoundation\Request; use Thelia\Log\Tlog; use Thelia\Model\Base\Admin as BaseAdminUser; -class AdminLog extends BaseAdminLog { - - /** - * A sdimple helper to insert an entry in the admin log +class AdminLog extends BaseAdminLog +{ + /** + * A simple helper to insert an entry in the admin log * - * @param unknown $actionLabel - * @param Request $request - * @param Admin $adminUser - */ - public static function append($actionLabel, Request $request, BaseAdminUser $adminUser = null) { + * @param $resource + * @param $action + * @param $message + * @param Request $request + * @param Base\Admin $adminUser + */ + public static function append($resource, $action, $message, Request $request, BaseAdminUser $adminUser = null) { $log = new AdminLog(); @@ -24,7 +26,9 @@ class AdminLog extends BaseAdminLog { ->setAdminLogin($adminUser !== null ? $adminUser->getLogin() : '') ->setAdminFirstname($adminUser !== null ? $adminUser->getFirstname() : '') ->setAdminLastname($adminUser !== null ? $adminUser->getLastname() : '') - ->setAction($actionLabel) + ->setResource($resource) + ->setAction($action) + ->setMessage($message) ->setRequest($request->__toString()) ; diff --git a/core/lib/Thelia/Model/AdminLogQuery.php b/core/lib/Thelia/Model/AdminLogQuery.php index 43a054bbb..7113a4658 100755 --- a/core/lib/Thelia/Model/AdminLogQuery.php +++ b/core/lib/Thelia/Model/AdminLogQuery.php @@ -2,6 +2,7 @@ namespace Thelia\Model; +use Propel\Runtime\ActiveQuery\Criteria; use Thelia\Model\Base\AdminLogQuery as BaseAdminLogQuery; @@ -15,6 +16,43 @@ use Thelia\Model\Base\AdminLogQuery as BaseAdminLogQuery; * long as it does not already exist in the output directory. * */ -class AdminLogQuery extends BaseAdminLogQuery { +class AdminLogQuery extends BaseAdminLogQuery +{ + /** + * @param null $login + * @param null $minDate + * @param null $maxDate + * @param null $resources + * @param null $actions + * + * @return array|mixed|\Propel\Runtime\Collection\ObjectCollection + */ + public static function getEntries($login = null, $minDate = null, $maxDate = null, $resources = null, $actions = null) + { + $search = self::create(); + if(null !== $minDate) { + $search->filterByCreatedAt($minDate, Criteria::GREATER_EQUAL); + } + + if(null !== $maxDate) { + $maxDateObject = new \DateTime($maxDate); + $maxDateObject->add(new \DateInterval('P1D')); + $search->filterByCreatedAt(date('Y-m-d', $maxDateObject->getTimestamp()), Criteria::LESS_THAN); + } + + if(null !== $resources) { + $search->filterByResource($resources); + } + + if(null !== $actions) { + $search->filterByAction($actions); + } + + if(null !== $login) { + $search->filterByAdminLogin($login); + } + + return $search->find(); + } } // AdminLogQuery diff --git a/core/lib/Thelia/Model/Base/AdminLog.php b/core/lib/Thelia/Model/Base/AdminLog.php index dfce950eb..abebb7cd9 100644 --- a/core/lib/Thelia/Model/Base/AdminLog.php +++ b/core/lib/Thelia/Model/Base/AdminLog.php @@ -78,12 +78,24 @@ abstract class AdminLog implements ActiveRecordInterface */ protected $admin_lastname; + /** + * The value for the resource field. + * @var string + */ + protected $resource; + /** * The value for the action field. * @var string */ protected $action; + /** + * The value for the message field. + * @var string + */ + protected $message; + /** * The value for the request field. * @var string @@ -412,6 +424,17 @@ abstract class AdminLog implements ActiveRecordInterface return $this->admin_lastname; } + /** + * Get the [resource] column value. + * + * @return string + */ + public function getResource() + { + + return $this->resource; + } + /** * Get the [action] column value. * @@ -423,6 +446,17 @@ abstract class AdminLog implements ActiveRecordInterface return $this->action; } + /** + * Get the [message] column value. + * + * @return string + */ + public function getMessage() + { + + return $this->message; + } + /** * Get the [request] column value. * @@ -558,6 +592,27 @@ abstract class AdminLog implements ActiveRecordInterface return $this; } // setAdminLastname() + /** + * Set the value of [resource] column. + * + * @param string $v new value + * @return \Thelia\Model\AdminLog The current object (for fluent API support) + */ + public function setResource($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->resource !== $v) { + $this->resource = $v; + $this->modifiedColumns[] = AdminLogTableMap::RESOURCE; + } + + + return $this; + } // setResource() + /** * Set the value of [action] column. * @@ -579,6 +634,27 @@ abstract class AdminLog implements ActiveRecordInterface return $this; } // setAction() + /** + * Set the value of [message] column. + * + * @param string $v new value + * @return \Thelia\Model\AdminLog The current object (for fluent API support) + */ + public function setMessage($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->message !== $v) { + $this->message = $v; + $this->modifiedColumns[] = AdminLogTableMap::MESSAGE; + } + + + return $this; + } // setMessage() + /** * Set the value of [request] column. * @@ -691,19 +767,25 @@ abstract class AdminLog implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : AdminLogTableMap::translateFieldName('AdminLastname', TableMap::TYPE_PHPNAME, $indexType)]; $this->admin_lastname = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : AdminLogTableMap::translateFieldName('Action', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : AdminLogTableMap::translateFieldName('Resource', TableMap::TYPE_PHPNAME, $indexType)]; + $this->resource = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : AdminLogTableMap::translateFieldName('Action', TableMap::TYPE_PHPNAME, $indexType)]; $this->action = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : AdminLogTableMap::translateFieldName('Request', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : AdminLogTableMap::translateFieldName('Message', TableMap::TYPE_PHPNAME, $indexType)]; + $this->message = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : AdminLogTableMap::translateFieldName('Request', TableMap::TYPE_PHPNAME, $indexType)]; $this->request = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : AdminLogTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : AdminLogTableMap::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 ? 7 + $startcol : AdminLogTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : AdminLogTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -716,7 +798,7 @@ abstract class AdminLog implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 8; // 8 = AdminLogTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 10; // 10 = AdminLogTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\AdminLog object", 0, $e); @@ -948,9 +1030,15 @@ abstract class AdminLog implements ActiveRecordInterface if ($this->isColumnModified(AdminLogTableMap::ADMIN_LASTNAME)) { $modifiedColumns[':p' . $index++] = 'ADMIN_LASTNAME'; } + if ($this->isColumnModified(AdminLogTableMap::RESOURCE)) { + $modifiedColumns[':p' . $index++] = 'RESOURCE'; + } if ($this->isColumnModified(AdminLogTableMap::ACTION)) { $modifiedColumns[':p' . $index++] = 'ACTION'; } + if ($this->isColumnModified(AdminLogTableMap::MESSAGE)) { + $modifiedColumns[':p' . $index++] = 'MESSAGE'; + } if ($this->isColumnModified(AdminLogTableMap::REQUEST)) { $modifiedColumns[':p' . $index++] = 'REQUEST'; } @@ -983,9 +1071,15 @@ abstract class AdminLog implements ActiveRecordInterface case 'ADMIN_LASTNAME': $stmt->bindValue($identifier, $this->admin_lastname, PDO::PARAM_STR); break; + case 'RESOURCE': + $stmt->bindValue($identifier, $this->resource, PDO::PARAM_STR); + break; case 'ACTION': $stmt->bindValue($identifier, $this->action, PDO::PARAM_STR); break; + case 'MESSAGE': + $stmt->bindValue($identifier, $this->message, PDO::PARAM_STR); + break; case 'REQUEST': $stmt->bindValue($identifier, $this->request, PDO::PARAM_STR); break; @@ -1070,15 +1164,21 @@ abstract class AdminLog implements ActiveRecordInterface return $this->getAdminLastname(); break; case 4: - return $this->getAction(); + return $this->getResource(); break; case 5: - return $this->getRequest(); + return $this->getAction(); break; case 6: - return $this->getCreatedAt(); + return $this->getMessage(); break; case 7: + return $this->getRequest(); + break; + case 8: + return $this->getCreatedAt(); + break; + case 9: return $this->getUpdatedAt(); break; default: @@ -1113,10 +1213,12 @@ abstract class AdminLog implements ActiveRecordInterface $keys[1] => $this->getAdminLogin(), $keys[2] => $this->getAdminFirstname(), $keys[3] => $this->getAdminLastname(), - $keys[4] => $this->getAction(), - $keys[5] => $this->getRequest(), - $keys[6] => $this->getCreatedAt(), - $keys[7] => $this->getUpdatedAt(), + $keys[4] => $this->getResource(), + $keys[5] => $this->getAction(), + $keys[6] => $this->getMessage(), + $keys[7] => $this->getRequest(), + $keys[8] => $this->getCreatedAt(), + $keys[9] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach ($virtualColumns as $key => $virtualColumn) { @@ -1169,15 +1271,21 @@ abstract class AdminLog implements ActiveRecordInterface $this->setAdminLastname($value); break; case 4: - $this->setAction($value); + $this->setResource($value); break; case 5: - $this->setRequest($value); + $this->setAction($value); break; case 6: - $this->setCreatedAt($value); + $this->setMessage($value); break; case 7: + $this->setRequest($value); + break; + case 8: + $this->setCreatedAt($value); + break; + case 9: $this->setUpdatedAt($value); break; } // switch() @@ -1208,10 +1316,12 @@ abstract class AdminLog implements ActiveRecordInterface if (array_key_exists($keys[1], $arr)) $this->setAdminLogin($arr[$keys[1]]); if (array_key_exists($keys[2], $arr)) $this->setAdminFirstname($arr[$keys[2]]); if (array_key_exists($keys[3], $arr)) $this->setAdminLastname($arr[$keys[3]]); - if (array_key_exists($keys[4], $arr)) $this->setAction($arr[$keys[4]]); - if (array_key_exists($keys[5], $arr)) $this->setRequest($arr[$keys[5]]); - if (array_key_exists($keys[6], $arr)) $this->setCreatedAt($arr[$keys[6]]); - if (array_key_exists($keys[7], $arr)) $this->setUpdatedAt($arr[$keys[7]]); + if (array_key_exists($keys[4], $arr)) $this->setResource($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setAction($arr[$keys[5]]); + if (array_key_exists($keys[6], $arr)) $this->setMessage($arr[$keys[6]]); + if (array_key_exists($keys[7], $arr)) $this->setRequest($arr[$keys[7]]); + if (array_key_exists($keys[8], $arr)) $this->setCreatedAt($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setUpdatedAt($arr[$keys[9]]); } /** @@ -1227,7 +1337,9 @@ abstract class AdminLog implements ActiveRecordInterface if ($this->isColumnModified(AdminLogTableMap::ADMIN_LOGIN)) $criteria->add(AdminLogTableMap::ADMIN_LOGIN, $this->admin_login); if ($this->isColumnModified(AdminLogTableMap::ADMIN_FIRSTNAME)) $criteria->add(AdminLogTableMap::ADMIN_FIRSTNAME, $this->admin_firstname); if ($this->isColumnModified(AdminLogTableMap::ADMIN_LASTNAME)) $criteria->add(AdminLogTableMap::ADMIN_LASTNAME, $this->admin_lastname); + if ($this->isColumnModified(AdminLogTableMap::RESOURCE)) $criteria->add(AdminLogTableMap::RESOURCE, $this->resource); if ($this->isColumnModified(AdminLogTableMap::ACTION)) $criteria->add(AdminLogTableMap::ACTION, $this->action); + if ($this->isColumnModified(AdminLogTableMap::MESSAGE)) $criteria->add(AdminLogTableMap::MESSAGE, $this->message); if ($this->isColumnModified(AdminLogTableMap::REQUEST)) $criteria->add(AdminLogTableMap::REQUEST, $this->request); if ($this->isColumnModified(AdminLogTableMap::CREATED_AT)) $criteria->add(AdminLogTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(AdminLogTableMap::UPDATED_AT)) $criteria->add(AdminLogTableMap::UPDATED_AT, $this->updated_at); @@ -1297,7 +1409,9 @@ abstract class AdminLog implements ActiveRecordInterface $copyObj->setAdminLogin($this->getAdminLogin()); $copyObj->setAdminFirstname($this->getAdminFirstname()); $copyObj->setAdminLastname($this->getAdminLastname()); + $copyObj->setResource($this->getResource()); $copyObj->setAction($this->getAction()); + $copyObj->setMessage($this->getMessage()); $copyObj->setRequest($this->getRequest()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); @@ -1338,7 +1452,9 @@ abstract class AdminLog implements ActiveRecordInterface $this->admin_login = null; $this->admin_firstname = null; $this->admin_lastname = null; + $this->resource = null; $this->action = null; + $this->message = null; $this->request = null; $this->created_at = null; $this->updated_at = null; diff --git a/core/lib/Thelia/Model/Base/AdminLogQuery.php b/core/lib/Thelia/Model/Base/AdminLogQuery.php index 53a5849b5..061b9013d 100644 --- a/core/lib/Thelia/Model/Base/AdminLogQuery.php +++ b/core/lib/Thelia/Model/Base/AdminLogQuery.php @@ -22,7 +22,9 @@ use Thelia\Model\Map\AdminLogTableMap; * @method ChildAdminLogQuery orderByAdminLogin($order = Criteria::ASC) Order by the admin_login column * @method ChildAdminLogQuery orderByAdminFirstname($order = Criteria::ASC) Order by the admin_firstname column * @method ChildAdminLogQuery orderByAdminLastname($order = Criteria::ASC) Order by the admin_lastname column + * @method ChildAdminLogQuery orderByResource($order = Criteria::ASC) Order by the resource column * @method ChildAdminLogQuery orderByAction($order = Criteria::ASC) Order by the action column + * @method ChildAdminLogQuery orderByMessage($order = Criteria::ASC) Order by the message column * @method ChildAdminLogQuery orderByRequest($order = Criteria::ASC) Order by the request column * @method ChildAdminLogQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildAdminLogQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column @@ -31,7 +33,9 @@ use Thelia\Model\Map\AdminLogTableMap; * @method ChildAdminLogQuery groupByAdminLogin() Group by the admin_login column * @method ChildAdminLogQuery groupByAdminFirstname() Group by the admin_firstname column * @method ChildAdminLogQuery groupByAdminLastname() Group by the admin_lastname column + * @method ChildAdminLogQuery groupByResource() Group by the resource column * @method ChildAdminLogQuery groupByAction() Group by the action column + * @method ChildAdminLogQuery groupByMessage() Group by the message column * @method ChildAdminLogQuery groupByRequest() Group by the request column * @method ChildAdminLogQuery groupByCreatedAt() Group by the created_at column * @method ChildAdminLogQuery groupByUpdatedAt() Group by the updated_at column @@ -47,7 +51,9 @@ use Thelia\Model\Map\AdminLogTableMap; * @method ChildAdminLog findOneByAdminLogin(string $admin_login) Return the first ChildAdminLog filtered by the admin_login column * @method ChildAdminLog findOneByAdminFirstname(string $admin_firstname) Return the first ChildAdminLog filtered by the admin_firstname column * @method ChildAdminLog findOneByAdminLastname(string $admin_lastname) Return the first ChildAdminLog filtered by the admin_lastname column + * @method ChildAdminLog findOneByResource(string $resource) Return the first ChildAdminLog filtered by the resource column * @method ChildAdminLog findOneByAction(string $action) Return the first ChildAdminLog filtered by the action column + * @method ChildAdminLog findOneByMessage(string $message) Return the first ChildAdminLog filtered by the message column * @method ChildAdminLog findOneByRequest(string $request) Return the first ChildAdminLog filtered by the request column * @method ChildAdminLog findOneByCreatedAt(string $created_at) Return the first ChildAdminLog filtered by the created_at column * @method ChildAdminLog findOneByUpdatedAt(string $updated_at) Return the first ChildAdminLog filtered by the updated_at column @@ -56,7 +62,9 @@ use Thelia\Model\Map\AdminLogTableMap; * @method array findByAdminLogin(string $admin_login) Return ChildAdminLog objects filtered by the admin_login column * @method array findByAdminFirstname(string $admin_firstname) Return ChildAdminLog objects filtered by the admin_firstname column * @method array findByAdminLastname(string $admin_lastname) Return ChildAdminLog objects filtered by the admin_lastname column + * @method array findByResource(string $resource) Return ChildAdminLog objects filtered by the resource column * @method array findByAction(string $action) Return ChildAdminLog objects filtered by the action column + * @method array findByMessage(string $message) Return ChildAdminLog objects filtered by the message column * @method array findByRequest(string $request) Return ChildAdminLog objects filtered by the request column * @method array findByCreatedAt(string $created_at) Return ChildAdminLog objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildAdminLog objects filtered by the updated_at column @@ -148,7 +156,7 @@ abstract class AdminLogQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, ADMIN_LOGIN, ADMIN_FIRSTNAME, ADMIN_LASTNAME, ACTION, REQUEST, CREATED_AT, UPDATED_AT FROM admin_log WHERE ID = :p0'; + $sql = 'SELECT ID, ADMIN_LOGIN, ADMIN_FIRSTNAME, ADMIN_LASTNAME, RESOURCE, ACTION, MESSAGE, REQUEST, CREATED_AT, UPDATED_AT FROM admin_log WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -365,6 +373,35 @@ abstract class AdminLogQuery extends ModelCriteria return $this->addUsingAlias(AdminLogTableMap::ADMIN_LASTNAME, $adminLastname, $comparison); } + /** + * Filter the query on the resource column + * + * Example usage: + * + * $query->filterByResource('fooValue'); // WHERE resource = 'fooValue' + * $query->filterByResource('%fooValue%'); // WHERE resource LIKE '%fooValue%' + * + * + * @param string $resource 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 ChildAdminLogQuery The current query, for fluid interface + */ + public function filterByResource($resource = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($resource)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $resource)) { + $resource = str_replace('*', '%', $resource); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(AdminLogTableMap::RESOURCE, $resource, $comparison); + } + /** * Filter the query on the action column * @@ -394,6 +431,35 @@ abstract class AdminLogQuery extends ModelCriteria return $this->addUsingAlias(AdminLogTableMap::ACTION, $action, $comparison); } + /** + * Filter the query on the message column + * + * Example usage: + * + * $query->filterByMessage('fooValue'); // WHERE message = 'fooValue' + * $query->filterByMessage('%fooValue%'); // WHERE message LIKE '%fooValue%' + * + * + * @param string $message 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 ChildAdminLogQuery The current query, for fluid interface + */ + public function filterByMessage($message = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($message)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $message)) { + $message = str_replace('*', '%', $message); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(AdminLogTableMap::MESSAGE, $message, $comparison); + } + /** * Filter the query on the request column * diff --git a/core/lib/Thelia/Model/Map/AdminLogTableMap.php b/core/lib/Thelia/Model/Map/AdminLogTableMap.php index 633d6b4e9..fabd848dc 100644 --- a/core/lib/Thelia/Model/Map/AdminLogTableMap.php +++ b/core/lib/Thelia/Model/Map/AdminLogTableMap.php @@ -57,7 +57,7 @@ class AdminLogTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 8; + const NUM_COLUMNS = 10; /** * The number of lazy-loaded columns @@ -67,7 +67,7 @@ class AdminLogTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 8; + const NUM_HYDRATE_COLUMNS = 10; /** * the column name for the ID field @@ -89,11 +89,21 @@ class AdminLogTableMap extends TableMap */ const ADMIN_LASTNAME = 'admin_log.ADMIN_LASTNAME'; + /** + * the column name for the RESOURCE field + */ + const RESOURCE = 'admin_log.RESOURCE'; + /** * the column name for the ACTION field */ const ACTION = 'admin_log.ACTION'; + /** + * the column name for the MESSAGE field + */ + const MESSAGE = 'admin_log.MESSAGE'; + /** * the column name for the REQUEST field */ @@ -121,12 +131,12 @@ class AdminLogTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'AdminLogin', 'AdminFirstname', 'AdminLastname', 'Action', 'Request', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'adminLogin', 'adminFirstname', 'adminLastname', 'action', 'request', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(AdminLogTableMap::ID, AdminLogTableMap::ADMIN_LOGIN, AdminLogTableMap::ADMIN_FIRSTNAME, AdminLogTableMap::ADMIN_LASTNAME, AdminLogTableMap::ACTION, AdminLogTableMap::REQUEST, AdminLogTableMap::CREATED_AT, AdminLogTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'ADMIN_LOGIN', 'ADMIN_FIRSTNAME', 'ADMIN_LASTNAME', 'ACTION', 'REQUEST', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'admin_login', 'admin_firstname', 'admin_lastname', 'action', 'request', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, ) + self::TYPE_PHPNAME => array('Id', 'AdminLogin', 'AdminFirstname', 'AdminLastname', 'Resource', 'Action', 'Message', 'Request', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'adminLogin', 'adminFirstname', 'adminLastname', 'resource', 'action', 'message', 'request', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(AdminLogTableMap::ID, AdminLogTableMap::ADMIN_LOGIN, AdminLogTableMap::ADMIN_FIRSTNAME, AdminLogTableMap::ADMIN_LASTNAME, AdminLogTableMap::RESOURCE, AdminLogTableMap::ACTION, AdminLogTableMap::MESSAGE, AdminLogTableMap::REQUEST, AdminLogTableMap::CREATED_AT, AdminLogTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'ADMIN_LOGIN', 'ADMIN_FIRSTNAME', 'ADMIN_LASTNAME', 'RESOURCE', 'ACTION', 'MESSAGE', 'REQUEST', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'admin_login', 'admin_firstname', 'admin_lastname', 'resource', 'action', 'message', 'request', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ) ); /** @@ -136,12 +146,12 @@ class AdminLogTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'AdminLogin' => 1, 'AdminFirstname' => 2, 'AdminLastname' => 3, 'Action' => 4, 'Request' => 5, 'CreatedAt' => 6, 'UpdatedAt' => 7, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'adminLogin' => 1, 'adminFirstname' => 2, 'adminLastname' => 3, 'action' => 4, 'request' => 5, 'createdAt' => 6, 'updatedAt' => 7, ), - self::TYPE_COLNAME => array(AdminLogTableMap::ID => 0, AdminLogTableMap::ADMIN_LOGIN => 1, AdminLogTableMap::ADMIN_FIRSTNAME => 2, AdminLogTableMap::ADMIN_LASTNAME => 3, AdminLogTableMap::ACTION => 4, AdminLogTableMap::REQUEST => 5, AdminLogTableMap::CREATED_AT => 6, AdminLogTableMap::UPDATED_AT => 7, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'ADMIN_LOGIN' => 1, 'ADMIN_FIRSTNAME' => 2, 'ADMIN_LASTNAME' => 3, 'ACTION' => 4, 'REQUEST' => 5, 'CREATED_AT' => 6, 'UPDATED_AT' => 7, ), - self::TYPE_FIELDNAME => array('id' => 0, 'admin_login' => 1, 'admin_firstname' => 2, 'admin_lastname' => 3, 'action' => 4, 'request' => 5, 'created_at' => 6, 'updated_at' => 7, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, ) + self::TYPE_PHPNAME => array('Id' => 0, 'AdminLogin' => 1, 'AdminFirstname' => 2, 'AdminLastname' => 3, 'Resource' => 4, 'Action' => 5, 'Message' => 6, 'Request' => 7, 'CreatedAt' => 8, 'UpdatedAt' => 9, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'adminLogin' => 1, 'adminFirstname' => 2, 'adminLastname' => 3, 'resource' => 4, 'action' => 5, 'message' => 6, 'request' => 7, 'createdAt' => 8, 'updatedAt' => 9, ), + self::TYPE_COLNAME => array(AdminLogTableMap::ID => 0, AdminLogTableMap::ADMIN_LOGIN => 1, AdminLogTableMap::ADMIN_FIRSTNAME => 2, AdminLogTableMap::ADMIN_LASTNAME => 3, AdminLogTableMap::RESOURCE => 4, AdminLogTableMap::ACTION => 5, AdminLogTableMap::MESSAGE => 6, AdminLogTableMap::REQUEST => 7, AdminLogTableMap::CREATED_AT => 8, AdminLogTableMap::UPDATED_AT => 9, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'ADMIN_LOGIN' => 1, 'ADMIN_FIRSTNAME' => 2, 'ADMIN_LASTNAME' => 3, 'RESOURCE' => 4, 'ACTION' => 5, 'MESSAGE' => 6, 'REQUEST' => 7, 'CREATED_AT' => 8, 'UPDATED_AT' => 9, ), + self::TYPE_FIELDNAME => array('id' => 0, 'admin_login' => 1, 'admin_firstname' => 2, 'admin_lastname' => 3, 'resource' => 4, 'action' => 5, 'message' => 6, 'request' => 7, 'created_at' => 8, 'updated_at' => 9, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ) ); /** @@ -164,8 +174,10 @@ class AdminLogTableMap extends TableMap $this->addColumn('ADMIN_LOGIN', 'AdminLogin', 'VARCHAR', false, 255, null); $this->addColumn('ADMIN_FIRSTNAME', 'AdminFirstname', 'VARCHAR', false, 255, null); $this->addColumn('ADMIN_LASTNAME', 'AdminLastname', 'VARCHAR', false, 255, null); + $this->addColumn('RESOURCE', 'Resource', 'VARCHAR', false, 255, null); $this->addColumn('ACTION', 'Action', 'VARCHAR', false, 255, null); - $this->addColumn('REQUEST', 'Request', 'LONGVARCHAR', false, null, null); + $this->addColumn('MESSAGE', 'Message', 'LONGVARCHAR', false, null, null); + $this->addColumn('REQUEST', 'Request', 'CLOB', false, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -332,7 +344,9 @@ class AdminLogTableMap extends TableMap $criteria->addSelectColumn(AdminLogTableMap::ADMIN_LOGIN); $criteria->addSelectColumn(AdminLogTableMap::ADMIN_FIRSTNAME); $criteria->addSelectColumn(AdminLogTableMap::ADMIN_LASTNAME); + $criteria->addSelectColumn(AdminLogTableMap::RESOURCE); $criteria->addSelectColumn(AdminLogTableMap::ACTION); + $criteria->addSelectColumn(AdminLogTableMap::MESSAGE); $criteria->addSelectColumn(AdminLogTableMap::REQUEST); $criteria->addSelectColumn(AdminLogTableMap::CREATED_AT); $criteria->addSelectColumn(AdminLogTableMap::UPDATED_AT); @@ -341,7 +355,9 @@ class AdminLogTableMap extends TableMap $criteria->addSelectColumn($alias . '.ADMIN_LOGIN'); $criteria->addSelectColumn($alias . '.ADMIN_FIRSTNAME'); $criteria->addSelectColumn($alias . '.ADMIN_LASTNAME'); + $criteria->addSelectColumn($alias . '.RESOURCE'); $criteria->addSelectColumn($alias . '.ACTION'); + $criteria->addSelectColumn($alias . '.MESSAGE'); $criteria->addSelectColumn($alias . '.REQUEST'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); diff --git a/core/lib/Thelia/Model/Module.php b/core/lib/Thelia/Model/Module.php index b7fb2a443..c9ccd5f8d 100755 --- a/core/lib/Thelia/Model/Module.php +++ b/core/lib/Thelia/Model/Module.php @@ -2,8 +2,13 @@ namespace Thelia\Model; +use Propel\Runtime\Connection\ConnectionInterface; use Thelia\Model\Base\Module as BaseModule; class Module extends BaseModule { + public function postSave(ConnectionInterface $con = null) + { + ModuleQuery::resetActivated(); + } } diff --git a/core/lib/Thelia/Model/ModuleQuery.php b/core/lib/Thelia/Model/ModuleQuery.php index fdfe502a4..aaf2092e6 100755 --- a/core/lib/Thelia/Model/ModuleQuery.php +++ b/core/lib/Thelia/Model/ModuleQuery.php @@ -16,13 +16,26 @@ use Thelia\Model\Base\ModuleQuery as BaseModuleQuery; * */ class ModuleQuery extends BaseModuleQuery { + + protected static $activated = null; /** * @return array|mixed|\PropelObjectCollection */ public static function getActivated() { - return self::create() - ->filterByActivate(1) - ->find(); + if(null === self::$activated) { + self::$activated = self::create() + ->filterByActivate(1) + ->find(); + } + + return self::$activated; } + + public static function resetActivated() + { + self::$activated = null; + } + + } // ModuleQuery diff --git a/core/lib/Thelia/Tools/FileManager.php b/core/lib/Thelia/Tools/FileManager.php index a795bcd5e..b4173645e 100644 --- a/core/lib/Thelia/Tools/FileManager.php +++ b/core/lib/Thelia/Tools/FileManager.php @@ -118,20 +118,6 @@ class FileManager $directory = $this->getUploadDir($parentType, $fileType); $fileName = $this->renameFile($model->getId(), $uploadedFile); - $this->adminLogAppend( - $this->translator->trans( - 'Uploading %type% %fileName% to %directory% for parent_id %parentId% (%parentType%)', - array( - '%type%' => $fileType, - '%fileName%' => $uploadedFile->getClientOriginalName(), - '%directory%' => $directory . '/' . $fileName, - '%parentId%' => $parentId, - '%parentType%' => $parentType - ), - 'image' - ) - ); - $newUploadedFile = $uploadedFile->move($directory, $fileName); $model->setFile($fileName); @@ -282,20 +268,6 @@ class FileManager return strtolower(preg_replace('/[^a-zA-Z0-9-_\.]/', '', $string)); } - /** - * Helper to append a message to the admin log. - * - * @param string $message - */ - public function adminLogAppend($message) - { - AdminLog::append( - $message, - $this->container->get('request'), - $this->container->get('thelia.securityContext')->getAdminUser() - ); - } - /** * Delete image from file storage and database * diff --git a/install/thelia.sql b/install/thelia.sql index 79163345b..b213c114f 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -984,6 +984,7 @@ CREATE TABLE `admin` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`), + UNIQUE INDEX `login_UNIQUE` (`login`), INDEX `idx_admin_profile_id` (`profile_id`), CONSTRAINT `fk_admin_profile_id` FOREIGN KEY (`profile_id`) @@ -1138,8 +1139,10 @@ CREATE TABLE `admin_log` `admin_login` VARCHAR(255), `admin_firstname` VARCHAR(255), `admin_lastname` VARCHAR(255), + `resource` VARCHAR(255), `action` VARCHAR(255), - `request` TEXT, + `message` TEXT, + `request` LONGTEXT, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) diff --git a/local/config/schema.xml b/local/config/schema.xml index ba19efee0..cc9c4c396 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -1,1259 +1,1264 @@ - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - -
-
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
diff --git a/local/modules/Cheque/Config/config.xml b/local/modules/Cheque/Config/config.xml index 2430f5027..cac3f6b7b 100755 --- a/local/modules/Cheque/Config/config.xml +++ b/local/modules/Cheque/Config/config.xml @@ -1,4 +1,4 @@ - +string + +
+ + + + {module_include location='admin_logs_top'} + +
+
+
+ +
{intl l="Administration logs"}
+ +
+
+ +
+
+ +
+
+ {intl l='Period'} : +
+ +
+
+
+ {intl l='From'} + + + + +
+
+
+
+ {intl l='To'} + + + + +
+
+
+
+ +
+
+ {intl l='Administrators'} : +
+ +
+ {loop type="admin" name="admin-list" backend_context="1"} + {if ($LOOP_COUNT-1)%4 == 0 AND $LOOP_COUNT != 0 AND $LOOP_COUNT != $LOOP_TOTAL} +
+
+ {/if} +
+ + +
+ {/loop} +
+
+ +
+
+ {intl l='Resources'} : +
+ +
+ {loop type="resource" name="resources-list" backend_context="1"} + {if ($LOOP_COUNT-1)%4 == 0 AND $LOOP_COUNT != 0 AND $LOOP_COUNT != $LOOP_TOTAL} +
+
+ {/if} +
+ + +
+ {/loop} +
+ +
+ +
+
+ {intl l='Modules'} : +
+ +
+ {loop type="module" name="modules-list" backend_context="1"} + {if ($LOOP_COUNT-1)%4 == 0 AND $LOOP_COUNT != 0 AND $LOOP_COUNT != $LOOP_TOTAL} +
+
+ {/if} +
+ + +
+ {/loop} +
+ +
+ +
+
+ +
+
+ +
+ +
+ +
+
+
+ + {module_include location='admin_logs_bottom'} + +
+ +{/block} + +{block name="javascript-initialization"} + {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} + + {/javascripts} + + {javascripts file='assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.js'} + + {/javascripts} + + {stylesheets file='assets/js/jquery.ui/jquery.ui.theme.css'} + + {/stylesheets} + {stylesheets file='assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.css'} + + {/stylesheets} + + {javascripts file="assets/js/jquery/jquery.ui.ui.datepicker/i18n/jquery.ui.datepicker-{lang attr="locale"}.js" catchException="true"} + + {/javascripts} + + + + +{/block} \ No newline at end of file diff --git a/templates/admin/default/administrators.html b/templates/admin/default/administrators.html index 9cb4a792a..c2b8fa521 100644 --- a/templates/admin/default/administrators.html +++ b/templates/admin/default/administrators.html @@ -62,13 +62,20 @@
- {loop type="auth" name="can_change" role="ADMIN" resource="admin.configuration.administrator" access="UPDATE"} + {* if admin is current admin : + - can UPDATE anyway + - cannot delete himself + *} + {if $ID == {admin attr="id"}} - {/loop} - - {loop type="auth" name="can_delete" role="ADMIN" resource="admin.configuration.administrator" access="DELETE"} - - {/loop} + {else} + {loop type="auth" name="can_change" role="ADMIN" resource="admin.configuration.administrator" access="UPDATE"} + + {/loop} + {loop type="auth" name="can_delete" role="ADMIN" resource="admin.configuration.administrator" access="DELETE"} + + {/loop} + {/if}
diff --git a/templates/admin/default/ajax/logger.html b/templates/admin/default/ajax/logger.html new file mode 100644 index 000000000..4da624897 --- /dev/null +++ b/templates/admin/default/ajax/logger.html @@ -0,0 +1,13 @@ +
+
    + {foreach $entries as $entry} +
  • + {$entry.head} + : + {$entry.data} +
  • + {foreachelse} +
  • NO ENTRIES FOUND
  • + {/foreach} +
+
\ No newline at end of file diff --git a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js deleted file mode 100755 index 97a3d67ed..000000000 --- a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js +++ /dev/null @@ -1,474 +0,0 @@ -///* ========================================================= -// * bootstrap-datepicker.js -// * http://www.eyecon.ro/bootstrap-datepicker -// * ========================================================= -// * Copyright 2012 Stefan Petre -// * -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// * ========================================================= */ -// -//!function( $ ) { -// -// // Picker object -// -// var Datepicker = function(element, options){ -// this.element = $(element); -// this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); -// this.picker = $(DPGlobal.template) -// .appendTo('body') -// .on({ -// click: $.proxy(this.click, this)//, -// //mousedown: $.proxy(this.mousedown, this) -// }); -// this.isInput = this.element.is('input'); -// this.component = this.element.is('.date') ? this.element.find('.add-on') : false; -// -// if (this.isInput) { -// this.element.on({ -// focus: $.proxy(this.show, this), -// //blur: $.proxy(this.hide, this), -// keyup: $.proxy(this.update, this) -// }); -// } else { -// if (this.component){ -// this.component.on('click', $.proxy(this.show, this)); -// } else { -// this.element.on('click', $.proxy(this.show, this)); -// } -// } -// -// this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; -// if (typeof this.minViewMode === 'string') { -// switch (this.minViewMode) { -// case 'months': -// this.minViewMode = 1; -// break; -// case 'years': -// this.minViewMode = 2; -// break; -// default: -// this.minViewMode = 0; -// break; -// } -// } -// this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; -// if (typeof this.viewMode === 'string') { -// switch (this.viewMode) { -// case 'months': -// this.viewMode = 1; -// break; -// case 'years': -// this.viewMode = 2; -// break; -// default: -// this.viewMode = 0; -// break; -// } -// } -// this.startViewMode = this.viewMode; -// this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; -// this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; -// this.onRender = options.onRender; -// this.fillDow(); -// this.fillMonths(); -// this.update(); -// this.showMode(); -// }; -// -// Datepicker.prototype = { -// constructor: Datepicker, -// -// show: function(e) { -// this.picker.show(); -// this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); -// this.place(); -// $(window).on('resize', $.proxy(this.place, this)); -// if (e ) { -// e.stopPropagation(); -// e.preventDefault(); -// } -// if (!this.isInput) { -// } -// var that = this; -// $(document).on('mousedown', function(ev){ -// if ($(ev.target).closest('.datepicker').length == 0) { -// that.hide(); -// } -// }); -// this.element.trigger({ -// type: 'show', -// date: this.date -// }); -// }, -// -// hide: function(){ -// this.picker.hide(); -// $(window).off('resize', this.place); -// this.viewMode = this.startViewMode; -// this.showMode(); -// if (!this.isInput) { -// $(document).off('mousedown', this.hide); -// } -// //this.set(); -// this.element.trigger({ -// type: 'hide', -// date: this.date -// }); -// }, -// -// set: function() { -// var formated = DPGlobal.formatDate(this.date, this.format); -// if (!this.isInput) { -// if (this.component){ -// this.element.find('input').prop('value', formated); -// } -// this.element.data('date', formated); -// } else { -// this.element.prop('value', formated); -// } -// }, -// -// setValue: function(newDate) { -// if (typeof newDate === 'string') { -// this.date = DPGlobal.parseDate(newDate, this.format); -// } else { -// this.date = new Date(newDate); -// } -// this.set(); -// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); -// this.fill(); -// }, -// -// place: function(){ -// var offset = this.component ? this.component.offset() : this.element.offset(); -// this.picker.css({ -// top: offset.top + this.height, -// left: offset.left -// }); -// }, -// -// update: function(newDate){ -// this.date = DPGlobal.parseDate( -// typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), -// this.format -// ); -// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); -// this.fill(); -// }, -// -// fillDow: function(){ -// var dowCnt = this.weekStart; -// var html = ''; -// while (dowCnt < this.weekStart + 7) { -// html += ''+DPGlobal.dates.daysMin[(dowCnt++)%7]+''; -// } -// html += ''; -// this.picker.find('.datepicker-days thead').append(html); -// }, -// -// fillMonths: function(){ -// var html = ''; -// var i = 0 -// while (i < 12) { -// html += ''+DPGlobal.dates.monthsShort[i++]+''; -// } -// this.picker.find('.datepicker-months td').append(html); -// }, -// -// fill: function() { -// var d = new Date(this.viewDate), -// year = d.getFullYear(), -// month = d.getMonth(), -// currentDate = this.date.valueOf(); -// this.picker.find('.datepicker-days th:eq(1)') -// .text(DPGlobal.dates.months[month]+' '+year); -// var prevMonth = new Date(year, month-1, 28,0,0,0,0), -// day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); -// prevMonth.setDate(day); -// prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); -// var nextMonth = new Date(prevMonth); -// nextMonth.setDate(nextMonth.getDate() + 42); -// nextMonth = nextMonth.valueOf(); -// var html = []; -// var clsName, -// prevY, -// prevM; -// while(prevMonth.valueOf() < nextMonth) { -// if (prevMonth.getDay() === this.weekStart) { -// html.push(''); -// } -// clsName = this.onRender(prevMonth); -// prevY = prevMonth.getFullYear(); -// prevM = prevMonth.getMonth(); -// if ((prevM < month && prevY === year) || prevY < year) { -// clsName += ' old'; -// } else if ((prevM > month && prevY === year) || prevY > year) { -// clsName += ' new'; -// } -// if (prevMonth.valueOf() === currentDate) { -// clsName += ' active'; -// } -// html.push(''+prevMonth.getDate() + ''); -// if (prevMonth.getDay() === this.weekEnd) { -// html.push(''); -// } -// prevMonth.setDate(prevMonth.getDate()+1); -// } -// this.picker.find('.datepicker-days tbody').empty().append(html.join('')); -// var currentYear = this.date.getFullYear(); -// -// var months = this.picker.find('.datepicker-months') -// .find('th:eq(1)') -// .text(year) -// .end() -// .find('span').removeClass('active'); -// if (currentYear === year) { -// months.eq(this.date.getMonth()).addClass('active'); -// } -// -// 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); -// }, -// -// click: function(e) { -// e.stopPropagation(); -// 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 'switch': -// this.showMode(1); -// break; -// case 'prev': -// case 'next': -// this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( -// this.viewDate, -// this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + -// DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) -// ); -// this.fill(); -// this.set(); -// break; -// } -// break; -// case 'span': -// if (target.is('.month')) { -// var month = target.parent().find('span').index(target); -// this.viewDate.setMonth(month); -// } else { -// var year = parseInt(target.text(), 10)||0; -// this.viewDate.setFullYear(year); -// } -// if (this.viewMode !== 0) { -// this.date = new Date(this.viewDate); -// this.element.trigger({ -// type: 'changeDate', -// date: this.date, -// viewMode: DPGlobal.modes[this.viewMode].clsName -// }); -// } -// this.showMode(-1); -// this.fill(); -// this.set(); -// break; -// case 'td': -// if (target.is('.day') && !target.is('.disabled')){ -// var day = parseInt(target.text(), 10)||1; -// var month = this.viewDate.getMonth(); -// if (target.is('.old')) { -// month -= 1; -// } else if (target.is('.new')) { -// month += 1; -// } -// var year = this.viewDate.getFullYear(); -// this.date = new Date(year, month, day,0,0,0,0); -// this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); -// this.fill(); -// this.set(); -// this.element.trigger({ -// type: 'changeDate', -// date: this.date, -// viewMode: DPGlobal.modes[this.viewMode].clsName -// }); -// } -// break; -// } -// } -// }, -// -// mousedown: function(e){ -// e.stopPropagation(); -// e.preventDefault(); -// }, -// -// showMode: function(dir) { -// if (dir) { -// this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); -// } -// this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); -// } -// }; -// -// $.fn.datepicker = function ( option, val ) { -// return this.each(function () { -// var $this = $(this), -// data = $this.data('datepicker'), -// options = typeof option === 'object' && option; -// if (!data) { -// $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); -// } -// if (typeof option === 'string') data[option](val); -// }); -// }; -// -// $.fn.datepicker.defaults = { -// onRender: function(date) { -// return ''; -// } -// }; -// $.fn.datepicker.Constructor = Datepicker; -// -// var DPGlobal = { -// modes: [ -// { -// clsName: 'days', -// navFnc: 'Month', -// navStep: 1 -// }, -// { -// clsName: 'months', -// navFnc: 'FullYear', -// navStep: 1 -// }, -// { -// clsName: 'years', -// navFnc: 'FullYear', -// navStep: 10 -// }], -// dates:{ -// 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"] -// }, -// 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] -// }, -// parseFormat: function(format){ -// var separator = format.match(/[.\/\-\s].*?/), -// parts = format.split(/\W+/); -// if (!separator || !parts || parts.length === 0){ -// throw new Error("Invalid date format."); -// } -// return {separator: separator, parts: parts}; -// }, -// parseDate: function(date, format) { -// var parts = date.split(format.separator), -// date = new Date(), -// val; -// date.setHours(0); -// date.setMinutes(0); -// date.setSeconds(0); -// date.setMilliseconds(0); -// if (parts.length === format.parts.length) { -// var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); -// for (var i=0, cnt = format.parts.length; i < cnt; i++) { -// val = parseInt(parts[i], 10)||1; -// switch(format.parts[i]) { -// case 'dd': -// case 'd': -// day = val; -// date.setDate(val); -// break; -// case 'mm': -// case 'm': -// month = val - 1; -// date.setMonth(val - 1); -// break; -// case 'yy': -// year = 2000 + val; -// date.setFullYear(2000 + val); -// break; -// case 'yyyy': -// year = val; -// date.setFullYear(val); -// break; -// } -// } -// date = new Date(year, month, day, 0 ,0 ,0); -// } -// return date; -// }, -// formatDate: function(date, format){ -// var val = { -// d: date.getDate(), -// m: date.getMonth() + 1, -// yy: date.getFullYear().toString().substring(2), -// yyyy: date.getFullYear() -// }; -// val.dd = (val.d < 10 ? '0' : '') + val.d; -// val.mm = (val.m < 10 ? '0' : '') + val.m; -// var date = []; -// for (var i=0, cnt = format.parts.length; i < cnt; i++) { -// date.push(val[format.parts[i]]); -// } -// return date.join(format.separator); -// }, -// headTemplate: ''+ -// ''+ -// '‹'+ -// ''+ -// '›'+ -// ''+ -// '', -// contTemplate: '' -// }; -// DPGlobal.template = ''; -// -//}( window.jQuery ); \ No newline at end of file diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-es_ES.js b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-es_ES.js new file mode 100644 index 000000000..00e1a72b5 --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-es_ES.js @@ -0,0 +1,23 @@ +/* Inicialización en español para la extensión 'UI date picker' para jQuery. */ +/* Traducido por Vester (xvester@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['es_ES'] = { + closeText: 'Cerrar', + prevText: '<Ant', + nextText: 'Sig>', + currentText: 'Hoy', + monthNames: ['enero','febrero','marzo','abril','mayo','junio', + 'julio','agosto','septiembre','octubre','noviembre','diciembre'], + monthNamesShort: ['ene','feb','mar','abr','may','jun', + 'jul','ogo','sep','oct','nov','dic'], + dayNames: ['domingo','lunes','martes','miércoles','jueves','viernes','sábado'], + dayNamesShort: ['dom','lun','mar','mié','juv','vie','sáb'], + dayNamesMin: ['D','L','M','X','J','V','S'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['es_ES']); +}); diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-fr_FR.js b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-fr_FR.js new file mode 100644 index 000000000..ae93d304f --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-fr_FR.js @@ -0,0 +1,25 @@ +/* French initialisation for the jQuery UI date picker plugin. */ +/* Written by Keith Wood (kbwood{at}iinet.com.au), + Stéphane Nahmani (sholby@sholby.net), + Stéphane Raimbault */ +jQuery(function($){ + $.datepicker.regional['fr_FR'] = { + closeText: 'Fermer', + prevText: 'Précédent', + nextText: 'Suivant', + currentText: 'Aujourd\'hui', + monthNames: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', + 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'], + monthNamesShort: ['janv.', 'févr.', 'mars', 'avril', 'mai', 'juin', + 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'], + dayNames: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'], + dayNamesShort: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'], + dayNamesMin: ['D','L','M','M','J','V','S'], + weekHeader: 'Sem.', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['fr_FR']); +}); diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-it_IT.js.js b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-it_IT.js.js new file mode 100644 index 000000000..98698ae5e --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/jquery.ui.datepicker-it_IT.js.js @@ -0,0 +1,23 @@ +/* Italian initialisation for the jQuery UI date picker plugin. */ +/* Written by Antonello Pasella (antonello.pasella@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['it_IT'] = { + closeText: 'Chiudi', + prevText: '<Prec', + nextText: 'Succ>', + currentText: 'Oggi', + monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', + 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], + monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', + 'Lug','Ago','Set','Ott','Nov','Dic'], + dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], + dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], + dayNamesMin: ['Do','Lu','Ma','Me','Gi','Ve','Sa'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['it_IT']); +}); diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/readme.txt b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/readme.txt new file mode 100644 index 000000000..fb2e09c20 --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/i18n/readme.txt @@ -0,0 +1,5 @@ +JQuery UI datepicker localization files were found here : https://github.com/jquery/jquery-ui/tree/master/ui/i18n + +Warning : You must change file name an localization array key declaration in file to match thelia lang locale. + +Exemple : change fr with fr_FR \ No newline at end of file diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.css b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.css new file mode 100644 index 000000000..9538bce8f --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.css @@ -0,0 +1,175 @@ +/*! + * jQuery UI Datepicker @VERSION + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/datepicker/#theming + */ +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.js b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.js new file mode 100644 index 000000000..e4961a1df --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.datepicker/jquery.ui.datepicker.js @@ -0,0 +1,2059 @@ +/*! + * jQuery UI Datepicker @VERSION + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/datepicker/ + * + * Depends: + * jquery.ui.core.js + */ +(function( $, undefined ) { + +$.extend($.ui, { datepicker: { version: "@VERSION" } }); + +var datepicker_instActive; + +function datepicker_getZindex( elem ) { + var position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + //
+ value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + + return 0; +} +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division + this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class + this._appendClass = "ui-datepicker-append"; // The name of the append marker class + this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class + this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class + this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class + this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class + this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class + this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[""] = { // Default regional settings + closeText: "Done", // Display text for close link + prevText: "Prev", // Display text for previous month link + nextText: "Next", // Display text for next month link + currentText: "Today", // Display text for current month link + monthNames: ["January","February","March","April","May","June", + "July","August","September","October","November","December"], // Names of months for drop-down and formatting + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting + dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday + weekHeader: "Wk", // Column header for week of the year + dateFormat: "mm/dd/yy", // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false, // True if right-to-left language, false if left-to-right + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearSuffix: "" // Additional text to append to the year in the month headers + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: "focus", // "focus" for popup on focus, + // "button" for trigger button, or "both" for either + showAnim: "fadeIn", // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: "", // Display text following the input box, e.g. showing the format + buttonText: "...", // Text for trigger button + buttonImage: "", // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + yearRange: "c-10:c+10", // Range of years to display in drop-down, + // either relative to today's year (-nn:+nn), relative to currently displayed year + // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) + showOtherMonths: false, // True to show dates in other months, false to leave blank + selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable + showWeek: false, // True to show week of the year, false to not show it + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: "+10", // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with "+" for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: "fast", // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: "", // Selector for an alternate field to store selected dates into + altFormat: "", // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false, // True to show button panel, false to not show it + autoSize: false, // True to size the input for the date format, false to leave as is + disabled: false // The initial disabled state + }; + $.extend(this._defaults, this.regional[""]); + this.dpDiv = datepicker_bindHover($("
")); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: "hasDatepicker", + + //Keep track of the maximum number of rows displayed (see #7043) + maxRows: 4, + + // TODO rename to "widget" when switching to widget factory + _widgetDatepicker: function() { + return this.dpDiv; + }, + + /* Override the default settings for all instances of the date picker. + * @param settings object - the new settings to use as defaults (anonymous object) + * @return the manager object + */ + setDefaults: function(settings) { + datepicker_extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + * @param target element - the target input field or division or span + * @param settings object - the new settings to use for this date picker instance (anonymous) + */ + _attachDatepicker: function(target, settings) { + var nodeName, inline, inst; + nodeName = target.nodeName.toLowerCase(); + inline = (nodeName === "div" || nodeName === "span"); + if (!target.id) { + this.uuid += 1; + target.id = "dp" + this.uuid; + } + inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}); + if (nodeName === "input") { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + datepicker_bindHover($("
")))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.append = $([]); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) { + return; + } + this._attachments(input, inst); + input.addClass(this.markerClassName).keydown(this._doKeyDown). + keypress(this._doKeyPress).keyup(this._doKeyUp); + this._autoSize(inst); + $.data(target, "datepicker", inst); + //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + }, + + /* Make attachments based on settings. */ + _attachments: function(input, inst) { + var showOn, buttonText, buttonImage, + appendText = this._get(inst, "appendText"), + isRTL = this._get(inst, "isRTL"); + + if (inst.append) { + inst.append.remove(); + } + if (appendText) { + inst.append = $("" + appendText + ""); + input[isRTL ? "before" : "after"](inst.append); + } + + input.unbind("focus", this._showDatepicker); + + if (inst.trigger) { + inst.trigger.remove(); + } + + showOn = this._get(inst, "showOn"); + if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + } + if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked + buttonText = this._get(inst, "buttonText"); + buttonImage = this._get(inst, "buttonImage"); + inst.trigger = $(this._get(inst, "buttonImageOnly") ? + $("").addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $("").addClass(this._triggerClass). + html(!buttonImage ? buttonText : $("").attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? "before" : "after"](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { + $.datepicker._hideDatepicker(); + } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { + $.datepicker._hideDatepicker(); + $.datepicker._showDatepicker(input[0]); + } else { + $.datepicker._showDatepicker(input[0]); + } + return false; + }); + } + }, + + /* Apply the maximum length for the date format. */ + _autoSize: function(inst) { + if (this._get(inst, "autoSize") && !inst.inline) { + var findMax, max, maxI, i, + date = new Date(2009, 12 - 1, 20), // Ensure double digits + dateFormat = this._get(inst, "dateFormat"); + + if (dateFormat.match(/[DM]/)) { + findMax = function(names) { + max = 0; + maxI = 0; + for (i = 0; i < names.length; i++) { + if (names[i].length > max) { + max = names[i].length; + maxI = i; + } + } + return maxI; + }; + date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? + "monthNames" : "monthNamesShort")))); + date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? + "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); + } + inst.input.attr("size", this._formatDate(inst, date).length); + } + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) { + return; + } + divSpan.addClass(this.markerClassName).append(inst.dpDiv); + $.data(target, "datepicker", inst); + this._setDate(inst, this._getDefaultDate(inst), true); + this._updateDatepicker(inst); + this._updateAlternate(inst); + //If disabled option is true, disable the datepicker before showing it (see ticket #5665) + if( inst.settings.disabled ) { + this._disableDatepicker( target ); + } + // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements + // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height + inst.dpDiv.css( "display", "block" ); + }, + + /* Pop-up the date picker in a "dialog" box. + * @param input element - ignored + * @param date string or Date - the initial date to display + * @param onSelect function - the function to call when a date is selected + * @param settings object - update the dialog date picker instance's settings (anonymous object) + * @param pos int[2] - coordinates for the dialog's position within the screen or + * event - with x/y coordinates or + * leave empty for default (screen centre) + * @return the manager object + */ + _dialogDatepicker: function(input, date, onSelect, settings, pos) { + var id, browserWidth, browserHeight, scrollX, scrollY, + inst = this._dialogInst; // internal instance + + if (!inst) { + this.uuid += 1; + id = "dp" + this.uuid; + this._dialogInput = $(""); + this._dialogInput.keydown(this._doKeyDown); + $("body").append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], "datepicker", inst); + } + datepicker_extendRemove(inst.settings, settings || {}); + date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); + this._dialogInput.val(date); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + browserWidth = document.documentElement.clientWidth; + browserHeight = document.documentElement.clientHeight; + scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) { + $.blockUI(this.dpDiv); + } + $.data(this._dialogInput[0], "datepicker", inst); + return this; + }, + + /* Detach a datepicker from its control. + * @param target element - the target input field or division or span + */ + _destroyDatepicker: function(target) { + var nodeName, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + $.removeData(target, "datepicker"); + if (nodeName === "input") { + inst.append.remove(); + inst.trigger.remove(); + $target.removeClass(this.markerClassName). + unbind("focus", this._showDatepicker). + unbind("keydown", this._doKeyDown). + unbind("keypress", this._doKeyPress). + unbind("keyup", this._doKeyUp); + } else if (nodeName === "div" || nodeName === "span") { + $target.removeClass(this.markerClassName).empty(); + } + }, + + /* Enable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _enableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img").css({opacity: "1.0", cursor: ""}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().removeClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", false); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + * @param target element - the target input field or division or span + */ + _disableDatepicker: function(target) { + var nodeName, inline, + $target = $(target), + inst = $.data(target, "datepicker"); + + if (!$target.hasClass(this.markerClassName)) { + return; + } + + nodeName = target.nodeName.toLowerCase(); + if (nodeName === "input") { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img").css({opacity: "0.5", cursor: "default"}); + } else if (nodeName === "div" || nodeName === "span") { + inline = $target.children("." + this._inlineClass); + inline.children().addClass("ui-state-disabled"); + inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). + prop("disabled", true); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value === target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + * @param target element - the target input field or division or span + * @return boolean - true if disabled, false if enabled + */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] === target) { + return true; + } + } + return false; + }, + + /* Retrieve the instance data for the target control. + * @param target element - the target input field or division or span + * @return object - the associated instance data + * @throws error if a jQuery problem getting data + */ + _getInst: function(target) { + try { + return $.data(target, "datepicker"); + } + catch (err) { + throw "Missing instance data for this datepicker"; + } + }, + + /* Update or retrieve the settings for a date picker attached to an input field or division. + * @param target element - the target input field or division or span + * @param name object - the new settings to update or + * string - the name of the setting to change or retrieve, + * when retrieving also "all" for all instance settings or + * "defaults" for all global defaults + * @param value any - the new value for the setting + * (omit if above is an object or to retrieve a value) + */ + _optionDatepicker: function(target, name, value) { + var settings, date, minDate, maxDate, + inst = this._getInst(target); + + if (arguments.length === 2 && typeof name === "string") { + return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : + (inst ? (name === "all" ? $.extend({}, inst.settings) : + this._get(inst, name)) : null)); + } + + settings = name || {}; + if (typeof name === "string") { + settings = {}; + settings[name] = value; + } + + if (inst) { + if (this._curInst === inst) { + this._hideDatepicker(); + } + + date = this._getDateDatepicker(target, true); + minDate = this._getMinMaxDate(inst, "min"); + maxDate = this._getMinMaxDate(inst, "max"); + datepicker_extendRemove(inst.settings, settings); + // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided + if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { + inst.settings.minDate = this._formatDate(inst, minDate); + } + if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { + inst.settings.maxDate = this._formatDate(inst, maxDate); + } + if ( "disabled" in settings ) { + if ( settings.disabled ) { + this._disableDatepicker(target); + } else { + this._enableDatepicker(target); + } + } + this._attachments($(target), inst); + this._autoSize(inst); + this._setDate(inst, date); + this._updateAlternate(inst); + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + * @param target element - the target input field or division or span + */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + * @param target element - the target input field or division or span + * @param date Date - the new date + */ + _setDateDatepicker: function(target, date) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + * @param target element - the target input field or division or span + * @param noDefault boolean - true if no default date is to be used + * @return Date - the current date + */ + _getDateDatepicker: function(target, noDefault) { + var inst = this._getInst(target); + if (inst && !inst.inline) { + this._setDateFromField(inst, noDefault); + } + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var onSelect, dateStr, sel, + inst = $.datepicker._getInst(event.target), + handled = true, + isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); + + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) { + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(); + handled = false; + break; // hide on tab out + case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + + $.datepicker._currentClass + ")", inst.dpDiv); + if (sel[0]) { + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + } + + onSelect = $.datepicker._get(inst, "onSelect"); + if (onSelect) { + dateStr = $.datepicker._formatDate(inst); + + // trigger custom callback + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); + } else { + $.datepicker._hideDatepicker(); + } + + return false; // don't submit the form + case 27: $.datepicker._hideDatepicker(); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) { + $.datepicker._clearDate(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) { + $.datepicker._gotoToday(event.target); + } + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, "stepBigMonths") : + -$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, -7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); + } + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) { + $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, "stepBigMonths") : + +$.datepicker._get(inst, "stepMonths")), "M"); + } + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) { + $.datepicker._adjustDate(event.target, +7, "D"); + } + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + } else { + handled = false; + } + + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var chars, chr, + inst = $.datepicker._getInst(event.target); + + if ($.datepicker._get(inst, "constrainInput")) { + chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); + chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); + return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Synchronise manual entry and field/alternate field. */ + _doKeyUp: function(event) { + var date, + inst = $.datepicker._getInst(event.target); + + if (inst.input.val() !== inst.lastVal) { + try { + date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + (inst.input ? inst.input.val() : null), + $.datepicker._getFormatConfig(inst)); + + if (date) { // only if valid + $.datepicker._setDateFromField(inst); + $.datepicker._updateAlternate(inst); + $.datepicker._updateDatepicker(inst); + } + } + catch (err) { + } + } + return true; + }, + + /* Pop-up the date picker for a given input field. + * If false returned from beforeShow event handler do not show. + * @param input element - the input field attached to the date picker or + * event - if triggered by focus + */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger + input = $("input", input.parentNode)[0]; + } + + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here + return; + } + + var inst, beforeShow, beforeShowSettings, isFixed, + offset, showAnim, duration; + + inst = $.datepicker._getInst(input); + if ($.datepicker._curInst && $.datepicker._curInst !== inst) { + $.datepicker._curInst.dpDiv.stop(true, true); + if ( inst && $.datepicker._datepickerShowing ) { + $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); + } + } + + beforeShow = $.datepicker._get(inst, "beforeShow"); + beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; + if(beforeShowSettings === false){ + return; + } + datepicker_extendRemove(inst.settings, beforeShowSettings); + + inst.lastVal = null; + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + + if ($.datepicker._inDialog) { // hide cursor + input.value = ""; + } + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + + isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css("position") === "fixed"; + return !isFixed; + }); + + offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + //to avoid flashes on Firefox + inst.dpDiv.empty(); + // determine sizing offscreen + inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + "static" : (isFixed ? "fixed" : "absolute")), display: "none", + left: offset.left + "px", top: offset.top + "px"}); + + if (!inst.inline) { + showAnim = $.datepicker._get(inst, "showAnim"); + duration = $.datepicker._get(inst, "duration"); + inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); + $.datepicker._datepickerShowing = true; + + if ( $.effects && $.effects.effect[ showAnim ] ) { + inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); + } else { + inst.dpDiv[showAnim || "show"](showAnim ? duration : null); + } + + if ( $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) + datepicker_instActive = inst; // for delegate hover events + inst.dpDiv.empty().append(this._generateHTML(inst)); + this._attachHandlers(inst); + inst.dpDiv.find("." + this._dayOverClass + " a").mouseover(); + + var origyearshtml, + numMonths = this._getNumberOfMonths(inst), + cols = numMonths[1], + width = 17; + + inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); + if (cols > 1) { + inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); + } + inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + + "Class"]("ui-datepicker-multi"); + inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + + "Class"]("ui-datepicker-rtl"); + + if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { + inst.input.focus(); + } + + // deffered render of the years select (to avoid flashes on Firefox) + if( inst.yearshtml ){ + origyearshtml = inst.yearshtml; + setTimeout(function(){ + //assure that inst.yearshtml didn't change. + if( origyearshtml === inst.yearshtml && inst.yearshtml ){ + inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); + } + origyearshtml = inst.yearshtml = null; + }, 0); + } + }, + + // #6694 - don't focus the input if it's already focused + // this breaks the change event in IE + // Support: IE and jQuery <1.9 + _shouldFocusInput: function( inst ) { + return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(), + dpHeight = inst.dpDiv.outerHeight(), + inputWidth = inst.input ? inst.input.outerWidth() : 0, + inputHeight = inst.input ? inst.input.outerHeight() : 0, + viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), + viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); + + offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight) : 0); + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + var position, + inst = this._getInst(obj), + isRTL = this._get(inst, "isRTL"); + + while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { + obj = obj[isRTL ? "previousSibling" : "nextSibling"]; + } + + position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + * @param input element - the input field attached to the date picker + */ + _hideDatepicker: function(input) { + var showAnim, duration, postProcess, onClose, + inst = this._curInst; + + if (!inst || (input && inst !== $.data(input, "datepicker"))) { + return; + } + + if (this._datepickerShowing) { + showAnim = this._get(inst, "showAnim"); + duration = this._get(inst, "duration"); + postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + + // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed + if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); + } else { + inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : + (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); + } + + if (!showAnim) { + postProcess(); + } + this._datepickerShowing = false; + + onClose = this._get(inst, "onClose"); + if (onClose) { + onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); + } + + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); + if ($.blockUI) { + $.unblockUI(); + $("body").append(this.dpDiv); + } + } + this._inDialog = false; + } + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) { + return; + } + + var $target = $(event.target), + inst = $.datepicker._getInst($target[0]); + + if ( ( ( $target[0].id !== $.datepicker._mainDivId && + $target.parents("#" + $.datepicker._mainDivId).length === 0 && + !$target.hasClass($.datepicker.markerClassName) && + !$target.closest("." + $.datepicker._triggerClass).length && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || + ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { + $.datepicker._hideDatepicker(); + } + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id), + inst = this._getInst(target[0]); + + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var date, + target = $(id), + inst = this._getInst(target[0]); + + if (this._get(inst, "gotoCurrent") && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } else { + date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id), + inst = this._getInst(target[0]); + + inst["selected" + (period === "M" ? "Month" : "Year")] = + inst["draw" + (period === "M" ? "Month" : "Year")] = + parseInt(select.options[select.selectedIndex].value,10); + + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var inst, + target = $(id); + + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + + inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $("a", td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + this._selectDate(target, ""); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var onSelect, + target = $(id), + inst = this._getInst(target[0]); + + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) { + inst.input.val(dateStr); + } + this._updateAlternate(inst); + + onSelect = this._get(inst, "onSelect"); + if (onSelect) { + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + } else if (inst.input) { + inst.input.trigger("change"); // fire the change event + } + + if (inst.inline){ + this._updateDatepicker(inst); + } else { + this._hideDatepicker(); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) !== "object") { + inst.input.focus(); // restore focus + } + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altFormat, date, dateStr, + altField = this._get(inst, "altField"); + + if (altField) { // update alternate field too + altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); + date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + * @param date Date - the date to customise + * @return [boolean, string] - is this date selectable?, what is its CSS class? + */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), ""]; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + * @param date Date - the date to get the week for + * @return number - the number of the week within the year that contains this date + */ + iso8601Week: function(date) { + var time, + checkDate = new Date(date.getTime()); + + // Find Thursday of this week starting on Monday + checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); + + time = checkDate.getTime(); + checkDate.setMonth(0); // Compare with Jan 1 + checkDate.setDate(1); + return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; + }, + + /* Parse a string value into a date object. + * See formatDate below for the possible formats. + * + * @param format string - the expected format of the date + * @param value string - the date in the above format + * @param settings Object - attributes include: + * shortYearCutoff number - the cutoff year for determining the century (optional) + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return Date - the extracted date value or null if value is blank + */ + parseDate: function (format, value, settings) { + if (format == null || value == null) { + throw "Invalid arguments"; + } + + value = (typeof value === "object" ? value.toString() : value + ""); + if (value === "") { + return null; + } + + var iFormat, dim, extra, + iValue = 0, + shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, + shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : + new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + year = -1, + month = -1, + day = -1, + doy = -1, + literal = false, + date, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Extract a number from the string value + getNumber = function(match) { + var isDoubled = lookAhead(match), + size = (match === "@" ? 14 : (match === "!" ? 20 : + (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), + digits = new RegExp("^\\d{1," + size + "}"), + num = value.substring(iValue).match(digits); + if (!num) { + throw "Missing number at position " + iValue; + } + iValue += num[0].length; + return parseInt(num[0], 10); + }, + // Extract a name from the string value and convert to an index + getName = function(match, shortNames, longNames) { + var index = -1, + names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { + return [ [k, v] ]; + }).sort(function (a, b) { + return -(a[1].length - b[1].length); + }); + + $.each(names, function (i, pair) { + var name = pair[1]; + if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { + index = pair[0]; + iValue += name.length; + return false; + } + }); + if (index !== -1) { + return index + 1; + } else { + throw "Unknown name at position " + iValue; + } + }, + // Confirm that a literal character matches the string value + checkLiteral = function() { + if (value.charAt(iValue) !== format.charAt(iFormat)) { + throw "Unexpected literal at position " + iValue; + } + iValue++; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + checkLiteral(); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + day = getNumber("d"); + break; + case "D": + getName("D", dayNamesShort, dayNames); + break; + case "o": + doy = getNumber("o"); + break; + case "m": + month = getNumber("m"); + break; + case "M": + month = getName("M", monthNamesShort, monthNames); + break; + case "y": + year = getNumber("y"); + break; + case "@": + date = new Date(getNumber("@")); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "!": + date = new Date((getNumber("!") - this._ticksTo1970) / 10000); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")){ + checkLiteral(); + } else { + literal = true; + } + break; + default: + checkLiteral(); + } + } + } + + if (iValue < value.length){ + extra = value.substr(iValue); + if (!/^\s+/.test(extra)) { + throw "Extra/unparsed characters found in date: " + extra; + } + } + + if (year === -1) { + year = new Date().getFullYear(); + } else if (year < 100) { + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + } + + if (doy > -1) { + month = 1; + day = doy; + do { + dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) { + break; + } + month++; + day -= dim; + } while (true); + } + + date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { + throw "Invalid date"; // E.g. 31/02/00 + } + return date; + }, + + /* Standard date formats. */ + ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) + COOKIE: "D, dd M yy", + ISO_8601: "yy-mm-dd", + RFC_822: "D, d M y", + RFC_850: "DD, dd-M-y", + RFC_1036: "D, d M y", + RFC_1123: "D, d M yy", + RFC_2822: "D, d M yy", + RSS: "D, d M y", // RFC 822 + TICKS: "!", + TIMESTAMP: "@", + W3C: "yy-mm-dd", // ISO 8601 + + _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), + + /* Format a date object into a string value. + * The format can be combinations of the following: + * d - day of month (no leading zero) + * dd - day of month (two digit) + * o - day of year (no leading zeros) + * oo - day of year (three digit) + * D - day name short + * DD - day name long + * m - month of year (no leading zero) + * mm - month of year (two digit) + * M - month name short + * MM - month name long + * y - year (two digit) + * yy - year (four digit) + * @ - Unix timestamp (ms since 01/01/1970) + * ! - Windows ticks (100ns since 01/01/0001) + * "..." - literal text + * '' - single quote + * + * @param format string - the desired format of the date + * @param date Date - the date value to format + * @param settings Object - attributes include: + * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + * dayNames string[7] - names of the days from Sunday (optional) + * monthNamesShort string[12] - abbreviated names of the months (optional) + * monthNames string[12] - names of the months (optional) + * @return string - the date in the above format + */ + formatDate: function (format, date, settings) { + if (!date) { + return ""; + } + + var iFormat, + dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, + dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, + monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, + monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }, + // Format a number, with leading zero if necessary + formatNumber = function(match, value, len) { + var num = "" + value; + if (lookAhead(match)) { + while (num.length < len) { + num = "0" + num; + } + } + return num; + }, + // Format a name, short or long as requested + formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }, + output = "", + literal = false; + + if (date) { + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + output += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": + output += formatNumber("d", date.getDate(), 2); + break; + case "D": + output += formatName("D", date.getDay(), dayNamesShort, dayNames); + break; + case "o": + output += formatNumber("o", + Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); + break; + case "m": + output += formatNumber("m", date.getMonth() + 1, 2); + break; + case "M": + output += formatName("M", date.getMonth(), monthNamesShort, monthNames); + break; + case "y": + output += (lookAhead("y") ? date.getFullYear() : + (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); + break; + case "@": + output += date.getTime(); + break; + case "!": + output += date.getTime() * 10000 + this._ticksTo1970; + break; + case "'": + if (lookAhead("'")) { + output += "'"; + } else { + literal = true; + } + break; + default: + output += format.charAt(iFormat); + } + } + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var iFormat, + chars = "", + literal = false, + // Check whether a format character is doubled + lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); + if (matches) { + iFormat++; + } + return matches; + }; + + for (iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) { + if (format.charAt(iFormat) === "'" && !lookAhead("'")) { + literal = false; + } else { + chars += format.charAt(iFormat); + } + } else { + switch (format.charAt(iFormat)) { + case "d": case "m": case "y": case "@": + chars += "0123456789"; + break; + case "D": case "M": + return null; // Accept anything + case "'": + if (lookAhead("'")) { + chars += "'"; + } else { + literal = true; + } + break; + default: + chars += format.charAt(iFormat); + } + } + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst, noDefault) { + if (inst.input.val() === inst.lastVal) { + return; + } + + var dateFormat = this._get(inst, "dateFormat"), + dates = inst.lastVal = inst.input ? inst.input.val() : null, + defaultDate = this._getDefaultDate(inst), + date = defaultDate, + settings = this._getFormatConfig(inst); + + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + dates = (noDefault ? "" : dates); + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + return this._restrictMinMax(inst, + this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(inst, date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }, + offsetString = function(offset) { + try { + return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), + offset, $.datepicker._getFormatConfig(inst)); + } + catch (e) { + // Ignore + } + + var date = (offset.toLowerCase().match(/^c/) ? + $.datepicker._getDate(inst) : null) || new Date(), + year = date.getFullYear(), + month = date.getMonth(), + day = date.getDate(), + pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, + matches = pattern.exec(offset); + + while (matches) { + switch (matches[2] || "d") { + case "d" : case "D" : + day += parseInt(matches[1],10); break; + case "w" : case "W" : + day += parseInt(matches[1],10) * 7; break; + case "m" : case "M" : + month += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + case "y": case "Y" : + year += parseInt(matches[1],10); + day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }, + newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : + (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); + + newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); + if (newDate) { + newDate.setHours(0); + newDate.setMinutes(0); + newDate.setSeconds(0); + newDate.setMilliseconds(0); + } + return this._daylightSavingAdjust(newDate); + }, + + /* Handle switch to/from daylight saving. + * Hours may be non-zero on daylight saving cut-over: + * > 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + */ + _daylightSavingAdjust: function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, noChange) { + var clear = !date, + origMonth = inst.selectedMonth, + origYear = inst.selectedYear, + newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); + + inst.selectedDay = inst.currentDay = newDate.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); + if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { + this._notifyChange(inst); + } + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? "" : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Attach the onxxx handlers. These are declared statically so + * they work with static code transformers like Caja. + */ + _attachHandlers: function(inst) { + var stepMonths = this._get(inst, "stepMonths"), + id = "#" + inst.id.replace( /\\\\/g, "\\" ); + inst.dpDiv.find("[data-handler]").map(function () { + var handler = { + prev: function () { + $.datepicker._adjustDate(id, -stepMonths, "M"); + }, + next: function () { + $.datepicker._adjustDate(id, +stepMonths, "M"); + }, + hide: function () { + $.datepicker._hideDatepicker(); + }, + today: function () { + $.datepicker._gotoToday(id); + }, + selectDay: function () { + $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); + return false; + }, + selectMonth: function () { + $.datepicker._selectMonthYear(id, this, "M"); + return false; + }, + selectYear: function () { + $.datepicker._selectMonthYear(id, this, "Y"); + return false; + } + }; + $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); + }); + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, + controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, + monthNames, monthNamesShort, beforeShowDay, showOtherMonths, + selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, + cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, + printDate, dRow, tbody, daySettings, otherMonth, unselectable, + tempDate = new Date(), + today = this._daylightSavingAdjust( + new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time + isRTL = this._get(inst, "isRTL"), + showButtonPanel = this._get(inst, "showButtonPanel"), + hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), + navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), + numMonths = this._getNumberOfMonths(inst), + showCurrentAtPos = this._get(inst, "showCurrentAtPos"), + stepMonths = this._get(inst, "stepMonths"), + isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), + currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + drawMonth = inst.drawMonth - showCurrentAtPos, + drawYear = inst.drawYear; + + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + + prevText = this._get(inst, "prevText"); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + + prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + "" + prevText + "" : + (hideIfNoPrevNext ? "" : "" + prevText + "")); + + nextText = this._get(inst, "nextText"); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + + next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + "" + nextText + "" : + (hideIfNoPrevNext ? "" : "" + nextText + "")); + + currentText = this._get(inst, "currentText"); + gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + + controls = (!inst.inline ? "" : ""); + + buttonPanel = (showButtonPanel) ? "
" + (isRTL ? controls : "") + + (this._isInRange(inst, gotoDate) ? "" : "") + (isRTL ? "" : controls) + "
" : ""; + + firstDay = parseInt(this._get(inst, "firstDay"),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + + showWeek = this._get(inst, "showWeek"); + dayNames = this._get(inst, "dayNames"); + dayNamesMin = this._get(inst, "dayNamesMin"); + monthNames = this._get(inst, "monthNames"); + monthNamesShort = this._get(inst, "monthNamesShort"); + beforeShowDay = this._get(inst, "beforeShowDay"); + showOtherMonths = this._get(inst, "showOtherMonths"); + selectOtherMonths = this._get(inst, "selectOtherMonths"); + defaultDate = this._getDefaultDate(inst); + html = ""; + dow; + for (row = 0; row < numMonths[0]; row++) { + group = ""; + this.maxRows = 4; + for (col = 0; col < numMonths[1]; col++) { + selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + cornerClass = " ui-corner-all"; + calender = ""; + if (isMultiMonth) { + calender += "
"; + } + calender += "
" + + (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + + (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + "
" + + ""; + thead = (showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += ""; + } + calender += thead + ""; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ""; + tbody = (!showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ""; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ""; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "
" + this._get(inst, "weekHeader") + "= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "" + dayNamesMin[day] + "
" + + this._get(inst, "calculateWeek")(printDate) + "" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "" + printDate.getDate() + "" : "" + printDate.getDate() + "")) + "
" + (isMultiMonth ? "
" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "
" : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "
", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "" + monthNames[drawMonth] + ""; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += ""; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "" + drawYear + ""; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += ""; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "
"; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10); + maxYear = parseInt(yearSplit[1], 10); + if ( yearSplit[0].match(/[+\-].*/) ) { + minYear += currentYear; + } + if ( yearSplit[1].match(/[+\-].*/) ) { + maxYear += currentYear; + } + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function datepicker_bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate(selector, "mouseover", function(){ + if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? dpDiv.parent()[0] : datepicker_instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } + }); +} + +/* jQuery extend now ignores nulls! */ +function datepicker_extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "@VERSION"; + +})(jQuery); diff --git a/templates/admin/default/assets/js/jquery.ui/jquery.ui.theme.css b/templates/admin/default/assets/js/jquery.ui/jquery.ui.theme.css new file mode 100644 index 000000000..71bd15664 --- /dev/null +++ b/templates/admin/default/assets/js/jquery.ui/jquery.ui.theme.css @@ -0,0 +1,410 @@ +/*! + * jQuery UI CSS Framework @VERSION + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/theming/ + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/ + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; + font-size: 1.1em/*{fsDefault}*/; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #aaaaaa/*{borderColorContent}*/; + background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; + color: #222222/*{fcContent}*/; +} +.ui-widget-content a { + color: #222222/*{fcContent}*/; +} +.ui-widget-header { + border: 1px solid #aaaaaa/*{borderColorHeader}*/; + background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; + color: #222222/*{fcHeader}*/; + font-weight: bold; +} +.ui-widget-header a { + color: #222222/*{fcHeader}*/; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #d3d3d3/*{borderColorDefault}*/; + background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; + font-weight: normal/*{fwDefault}*/; + color: #555555/*{fcDefault}*/; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #555555/*{fcDefault}*/; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #999999/*{borderColorHover}*/; + background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; + font-weight: normal/*{fwDefault}*/; + color: #212121/*{fcHover}*/; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited, +.ui-state-focus a, +.ui-state-focus a:hover, +.ui-state-focus a:link, +.ui-state-focus a:visited { + color: #212121/*{fcHover}*/; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #aaaaaa/*{borderColorActive}*/; + background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; + font-weight: normal/*{fwDefault}*/; + color: #212121/*{fcActive}*/; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #212121/*{fcActive}*/; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #fcefa1/*{borderColorHighlight}*/; + background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; + color: #363636/*{fcHighlight}*/; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636/*{fcHighlight}*/; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a/*{borderColorError}*/; + background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; + color: #cd0a0a/*{fcError}*/; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #cd0a0a/*{fcError}*/; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #cd0a0a/*{fcError}*/; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; +} +.ui-widget-header .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; +} +.ui-state-default .ui-icon { + background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; +} +.ui-state-active .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; +} +.ui-state-highlight .ui-icon { + background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; +} + +/* positioning */ +.ui-icon-blank { background-position: 16px 16px; } +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px/*{cornerRadius}*/; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px/*{cornerRadius}*/; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px/*{cornerRadius}*/; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px/*{cornerRadius}*/; +} + +/* Overlays */ +.ui-widget-overlay { + background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; + opacity: .3/*{opacityOverlay}*/; + filter: Alpha(Opacity=30)/*{opacityFilterOverlay}*/; +} +.ui-widget-shadow { + margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; + padding: 8px/*{thicknessShadow}*/; + background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; + opacity: .3/*{opacityShadow}*/; + filter: Alpha(Opacity=30)/*{opacityFilterShadow}*/; + border-radius: 8px/*{cornerRadiusShadow}*/; +} diff --git a/templates/admin/default/assets/less/thelia/logger.less b/templates/admin/default/assets/less/thelia/logger.less new file mode 100644 index 000000000..e8f6e63f2 --- /dev/null +++ b/templates/admin/default/assets/less/thelia/logger.less @@ -0,0 +1,25 @@ +.logger{ + margin: 20px 0px 20px 0px; + padding: 15px; + height: 400px; + overflow: scroll; + background-color: #000000; + color: #ffffff; + ul#logger-content{ + margin: 0px; + padding: 0px; + li.entry{ + list-style-type: none; + span.head { + color: #9acd32; + font-weight: bold; + } + span.data { + } + } + li.no-entry{ + list-style-type: none; + color: #ff0000; + } + } +} \ No newline at end of file diff --git a/templates/admin/default/assets/less/thelia/thelia.less b/templates/admin/default/assets/less/thelia/thelia.less index 4838ddda7..0d42273e9 100644 --- a/templates/admin/default/assets/less/thelia/thelia.less +++ b/templates/admin/default/assets/less/thelia/thelia.less @@ -15,6 +15,7 @@ @import "bootstrap-select.less"; @import "jqplot.less"; @import "dropzone.less"; +@import "logger.less"; // -- Base styling ------------------------------------------------------------ @@ -295,6 +296,14 @@ width: auto; } +.loading-block{ + background: url("@{imgDir}/ajax-loader.gif") no-repeat; + margin: auto; + height: 30px; + width: 30px; + display: none; +} + .modal-backdrop .loading { left: 50%; top: 50%; diff --git a/templates/admin/default/configuration.html b/templates/admin/default/configuration.html index a17042b4d..ff9622c45 100644 --- a/templates/admin/default/configuration.html +++ b/templates/admin/default/configuration.html @@ -153,19 +153,19 @@ {loop type="auth" name="pcc6" role="ADMIN" resource="admin.configuration.mailing-system" access="VIEW"} - {intl l='Mailing system'} + {intl l='Mailing system'} {/loop} -{* {loop type="auth" name="pcc7" role="ADMIN" resource="admin.configuration.admin-logs" access="VIEW"} + {loop type="auth" name="pcc7" role="ADMIN" resource="admin.configuration.admin-logs" access="VIEW"} - {intl l='Administration logs'} - + {intl l='Administration logs'} + {/loop} - {loop type="auth" name="pcc8" role="ADMIN" resource="admin.configuration.system-logs" access="VIEW"} +{* {loop type="auth" name="pcc8" role="ADMIN" resource="admin.configuration.system-logs" access="VIEW"} {intl l='System logs'} diff --git a/templates/admin/default/coupon-create.html b/templates/admin/default/coupon-create.html index 19f4bf795..66636df47 100755 --- a/templates/admin/default/coupon-create.html +++ b/templates/admin/default/coupon-create.html @@ -29,10 +29,6 @@ {/block} {block name="javascript-initialization"} - {javascripts file='assets/bootstrap-datepicker/js/bootstrap-datepicker.js'} - - {/javascripts} - {javascripts file='assets/js/main.js'} {/javascripts} @@ -63,10 +59,6 @@ filemanager_title:"{intl l='Files manager'}" , external_plugins: { "filemanager" : "{url file='/tinymce/plugins/filemanager/plugin.min.js'}"} }); - - $(function($){ - {*$('.datepicker').datepicker({ dateFormat: "{$dateFormat}", defaultDate: +60, minDate: "+0m" });*} - }); {/block} diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html index f96da1319..138ed28aa 100755 --- a/templates/admin/default/coupon-update.html +++ b/templates/admin/default/coupon-update.html @@ -28,10 +28,6 @@ {/block} {block name="javascript-initialization"} - {javascripts file='assets/bootstrap-datepicker/js/bootstrap-datepicker.js'} - - {/javascripts} - {javascripts file='assets/js/main.js'} {/javascripts} diff --git a/templates/admin/default/mailing-system.html b/templates/admin/default/mailing-system.html index 8ee5e3e3e..92d205289 100644 --- a/templates/admin/default/mailing-system.html +++ b/templates/admin/default/mailing-system.html @@ -13,7 +13,7 @@ {module_include location='mailing_system_top'} @@ -22,7 +22,7 @@
-
{intl l="Configuration variables"}
+
{intl l="Configuration mailing system"}
{form name="thelia.admin.mailing-system.update"} diff --git a/templates/default/index.html b/templates/default/index.html index c4204cb83..292aa238a 100644 --- a/templates/default/index.html +++ b/templates/default/index.html @@ -14,16 +14,16 @@
{images file='assets/img/carousel/slider1.png'}img1{/images}
-
+ {*
{images file='assets/img/carousel/slider2.png'}img2{/images}
{images file='assets/img/carousel/slider3.png'}img3{/images} -
+
*}
- - +{* + *}