From 77cf2c7cc65f8370a19e99947775c926f1573369 Mon Sep 17 00:00:00 2001 From: TheCoreDev Date: Tue, 11 Jun 2024 14:57:59 +0200 Subject: [PATCH] =?UTF-8?q?[11/06/2024]=20Les=20premi=C3=A8res=20modifs=20?= =?UTF-8?q?+=20installation=20de=20quelques=20modules=20indispensables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/light-domotique-NEW.iml | 3 + .idea/php.xml | 6 + domokits/.gitignore | 5 +- domokits/composer.json | 3 +- .../BetterSeo/.github/workflows/release.yml | 7 + .../local/modules/BetterSeo/BetterSeo.php | 77 + .../modules/BetterSeo/Config/Update/1.1.0.sql | 1 + .../modules/BetterSeo/Config/Update/1.2.0.sql | 1 + .../modules/BetterSeo/Config/Update/1.2.1.sql | 10 + .../modules/BetterSeo/Config/Update/1.3.0.sql | 6 + .../modules/BetterSeo/Config/Update/1.3.1.sql | 5 + .../modules/BetterSeo/Config/Update/1.4.0.sql | 1 + .../local/modules/BetterSeo/Config/config.xml | 20 + .../local/modules/BetterSeo/Config/module.xml | 32 + .../modules/BetterSeo/Config/routing.xml | 10 + .../local/modules/BetterSeo/Config/schema.xml | 56 + .../local/modules/BetterSeo/Config/sqldb.map | 2 + .../local/modules/BetterSeo/Config/thelia.sql | 58 + .../Controller/BetterSeoController.php | 64 + .../BetterSeo/EventListeners/SeoListener.php | 75 + .../modules/BetterSeo/Form/BetterSeoForm.php | 136 + .../local/modules/BetterSeo/Hook/MetaHook.php | 38 + .../modules/BetterSeo/Hook/SeoFormHook.php | 35 + .../I18n/backOffice/default/en_US.php | 11 + .../I18n/backOffice/default/fr_FR.php | 19 + .../local/modules/BetterSeo/I18n/en_US.php | 5 + .../local/modules/BetterSeo/I18n/fr_FR.php | 5 + domokits/local/modules/BetterSeo/LICENCE.md | 21 + .../modules/BetterSeo/Loop/BetterSeoLoop.php | 87 + .../modules/BetterSeo/Model/BetterSeo.php | 10 + .../modules/BetterSeo/Model/BetterSeoI18n.php | 10 + .../BetterSeo/Model/BetterSeoI18nQuery.php | 21 + .../BetterSeo/Model/BetterSeoQuery.php | 21 + domokits/local/modules/BetterSeo/README.md | 75 + .../Plugins/BetterSeoMicroDataPlugin.php | 318 + .../local/modules/BetterSeo/composer.json | 11 + .../default/seo-additional-fields.html | 196 + .../frontOffice/default/meta_hook.html | 18 + .../local/modules/CanonicalUrl/CHANGELOG.md | 20 + .../modules/CanonicalUrl/CanonicalUrl.php | 35 + .../modules/CanonicalUrl/Config/config.xml | 16 + .../modules/CanonicalUrl/Config/module.xml | 38 + .../modules/CanonicalUrl/Config/routing.xml | 7 + .../CanonicalUrl/Event/CanonicalUrlEvent.php | 50 + .../CanonicalUrl/Event/CanonicalUrlEvents.php | 23 + .../EventListener/CanonicalUrlListener.php | 249 + .../EventListener/SeoFormListener.php | 112 + .../modules/CanonicalUrl/Hook/MetaHook.php | 49 + .../CanonicalUrl/Hook/SeoUpdateFormHook.php | 50 + .../I18n/backOffice/default/en_US.php | 15 + .../local/modules/CanonicalUrl/LICENSE.txt | 165 + domokits/local/modules/CanonicalUrl/Readme.md | 47 + .../CanonicalUrl/Tests/CanonicalUrlTest.php | 245 + .../local/modules/CanonicalUrl/composer.json | 11 + .../default/hook-seo-update-form.html | 6 + domokits/local/modules/Carousel/CHANGELOG.md | 6 + domokits/local/modules/Carousel/Carousel.php | 124 + .../modules/Carousel/Config/TheliaMain.sql | 51 + .../local/modules/Carousel/Config/config.xml | 15 + .../local/modules/Carousel/Config/module.xml | 24 + .../local/modules/Carousel/Config/routing.xml | 42 + .../local/modules/Carousel/Config/schema.xml | 29 + .../modules/Carousel/Config/sql/destroy.sql | 6 + .../local/modules/Carousel/Config/sqldb.map | 2 + .../modules/Carousel/Config/update/2.4.0.sql | 1 + .../Controller/ConfigurationController.php | 196 + .../Carousel/Form/CarouselImageForm.php | 46 + .../Carousel/Form/CarouselUpdateForm.php | 222 + .../local/modules/Carousel/Hook/BackHook.php | 43 + .../I18n/backOffice/default/de_DE.php | 24 + .../I18n/backOffice/default/en_US.php | 25 + .../I18n/backOffice/default/fr_FR.php | 25 + .../I18n/backOffice/default/ru_RU.php | 24 + .../I18n/backOffice/default/tr_TR.php | 24 + .../local/modules/Carousel/I18n/de_DE.php | 30 + .../local/modules/Carousel/I18n/en_US.php | 32 + .../local/modules/Carousel/I18n/fr_FR.php | 37 + .../local/modules/Carousel/I18n/it_IT.php | 21 + .../local/modules/Carousel/I18n/ru_RU.php | 31 + .../local/modules/Carousel/I18n/tr_TR.php | 30 + .../local/modules/Carousel/Loop/Carousel.php | 237 + .../local/modules/Carousel/Model/Carousel.php | 120 + .../modules/Carousel/Model/CarouselI18n.php | 19 + .../Carousel/Model/CarouselI18nQuery.php | 26 + .../modules/Carousel/Model/CarouselQuery.php | 31 + domokits/local/modules/Carousel/Readme.md | 69 + domokits/local/modules/Carousel/composer.json | 11 + .../default/assets/js/module-configuration.js | 6 + .../default/module_configuration.html | 179 + .../frontOffice/default/carousel.html | 24 + domokits/local/modules/Cheque/Cheque.php | 71 + .../local/modules/Cheque/Config/config.xml | 25 + .../local/modules/Cheque/Config/module.xml | 25 + .../local/modules/Cheque/Config/routing.xml | 9 + .../local/modules/Cheque/Config/setup.sql | 32 + .../Cheque/Controller/ConfigureController.php | 84 + .../modules/Cheque/Form/ConfigurationForm.php | 80 + .../local/modules/Cheque/Hook/HookManager.php | 33 + .../Cheque/I18n/backOffice/default/de_DE.php | 15 + .../Cheque/I18n/backOffice/default/en_US.php | 15 + .../Cheque/I18n/backOffice/default/fr_FR.php | 15 + .../Cheque/I18n/backOffice/default/ru_RU.php | 15 + .../Cheque/I18n/backOffice/default/tr_TR.php | 15 + domokits/local/modules/Cheque/I18n/de_DE.php | 21 + domokits/local/modules/Cheque/I18n/en_US.php | 21 + domokits/local/modules/Cheque/I18n/fr_FR.php | 21 + .../Cheque/I18n/frontOffice/default/de_DE.php | 16 + .../Cheque/I18n/frontOffice/default/en_US.php | 16 + .../Cheque/I18n/frontOffice/default/fr_FR.php | 16 + .../Cheque/I18n/frontOffice/default/ru_RU.php | 16 + .../Cheque/I18n/frontOffice/default/tr_TR.php | 16 + domokits/local/modules/Cheque/I18n/ru_RU.php | 21 + domokits/local/modules/Cheque/I18n/tr_TR.php | 21 + domokits/local/modules/Cheque/LICENSE.txt | 674 + .../Listener/SendPaymentConfirmationEmail.php | 68 + domokits/local/modules/Cheque/composer.json | 11 + .../local/modules/Cheque/images/cheque.png | Bin 0 -> 24812 bytes .../default/module_configuration.html | 55 + .../order-placed.additional-payment-info.html | 21 + .../modules/ChoiceFilter/ChoiceFilter.php | 50 + .../modules/ChoiceFilter/Config/config.xml | 20 + .../modules/ChoiceFilter/Config/insert.sql | 17 + .../modules/ChoiceFilter/Config/module.xml | 28 + .../modules/ChoiceFilter/Config/routing.xml | 15 + .../modules/ChoiceFilter/Config/schema.xml | 48 + .../modules/ChoiceFilter/Config/thelia.sql | 91 + .../Controller/ChoiceFilterController.php | 130 + .../Front/ChoiceFilterFrontController.php | 202 + .../ChoiceFilter/Hook/ChoiceFilterHook.php | 142 + .../I18n/backOffice/default/fr_FR.php | 17 + .../local/modules/ChoiceFilter/I18n/en_US.php | 4 + .../local/modules/ChoiceFilter/I18n/fr_FR.php | 4 + domokits/local/modules/ChoiceFilter/LICENCE | 21 + .../ChoiceFilter/Loop/ChoiceFilterLoop.php | 152 + .../Model/Api/BrandChoiceFilter.php | 122 + .../Model/Api/CategoryChoiceFilter.php | 149 + .../ChoiceFilter/Model/Api/ChoiceFilter.php | 226 + .../Model/Api/ChoiceFilterValue.php | 88 + .../ChoiceFilter/Model/ChoiceFilter.php | 10 + .../ChoiceFilter/Model/ChoiceFilterOther.php | 10 + .../Model/ChoiceFilterOtherI18n.php | 10 + .../Model/ChoiceFilterOtherI18nQuery.php | 21 + .../Model/ChoiceFilterOtherQuery.php | 39 + .../ChoiceFilter/Model/ChoiceFilterQuery.php | 192 + domokits/local/modules/ChoiceFilter/Readme.md | 108 + domokits/local/modules/ChoiceFilter/Util.php | 79 + .../local/modules/ChoiceFilter/composer.json | 12 + .../default/choice-filter/category-edit.html | 1 + .../choice-filter/hook/category.edit-js.html | 27 + .../hook/category.tab-content.html | 1 + .../hook/template-edit.bottom.html | 117 + .../choice-filter/hook/template.edit-js.html | 1 + .../default/choice-filter/template-edit.html | 1 + .../.github/workflows/release.yml | 7 + .../local/modules/CustomDelivery/CHANGELOG.md | 17 + .../modules/CustomDelivery/Config/config.xml | 38 + .../modules/CustomDelivery/Config/module.xml | 24 + .../modules/CustomDelivery/Config/routing.xml | 19 + .../modules/CustomDelivery/Config/schema.xml | 23 + .../modules/CustomDelivery/Config/sqldb.map | 2 + .../modules/CustomDelivery/Config/thelia.sql | 29 + .../Controller/BackController.php | 245 + .../modules/CustomDelivery/CustomDelivery.php | 288 + .../EventListeners/ApiListener.php | 104 + .../EventListeners/CustomDeliveryEvents.php | 127 + .../CustomDelivery/Form/ConfigurationForm.php | 130 + .../modules/CustomDelivery/Form/SliceForm.php | 92 + .../CustomDelivery/Hook/HookManager.php | 67 + .../I18n/backOffice/default/en_US.php | 19 + .../I18n/backOffice/default/fr_FR.php | 19 + .../I18n/email/default/en_US.php | 11 + .../I18n/email/default/fr_FR.php | 11 + .../modules/CustomDelivery/I18n/en_US.php | 24 + .../modules/CustomDelivery/I18n/fr_FR.php | 24 + domokits/local/modules/CustomDelivery/LICENSE | 166 + .../Loop/CustomDeliverySliceLoop.php | 168 + .../Model/CustomDeliverySlice.php | 10 + .../Model/CustomDeliverySliceQuery.php | 21 + .../local/modules/CustomDelivery/Readme.md | 32 + .../modules/CustomDelivery/composer.json | 11 + .../backOffice/default/module-config-js.html | 127 + .../default/module-configuration.html | 195 + .../default/custom-delivery-shipping.html | 17 + .../default/custom-delivery-shipping.txt | 18 + .../local/modules/FreeOrder/Config/config.xml | 6 + .../local/modules/FreeOrder/Config/module.xml | 27 + .../local/modules/FreeOrder/FreeOrder.php | 45 + domokits/local/modules/FreeOrder/LICENSE.txt | 674 + domokits/local/modules/FreeOrder/Readme.md | 25 + .../local/modules/FreeOrder/composer.json | 11 + .../local/modules/Front/Config/config.xml | 26 + domokits/local/modules/Front/Config/front.xml | 276 + .../local/modules/Front/Config/module.xml | 29 + .../Front/Controller/AddressController.php | 257 + .../Front/Controller/CartController.php | 241 + .../Front/Controller/ContactController.php | 91 + .../Front/Controller/CouponController.php | 158 + .../Front/Controller/CustomerController.php | 595 + .../Front/Controller/FeedController.php | 196 + .../Front/Controller/NewsletterController.php | 154 + .../Front/Controller/OrderController.php | 591 + .../Front/Controller/SitemapController.php | 144 + domokits/local/modules/Front/Front.php | 32 + domokits/local/modules/Front/I18n/de_DE.php | 32 + domokits/local/modules/Front/I18n/en_US.php | 34 + domokits/local/modules/Front/I18n/fr_FR.php | 33 + domokits/local/modules/Front/I18n/it_IT.php | 17 + domokits/local/modules/Front/I18n/ru_RU.php | 35 + domokits/local/modules/Front/I18n/tr_TR.php | 32 + domokits/local/modules/Front/LICENSE.txt | 674 + domokits/local/modules/Front/composer.json | 11 + .../modules/HookAdminHome/Config/config.xml | 44 + .../modules/HookAdminHome/Config/module.xml | 32 + .../modules/HookAdminHome/Config/routing.xml | 12 + .../Controller/ConfigurationController.php | 83 + .../Controller/HomeController.php | 164 + .../HookAdminHome/Form/Configuration.php | 101 + .../modules/HookAdminHome/Hook/AdminHook.php | 151 + .../HookAdminHome/Hook/HookAdminManager.php | 26 + .../modules/HookAdminHome/HookAdminHome.php | 61 + .../modules/HookAdminHome/I18n/ar_SA.php | 15 + .../I18n/backOffice/default/ar_SA.php | 21 + .../I18n/backOffice/default/cs_CZ.php | 41 + .../I18n/backOffice/default/de_DE.php | 40 + .../I18n/backOffice/default/en_US.php | 43 + .../I18n/backOffice/default/es_ES.php | 41 + .../I18n/backOffice/default/fr_FR.php | 42 + .../I18n/backOffice/default/it_IT.php | 42 + .../I18n/backOffice/default/pt_BR.php | 16 + .../I18n/backOffice/default/ru_RU.php | 41 + .../I18n/backOffice/default/tr_TR.php | 41 + .../modules/HookAdminHome/I18n/cs_CZ.php | 17 + .../modules/HookAdminHome/I18n/de_DE.php | 17 + .../modules/HookAdminHome/I18n/en_US.php | 17 + .../modules/HookAdminHome/I18n/es_ES.php | 16 + .../modules/HookAdminHome/I18n/fr_FR.php | 18 + .../modules/HookAdminHome/I18n/id_ID.php | 15 + .../modules/HookAdminHome/I18n/it_IT.php | 16 + .../modules/HookAdminHome/I18n/ru_RU.php | 17 + .../modules/HookAdminHome/I18n/tr_TR.php | 17 + .../local/modules/HookAdminHome/LICENSE.txt | 674 + .../local/modules/HookAdminHome/composer.json | 11 + .../backOffice/default/admin-home-config.html | 87 + .../default/ajax/thelia_news_feed.html | 29 + .../backOffice/default/assets/css/home.css | 1 + .../backOffice/default/assets/less/home.less | 45 + .../backOffice/default/block-information.html | 59 + .../default/block-month-sales-statistics.html | 48 + .../backOffice/default/block-news-js.html | 7 + .../backOffice/default/block-news.html | 5 + .../default/block-sales-statistics.html | 100 + .../default/block-statistics-js.html | 207 + .../backOffice/default/block-statistics.html | 34 + .../default/block-thelia-information.html | 24 + .../default/hook-admin-home-config.html | 1 + .../modules/HookAnalytics/Config/config.xml | 21 + .../modules/HookAnalytics/Config/module.xml | 24 + .../modules/HookAnalytics/Config/routing.xml | 10 + .../Controller/Configuration.php | 54 + .../HookAnalytics/Form/Configuration.php | 58 + .../modules/HookAnalytics/Hook/FrontHook.php | 36 + .../modules/HookAnalytics/HookAnalytics.php | 35 + .../I18n/backOffice/default/de_DE.php | 17 + .../I18n/backOffice/default/en_US.php | 17 + .../I18n/backOffice/default/fr_FR.php | 17 + .../I18n/backOffice/default/it_IT.php | 15 + .../I18n/backOffice/default/ru_RU.php | 17 + .../I18n/backOffice/default/tr_TR.php | 17 + .../modules/HookAnalytics/I18n/de_DE.php | 15 + .../modules/HookAnalytics/I18n/en_US.php | 15 + .../modules/HookAnalytics/I18n/fr_FR.php | 15 + .../I18n/frontOffice/default/de_DE.php | 20 + .../I18n/frontOffice/default/en_US.php | 20 + .../I18n/frontOffice/default/fr_FR.php | 20 + .../I18n/frontOffice/default/it_IT.php | 20 + .../I18n/frontOffice/default/ru_RU.php | 20 + .../I18n/frontOffice/default/tr_TR.php | 20 + .../modules/HookAnalytics/I18n/it_IT.php | 15 + .../modules/HookAnalytics/I18n/ru_RU.php | 15 + .../modules/HookAnalytics/I18n/tr_TR.php | 15 + .../local/modules/HookAnalytics/LICENSE.txt | 674 + .../local/modules/HookAnalytics/composer.json | 11 + .../default/assets/js/module-configuration.js | 29 + .../default/module_configuration.html | 62 + .../local/modules/HookCart/Config/config.xml | 15 + .../local/modules/HookCart/Config/module.xml | 24 + domokits/local/modules/HookCart/HookCart.php | 19 + .../I18n/frontOffice/default/de_DE.php | 19 + .../I18n/frontOffice/default/en_US.php | 19 + .../I18n/frontOffice/default/fr_FR.php | 19 + .../I18n/frontOffice/default/it_IT.php | 19 + .../I18n/frontOffice/default/ru_RU.php | 19 + .../I18n/frontOffice/default/tr_TR.php | 19 + domokits/local/modules/HookCart/LICENSE.txt | 674 + domokits/local/modules/HookCart/composer.json | 11 + .../frontOffice/default/assets/css/styles.css | 0 .../default/main-navbar-secondary.html | 3 + .../frontOffice/default/mini-cart.html | 73 + .../modules/HookContact/Config/config.xml | 13 + .../modules/HookContact/Config/module.xml | 24 + .../modules/HookContact/Hook/FrontHook.php | 39 + .../local/modules/HookContact/HookContact.php | 19 + .../local/modules/HookContact/I18n/de_DE.php | 15 + .../local/modules/HookContact/I18n/en_US.php | 15 + .../local/modules/HookContact/I18n/fr_FR.php | 15 + .../I18n/frontOffice/default/fr_FR.php | 15 + .../I18n/frontOffice/default/ru_RU.php | 15 + .../local/modules/HookContact/I18n/it_IT.php | 15 + .../local/modules/HookContact/I18n/ru_RU.php | 15 + .../local/modules/HookContact/I18n/tr_TR.php | 15 + .../local/modules/HookContact/LICENSE.txt | 674 + .../local/modules/HookContact/composer.json | 11 + .../frontOffice/default/main-footer-body.html | 25 + .../modules/HookCurrency/Config/config.xml | 13 + .../modules/HookCurrency/Config/module.xml | 24 + .../modules/HookCurrency/HookCurrency.php | 19 + .../local/modules/HookCurrency/LICENSE.txt | 674 + .../local/modules/HookCurrency/composer.json | 11 + .../default/main-navbar-secondary.html | 10 + .../modules/HookCustomer/Config/config.xml | 14 + .../modules/HookCustomer/Config/module.xml | 24 + .../modules/HookCustomer/HookCustomer.php | 19 + .../I18n/frontOffice/default/de_DE.php | 23 + .../I18n/frontOffice/default/en_US.php | 23 + .../I18n/frontOffice/default/fr_FR.php | 23 + .../I18n/frontOffice/default/it_IT.php | 23 + .../I18n/frontOffice/default/ru_RU.php | 23 + .../I18n/frontOffice/default/tr_TR.php | 23 + .../local/modules/HookCustomer/LICENSE.txt | 674 + .../local/modules/HookCustomer/composer.json | 11 + .../frontOffice/default/assets/css/styles.css | 0 .../default/main-navbar-secondary.html | 43 + .../local/modules/HookLang/Config/config.xml | 13 + .../local/modules/HookLang/Config/module.xml | 24 + domokits/local/modules/HookLang/HookLang.php | 19 + domokits/local/modules/HookLang/LICENSE.txt | 674 + domokits/local/modules/HookLang/composer.json | 11 + .../default/main-navbar-secondary.html | 10 + .../local/modules/HookLinks/Config/config.xml | 13 + .../local/modules/HookLinks/Config/module.xml | 24 + .../modules/HookLinks/Hook/FrontHook.php | 37 + .../local/modules/HookLinks/HookLinks.php | 19 + .../local/modules/HookLinks/I18n/de_DE.php | 15 + .../local/modules/HookLinks/I18n/en_US.php | 15 + .../local/modules/HookLinks/I18n/fr_FR.php | 15 + .../I18n/frontOffice/default/de_DE.php | 20 + .../I18n/frontOffice/default/en_US.php | 20 + .../I18n/frontOffice/default/fr_FR.php | 20 + .../I18n/frontOffice/default/it_IT.php | 20 + .../I18n/frontOffice/default/ru_RU.php | 20 + .../I18n/frontOffice/default/tr_TR.php | 20 + .../local/modules/HookLinks/I18n/it_IT.php | 15 + .../local/modules/HookLinks/I18n/ru_RU.php | 15 + .../local/modules/HookLinks/I18n/tr_TR.php | 15 + domokits/local/modules/HookLinks/LICENSE.txt | 674 + .../local/modules/HookLinks/composer.json | 11 + .../frontOffice/default/main-footer-body.html | 15 + .../modules/HookNavigation/Config/config.xml | 17 + .../modules/HookNavigation/Config/module.xml | 24 + .../modules/HookNavigation/Config/routing.xml | 9 + .../HookNavigationConfigController.php | 87 + .../Form/HookNavigationConfigForm.php | 51 + .../modules/HookNavigation/Hook/FrontHook.php | 50 + .../modules/HookNavigation/HookNavigation.php | 36 + .../I18n/backOffice/default/de_DE.php | 21 + .../I18n/backOffice/default/en_US.php | 20 + .../I18n/backOffice/default/fr_FR.php | 20 + .../I18n/backOffice/default/it_IT.php | 17 + .../I18n/backOffice/default/ru_RU.php | 20 + .../I18n/backOffice/default/tr_TR.php | 21 + .../modules/HookNavigation/I18n/en_US.php | 18 + .../modules/HookNavigation/I18n/fr_FR.php | 18 + .../I18n/frontOffice/default/de_DE.php | 16 + .../I18n/frontOffice/default/en_US.php | 18 + .../I18n/frontOffice/default/fr_FR.php | 18 + .../I18n/frontOffice/default/it_IT.php | 18 + .../I18n/frontOffice/default/ru_RU.php | 18 + .../I18n/frontOffice/default/tr_TR.php | 16 + .../modules/HookNavigation/I18n/it_IT.php | 15 + .../modules/HookNavigation/I18n/ru_RU.php | 18 + .../local/modules/HookNavigation/LICENSE.txt | 674 + .../Config/Base/HookNavigationConfigValue.php | 22 + .../Config/HookNavigationConfigValue.php | 22 + .../modules/HookNavigation/composer.json | 11 + .../default/hooknavigation-configuration.html | 116 + .../frontOffice/default/main-footer-body.html | 17 + .../default/main-footer-bottom.html | 7 + .../default/main-navbar-primary.html | 56 + .../modules/HookNewsletter/Config/config.xml | 13 + .../modules/HookNewsletter/Config/module.xml | 24 + .../modules/HookNewsletter/Hook/FrontHook.php | 37 + .../modules/HookNewsletter/HookNewsletter.php | 19 + .../modules/HookNewsletter/I18n/de_DE.php | 15 + .../modules/HookNewsletter/I18n/en_US.php | 15 + .../modules/HookNewsletter/I18n/fr_FR.php | 15 + .../I18n/frontOffice/default/de_DE.php | 18 + .../I18n/frontOffice/default/en_US.php | 18 + .../I18n/frontOffice/default/fr_FR.php | 18 + .../I18n/frontOffice/default/it_IT.php | 16 + .../I18n/frontOffice/default/ru_RU.php | 18 + .../I18n/frontOffice/default/tr_TR.php | 18 + .../modules/HookNewsletter/I18n/it_IT.php | 15 + .../modules/HookNewsletter/I18n/ru_RU.php | 15 + .../modules/HookNewsletter/I18n/tr_TR.php | 15 + .../local/modules/HookNewsletter/LICENSE.txt | 674 + .../modules/HookNewsletter/composer.json | 11 + .../frontOffice/default/main-footer-body.html | 13 + .../modules/HookProductsNew/Config/config.xml | 13 + .../modules/HookProductsNew/Config/module.xml | 24 + .../HookProductsNew/HookProductsNew.php | 19 + .../I18n/frontOffice/default/de_DE.php | 16 + .../I18n/frontOffice/default/en_US.php | 16 + .../I18n/frontOffice/default/fr_FR.php | 16 + .../I18n/frontOffice/default/it_IT.php | 16 + .../I18n/frontOffice/default/ru_RU.php | 16 + .../I18n/frontOffice/default/tr_TR.php | 16 + .../local/modules/HookProductsNew/LICENSE.txt | 674 + .../modules/HookProductsNew/composer.json | 11 + .../frontOffice/default/home-body.html | 59 + .../HookProductsOffer/Config/config.xml | 13 + .../HookProductsOffer/Config/module.xml | 24 + .../HookProductsOffer/HookProductsOffer.php | 19 + .../I18n/frontOffice/default/de_DE.php | 16 + .../I18n/frontOffice/default/en_US.php | 16 + .../I18n/frontOffice/default/fr_FR.php | 16 + .../I18n/frontOffice/default/it_IT.php | 16 + .../I18n/frontOffice/default/ru_RU.php | 16 + .../I18n/frontOffice/default/tr_TR.php | 16 + .../modules/HookProductsOffer/LICENSE.txt | 674 + .../modules/HookProductsOffer/composer.json | 11 + .../frontOffice/default/home-body.html | 39 + .../modules/HookSearch/Config/config.xml | 15 + .../modules/HookSearch/Config/module.xml | 24 + .../local/modules/HookSearch/HookSearch.php | 19 + .../I18n/frontOffice/default/de_DE.php | 18 + .../I18n/frontOffice/default/en_US.php | 18 + .../I18n/frontOffice/default/fr_FR.php | 18 + .../I18n/frontOffice/default/it_IT.php | 18 + .../I18n/frontOffice/default/ru_RU.php | 18 + .../I18n/frontOffice/default/tr_TR.php | 18 + domokits/local/modules/HookSearch/LICENSE.txt | 674 + .../local/modules/HookSearch/composer.json | 11 + .../frontOffice/default/assets/css/styles.css | 11 + .../default/main-navbar-primary.html | 11 + .../default/main-navbar-secondary.html | 7 + .../modules/HookSocial/Config/config.xml | 21 + .../modules/HookSocial/Config/module.xml | 24 + .../modules/HookSocial/Config/routing.xml | 10 + .../HookSocial/Controller/Configuration.php | 60 + .../modules/HookSocial/Form/Configuration.php | 85 + .../modules/HookSocial/Hook/FrontHook.php | 37 + .../local/modules/HookSocial/HookSocial.php | 19 + .../I18n/backOffice/default/de_DE.php | 16 + .../I18n/backOffice/default/en_US.php | 17 + .../I18n/backOffice/default/fr_FR.php | 17 + .../I18n/backOffice/default/it_IT.php | 16 + .../I18n/backOffice/default/ru_RU.php | 17 + .../I18n/backOffice/default/tr_TR.php | 17 + .../local/modules/HookSocial/I18n/de_DE.php | 22 + .../local/modules/HookSocial/I18n/en_US.php | 22 + .../local/modules/HookSocial/I18n/fr_FR.php | 22 + .../I18n/frontOffice/default/de_DE.php | 20 + .../I18n/frontOffice/default/en_US.php | 20 + .../I18n/frontOffice/default/fr_FR.php | 20 + .../I18n/frontOffice/default/it_IT.php | 20 + .../I18n/frontOffice/default/ru_RU.php | 21 + .../I18n/frontOffice/default/tr_TR.php | 20 + .../local/modules/HookSocial/I18n/it_IT.php | 22 + .../local/modules/HookSocial/I18n/ru_RU.php | 22 + .../local/modules/HookSocial/I18n/tr_TR.php | 22 + domokits/local/modules/HookSocial/LICENSE.txt | 674 + .../local/modules/HookSocial/composer.json | 11 + .../default/assets/js/module-configuration.js | 28 + .../default/module_configuration.html | 94 + .../frontOffice/default/assets/css/styles.css | 0 .../frontOffice/default/main-footer-body.html | 86 + .../LocalPickup/.github/workflows/release.yml | 7 + .../modules/LocalPickup/Config/config.xml | 22 + .../modules/LocalPickup/Config/module.xml | 18 + .../modules/LocalPickup/Config/routing.xml | 9 + .../Controller/ConfigurationController.php | 74 + .../EventListeners/APIListener.php | 145 + .../LocalPickup/Form/ConfigurationForm.php | 84 + .../modules/LocalPickup/Hook/HookManager.php | 75 + .../I18n/backOffice/default/en_US.php | 7 + .../I18n/backOffice/default/fr_FR.php | 7 + .../LocalPickup/I18n/email/default/en_US.php | 10 + .../LocalPickup/I18n/email/default/fr_FR.php | 10 + .../local/modules/LocalPickup/I18n/en_US.php | 8 + .../local/modules/LocalPickup/I18n/fr_FR.php | 8 + .../I18n/frontOffice/default/en_US.php | 8 + .../I18n/frontOffice/default/fr_FR.php | 8 + .../local/modules/LocalPickup/LICENSE.txt | 674 + .../Listener/UpdateDeliveryAddress.php | 109 + .../local/modules/LocalPickup/LocalPickup.php | 119 + .../modules/LocalPickup/Loop/LocalAddress.php | 132 + domokits/local/modules/LocalPickup/README.md | 101 + .../local/modules/LocalPickup/composer.json | 11 + .../default/module_configuration.html | 53 + .../email/default/order_shipping.html | 52 + .../email/default/order_shipping.txt | 0 .../default/localpickup/delivery-address.html | 5 + .../order-invoice-delivery-address.html | 25 + .../modules/OpenApi/Compiler/ModelPass.php | 32 + .../local/modules/OpenApi/Config/config.xml | 55 + .../local/modules/OpenApi/Config/module.xml | 43 + .../local/modules/OpenApi/Config/routing.xml | 31 + .../local/modules/OpenApi/Config/schema.xml | 29 + .../modules/OpenApi/Constraint/Length.php | 29 + .../modules/OpenApi/Constraint/NotBlank.php | 24 + .../modules/OpenApi/Constraint/NotNull.php | 24 + .../modules/OpenApi/Constraint/Zipcode.php | 17 + .../OpenApi/Constraint/ZipcodeValidator.php | 37 + .../Admin/BaseAdminOpenApiController.php | 16 + .../Admin/ConfigurationController.php | 45 + .../Controller/Front/AddressController.php | 268 + .../Controller/Front/AuthController.php | 147 + .../Front/BaseFrontOpenApiController.php | 16 + .../Controller/Front/CartController.php | 356 + .../Controller/Front/CategoryController.php | 147 + .../Controller/Front/CheckoutController.php | 318 + .../Controller/Front/ConfigController.php | 54 + .../Controller/Front/ContentController.php | 187 + .../Controller/Front/CouponController.php | 180 + .../Controller/Front/CustomerController.php | 230 + .../Controller/Front/DeliveryController.php | 403 + .../Controller/Front/FolderController.php | 147 + .../Controller/Front/PaymentController.php | 115 + .../Controller/Front/ProductController.php | 213 + .../OpenApi/Controller/OpenApiController.php | 56 + .../EventListener/ExceptionListener.php | 77 + .../OpenApi/EventListener/LogoutListener.php | 33 + .../OpenApi/EventListener/OrderListener.php | 58 + .../OpenApi/EventListener/RequestListener.php | 41 + .../Events/DeliveryModuleOptionEvent.php | 189 + .../OpenApi/Events/ModelExtendDataEvent.php | 101 + .../OpenApi/Events/ModelValidationEvent.php | 123 + .../modules/OpenApi/Events/OpenApiEvents.php | 8 + .../OpenApi/Exception/OpenApiException.php | 60 + .../local/modules/OpenApi/Form/ConfigForm.php | 28 + .../local/modules/OpenApi/Hook/BackHook.php | 17 + domokits/local/modules/OpenApi/I18n/en_US.php | 5 + domokits/local/modules/OpenApi/I18n/fr_FR.php | 11 + .../modules/OpenApi/Model/Api/Address.php | 638 + .../modules/OpenApi/Model/Api/Attribute.php | 103 + .../OpenApi/Model/Api/AttributeValue.php | 60 + .../OpenApi/Model/Api/BaseApiModel.php | 352 + .../local/modules/OpenApi/Model/Api/Brand.php | 74 + .../local/modules/OpenApi/Model/Api/Cart.php | 467 + .../modules/OpenApi/Model/Api/CartItem.php | 309 + .../modules/OpenApi/Model/Api/Category.php | 117 + .../modules/OpenApi/Model/Api/Checkout.php | 309 + .../OpenApi/Model/Api/CivilityTitle.php | 112 + .../modules/OpenApi/Model/Api/Content.php | 75 + .../modules/OpenApi/Model/Api/Coupon.php | 104 + .../modules/OpenApi/Model/Api/Customer.php | 381 + .../OpenApi/Model/Api/DeliveryModule.php | 214 + .../Model/Api/DeliveryModuleOption.php | 275 + .../modules/OpenApi/Model/Api/Document.php | 37 + .../local/modules/OpenApi/Model/Api/Error.php | 115 + .../modules/OpenApi/Model/Api/Feature.php | 91 + .../OpenApi/Model/Api/FeatureValue.php | 48 + .../local/modules/OpenApi/Model/Api/File.php | 131 + .../modules/OpenApi/Model/Api/Folder.php | 76 + .../local/modules/OpenApi/Model/Api/I18n.php | 211 + .../local/modules/OpenApi/Model/Api/Image.php | 35 + .../local/modules/OpenApi/Model/Api/Lang.php | 411 + .../OpenApi/Model/Api/ModelFactory.php | 61 + .../Model/Api/ModelTrait/translatable.php | 120 + .../OpenApi/Model/Api/PaymentModule.php | 192 + .../OpenApi/Model/Api/PickupLocation.php | 158 + .../local/modules/OpenApi/Model/Api/Price.php | 96 + .../modules/OpenApi/Model/Api/Product.php | 428 + .../OpenApi/Model/Api/ProductSaleElement.php | 502 + .../modules/OpenApi/Model/Api/Result.php | 100 + .../OpenApi/Model/Api/SchemaViolation.php | 43 + .../modules/OpenApi/Model/Api/Search.php | 133 + .../OpenApi/Normalizer/ModelApiNormalizer.php | 25 + domokits/local/modules/OpenApi/OpenApi.php | 69 + domokits/local/modules/OpenApi/Readme.md | 3 + .../OpenApi/Service/DocumentService.php | 62 + .../modules/OpenApi/Service/ImageService.php | 142 + .../OpenApi/Service/OpenApiService.php | 149 + .../modules/OpenApi/Service/SearchService.php | 88 + domokits/local/modules/OpenApi/composer.json | 13 + .../backOffice/default/configuration.html | 42 + .../frontOffice/default/swagger-ui.html | 22 + .../PayPal/.github/workflows/release.yml | 7 + .../modules/PayPal/Config/Update/3.0.2.sql | 234 + .../local/modules/PayPal/Config/config.xml | 123 + .../local/modules/PayPal/Config/create.sql | 195 + .../local/modules/PayPal/Config/module.xml | 28 + .../local/modules/PayPal/Config/routing.xml | 108 + .../local/modules/PayPal/Config/schema.xml | 133 + .../local/modules/PayPal/Config/sqldb.map | 2 + .../local/modules/PayPal/Config/thelia.sql | 210 + .../Controller/ConfigurationController.php | 119 + .../PayPalPlanifiedPaymentController.php | 356 + .../Controller/PayPalResponseController.php | 970 + .../Controller/PayPalWebHookController.php | 344 + .../modules/PayPal/Event/PayPalCartEvent.php | 66 + .../PayPal/Event/PayPalCustomerEvent.php | 66 + .../modules/PayPal/Event/PayPalEvents.php | 57 + .../modules/PayPal/Event/PayPalOrderEvent.php | 66 + .../modules/PayPal/Event/PayPalPlanEvent.php | 66 + .../Event/PayPalPlanifiedPaymentEvent.php | 66 + .../Form/TheliaOrderPaymentForm.php | 172 + .../PayPal/EventListeners/OrderListener.php | 273 + .../EventListeners/PayPalCartListener.php | 67 + .../EventListeners/PayPalCustomerListener.php | 87 + .../EventListeners/PayPalOrderListener.php | 68 + .../EventListeners/PayPalPlanListener.php | 63 + .../PayPalPlanifiedPaymentListener.php | 63 + .../modules/PayPal/Form/ConfigurationForm.php | 333 + .../modules/PayPal/Form/PayPalFormFields.php | 56 + .../Form/PayPalPlanifiedPaymentCreateForm.php | 194 + .../Form/PayPalPlanifiedPaymentUpdateForm.php | 56 + .../PayPal/Form/Type/PayPalCreditCardType.php | 247 + .../modules/PayPal/Hook/BackHookManager.php | 95 + .../modules/PayPal/Hook/FrontHookManager.php | 208 + .../modules/PayPal/Hook/PdfHookManager.php | 45 + .../PayPal/I18n/backOffice/default/fr_FR.php | 92 + domokits/local/modules/PayPal/I18n/en_US.php | 4 + domokits/local/modules/PayPal/I18n/fr_FR.php | 76 + .../PayPal/I18n/frontOffice/default/fr_FR.php | 12 + .../modules/PayPal/I18n/pdf/default/fr_FR.php | 10 + .../modules/PayPal/Loop/PayPalLogLoop.php | 154 + .../modules/PayPal/Loop/PayPalOrderLoop.php | 109 + .../Loop/PayPalPlanifiedPaymentLoop.php | 133 + .../local/modules/PayPal/Model/PaypalCart.php | 48 + .../modules/PayPal/Model/PaypalCartQuery.php | 21 + .../modules/PayPal/Model/PaypalCustomer.php | 52 + .../PayPal/Model/PaypalCustomerQuery.php | 21 + .../local/modules/PayPal/Model/PaypalLog.php | 10 + .../modules/PayPal/Model/PaypalLogQuery.php | 21 + .../modules/PayPal/Model/PaypalOrder.php | 48 + .../modules/PayPal/Model/PaypalOrderQuery.php | 21 + .../local/modules/PayPal/Model/PaypalPlan.php | 10 + .../modules/PayPal/Model/PaypalPlanQuery.php | 21 + .../PayPal/Model/PaypalPlanifiedPayment.php | 10 + .../Model/PaypalPlanifiedPaymentI18n.php | 10 + .../Model/PaypalPlanifiedPaymentI18nQuery.php | 21 + .../Model/PaypalPlanifiedPaymentQuery.php | 21 + domokits/local/modules/PayPal/PayPal.php | 382 + domokits/local/modules/PayPal/README.md | 56 + .../PayPal/Service/Base/PayPalBaseService.php | 414 + .../PayPal/Service/MyOwnSQLHandler.php | 30 + .../PayPal/Service/PayPalAgreementService.php | 953 + .../PayPal/Service/PayPalCustomerService.php | 164 + .../PayPal/Service/PayPalLoggerService.php | 128 + .../PayPal/Service/PayPalPaymentService.php | 417 + domokits/local/modules/PayPal/composer.json | 14 + domokits/local/modules/PayPal/images/logo.png | Bin 0 -> 4196 bytes .../modules/PayPal/images/payment_classic.png | Bin 0 -> 10828 bytes .../images/payment_classic_incontext.png | Bin 0 -> 139122 bytes .../PayPal/images/payment_credit_card.png | Bin 0 -> 41931 bytes .../images/payment_express_checkout.png | Bin 0 -> 117713 bytes .../PayPal/images/payment_recursive.png | Bin 0 -> 21604 bytes .../default/assets/paypal_agreement.jpeg | Bin 0 -> 7432 bytes .../default/assets/paypal_conf1.png | Bin 0 -> 17985 bytes .../default/assets/paypal_conf2.png | Bin 0 -> 26728 bytes .../default/assets/paypal_conf3.png | Bin 0 -> 19853 bytes .../default/assets/paypal_live_button.png | Bin 0 -> 6177 bytes .../default/assets/paypal_webhook.png | Bin 0 -> 17997 bytes ...eate-or-update-planified-payment-form.html | 38 + .../paypal/includes/paypal-log-row-js.html | 11 + .../paypal/includes/paypal-log-row.html | 20 + .../backOffice/default/paypal/menu/menu.html | 6 + .../default/paypal/module-configuration.html | 236 + .../default/paypal/order-edit-js.html | 1 + .../default/paypal/payment-information.html | 18 + .../backOffice/default/paypal/paypal-log.html | 105 + .../paypal/planified-payment-edit.html | 86 + .../default/paypal/planified-payment.html | 185 + .../default/paypal-payment-confirmation.html | 23 + .../default/paypal-payment-confirmation.txt | 9 + ...paypal-recursive-payment-confirmation.html | 23 + .../paypal-recursive-payment-confirmation.txt | 9 + .../frontOffice/default/assets/cards-logo.jpg | Bin 0 -> 13435 bytes .../default/assets/ntimes-cards-logo.png | Bin 0 -> 9334 bytes .../default/assets/paypal-logo.png | Bin 0 -> 4196 bytes .../default/paypal/cart-bottom.html | 11 + .../paypal/form/extra-credit-card.html | 85 + .../default/paypal/form/extra-paypal.html | 17 + .../paypal/form/extra-planified-payment.html | 26 + .../default/paypal/login-bottom.html | 16 + .../paypal/order-delivery-bottom-js.html | 7 + .../default/paypal/order-delivery-bottom.html | 4 + .../default/paypal/order-invoice-bottom.html | 11 + .../default/paypal/order-invoice-js.html | 58 + .../paypal/order-invoice-payment-extra.html | 21 + .../order-placed-additional-payment-info.html | 6 + .../default/paypal/after-payment-module.html | 6 + .../ProductLoopAttributeFilter/CHANGELOG.md | 3 + .../Config/config.xml | 7 + .../Config/module.xml | 43 + .../ProductLoopAttributeFilter/LICENSE | 21 + .../Listener/LoopProductListener.php | 79 + .../ProductLoopAttributeFilter.php | 44 + .../ProductLoopAttributeFilter/Readme.md | 43 + .../ProductLoopAttributeFilter/composer.json | 11 + .../ReCaptcha/Action/ReCaptchaAction.php | 56 + .../local/modules/ReCaptcha/Config/config.xml | 42 + .../local/modules/ReCaptcha/Config/module.xml | 41 + .../modules/ReCaptcha/Config/routing.xml | 15 + .../local/modules/ReCaptcha/Config/schema.xml | 30 + .../Controller/ConfigurationController.php | 52 + .../ReCaptcha/Event/ReCaptchaCheckEvent.php | 80 + .../ReCaptcha/Event/ReCaptchaEvents.php | 8 + .../ReCaptcha/Form/ConfigurationForm.php | 74 + .../modules/ReCaptcha/Hook/FrontHook.php | 59 + .../I18n/backOffice/default/fr_FR.php | 8 + .../local/modules/ReCaptcha/I18n/en_US.php | 4 + .../local/modules/ReCaptcha/I18n/fr_FR.php | 7 + domokits/local/modules/ReCaptcha/LICENSE | 21 + .../local/modules/ReCaptcha/ReCaptcha.php | 64 + domokits/local/modules/ReCaptcha/Readme.md | 62 + .../local/modules/ReCaptcha/composer.json | 12 + .../default/recaptcha/configuration.html | 72 + .../default/recaptcha-js-invisible.html | 56 + .../frontOffice/default/recaptcha-js.html | 23 + .../Command/ResetAllPasswordCommand.php | 86 + .../ResetPassword/Config/TheliaMain.sql | 50 + .../modules/ResetPassword/Config/config.xml | 42 + .../modules/ResetPassword/Config/module.xml | 43 + .../modules/ResetPassword/Config/routing.xml | 31 + .../modules/ResetPassword/Config/schema.xml | 48 + .../modules/ResetPassword/Config/sqldb.map | 0 .../ResetPassword/Config/update/1.0.1.sql | 26 + .../Front/ResetPasswordController.php | 52 + .../EventListener/LostPasswordListener.php | 39 + .../Form/Front/ResetPasswordAskForm.php | 19 + .../Form/Front/ResetPasswordForm.php | 59 + .../I18n/email/default/fr_FR.php | 16 + .../modules/ResetPassword/I18n/en_US.php | 15 + .../modules/ResetPassword/I18n/fr_FR.php | 15 + .../I18n/frontOffice/default/fr_FR.php | 7 + .../Model/CustomerForbiddenPassword.php | 19 + .../Model/CustomerForbiddenPasswordQuery.php | 19 + .../Model/PasswordResetToken.php | 19 + .../Model/PasswordResetTokenQuery.php | 19 + .../local/modules/ResetPassword/Readme.md | 13 + .../modules/ResetPassword/ResetPassword.php | 145 + .../Service/ResetPasswordService.php | 136 + .../local/modules/ResetPassword/composer.json | 12 + .../default/reset_all_password_message.html | 30 + .../email/default/reset_password_message.html | 30 + .../email/default/reset_password_message.txt | 10 + .../default/resetPassword/reset_password.html | 87 + .../RewriteUrl/.github/workflows/release.yml | 7 + .../AdminIncludes/brand-edit-js.html | 1 + .../RewriteUrl/AdminIncludes/brand-edit.html | 1 + .../AdminIncludes/category-edit-js.html | 1 + .../AdminIncludes/category-edit.html | 1 + .../AdminIncludes/content-edit-js.html | 1 + .../AdminIncludes/content-edit.html | 1 + .../AdminIncludes/folder-edit-js.html | 1 + .../RewriteUrl/AdminIncludes/folder-edit.html | 1 + .../AdminIncludes/product-edit-js.html | 1 + .../AdminIncludes/product-edit.html | 1 + .../modules/RewriteUrl/Config/config.xml | 38 + .../modules/RewriteUrl/Config/module.xml | 18 + .../modules/RewriteUrl/Config/routing.xml | 51 + .../modules/RewriteUrl/Config/schema.xml | 38 + .../modules/RewriteUrl/Config/thelia.sql | 62 + .../RewriteUrl/Config/update/1.4.8.sql | 22 + .../RewriteUrl/Config/update/1.5.0.sql | 45 + .../Admin/ModuleConfigController.php | 321 + .../Admin/NotRewritenUrlsAdminController.php | 39 + .../Admin/RewriteUrlAdminController.php | 480 + .../RewriteUrl/Event/RewriteUrlEvent.php | 211 + .../RewriteUrl/Event/RewriteUrlEvents.php | 26 + .../KernelExceptionListener.php | 69 + .../EventListeners/RewriteUrlListener.php | 161 + .../modules/RewriteUrl/Form/AddUrlForm.php | 87 + .../modules/RewriteUrl/Form/ReassignForm.php | 62 + .../RewriteUrl/Form/SetDefaultForm.php | 46 + .../RewriteUrl/Hook/ConfigurationHook.php | 72 + .../I18n/backOffice/default/fr_FR.php | 86 + .../local/modules/RewriteUrl/I18n/fr_FR.php | 19 + domokits/local/modules/RewriteUrl/LICENSE.txt | 165 + .../Loop/NotRewritenUrlCategoryLoop.php | 106 + .../RewriteUrl/Loop/RewriteUrlLoop.php | 104 + .../RewriteUrl/Loop/RewriteUrlRuleLoop.php | 83 + .../RewriteUrl/Model/RewriteurlRule.php | 104 + .../RewriteUrl/Model/RewriteurlRuleParam.php | 53 + .../Model/RewriteurlRuleParamQuery.php | 21 + .../RewriteUrl/Model/RewriteurlRuleQuery.php | 21 + .../Model/RewritingRedirectType.php | 16 + .../Model/RewritingRedirectTypeQuery.php | 21 + .../RewriteUrl/Model/RewritingUrlOverride.php | 35 + domokits/local/modules/RewriteUrl/Readme.md | 59 + .../local/modules/RewriteUrl/RewriteUrl.php | 130 + .../Service/RewritingRouterFirst.php | 150 + .../Service/RewritingRouterLast.php | 54 + .../local/modules/RewriteUrl/composer.json | 25 + domokits/local/modules/RewriteUrl/logo.jpg | Bin 0 -> 17459 bytes .../RewriteUrl/screenshot/screenshot-1.jpeg | Bin 0 -> 107388 bytes .../RewriteUrl/screenshot/screenshot-2.jpeg | Bin 0 -> 37334 bytes .../RewriteUrl/screenshot/screenshot-3.png | Bin 0 -> 123206 bytes .../RewriteUrl/module-configuration-js.html | 425 + .../RewriteUrl/module-configuration.html | 140 + .../default/RewriteUrl/tab-module-js.html | 188 + .../default/RewriteUrl/tab-module.html | 327 + .../default/RewriteUrl/tab-value-render.html | 44 + .../default/configuration-catalog.html | 6 + .../default/list-notrewritenurls.html | 425 + .../modules/ShortCode/Config/TheliaMain.sql | 25 + .../local/modules/ShortCode/Config/config.xml | 52 + .../local/modules/ShortCode/Config/module.xml | 43 + .../modules/ShortCode/Config/routing.xml | 31 + .../local/modules/ShortCode/Config/schema.xml | 17 + .../local/modules/ShortCode/Config/sqldb.map | 2 + .../ShortCode/Event/ShortCodeEvent.php | 60 + .../EventListener/ResponseListener.php | 95 + .../local/modules/ShortCode/I18n/en_US.php | 4 + .../local/modules/ShortCode/I18n/fr_FR.php | 4 + domokits/local/modules/ShortCode/LICENCE | 21 + .../modules/ShortCode/Model/ShortCode.php | 10 + .../ShortCode/Model/ShortCodeQuery.php | 21 + domokits/local/modules/ShortCode/Readme.md | 45 + .../local/modules/ShortCode/ShortCode.php | 89 + .../local/modules/ShortCode/composer.json | 12 + .../modules/ShortCodeMeta/Config/config.xml | 52 + .../modules/ShortCodeMeta/Config/module.xml | 40 + .../modules/ShortCodeMeta/Config/routing.xml | 31 + .../modules/ShortCodeMeta/Config/schema.xml | 30 + .../EventListener/ShortCodeListener.php | 45 + .../modules/ShortCodeMeta/I18n/en_US.php | 4 + .../modules/ShortCodeMeta/I18n/fr_FR.php | 4 + domokits/local/modules/ShortCodeMeta/LICENSE | 21 + .../local/modules/ShortCodeMeta/Readme.md | 54 + .../modules/ShortCodeMeta/ShortCodeMeta.php | 41 + .../Smarty/Plugins/ShortCodeMetaPlugin.php | 48 + .../local/modules/ShortCodeMeta/composer.json | 12 + .../default/short_code_meta_hook.html | 4 + .../SmartyRedirection/Config/config.xml | 12 + .../SmartyRedirection/Config/module.xml | 26 + .../modules/SmartyRedirection/LICENSE.txt | 165 + .../local/modules/SmartyRedirection/Readme.md | 39 + .../Smarty/Plugins/Redirect.php | 62 + .../SmartyRedirection/SmartyRedirection.php | 21 + .../modules/SmartyRedirection/composer.json | 11 + .../local/modules/StoreSeo/Config/config.xml | 17 + .../local/modules/StoreSeo/Config/module.xml | 26 + .../local/modules/StoreSeo/Config/routing.xml | 6 + .../Controller/StoreSeoConfigController.php | 97 + .../modules/StoreSeo/Form/StoreSeoForm.php | 38 + .../modules/StoreSeo/Hook/StoreSeoHook.php | 19 + .../I18n/backOffice/default/en_US.php | 9 + .../I18n/backOffice/default/fr_FR.php | 9 + .../local/modules/StoreSeo/I18n/en_US.php | 8 + .../local/modules/StoreSeo/I18n/fr_FR.php | 8 + domokits/local/modules/StoreSeo/Readme.md | 56 + .../Smarty/Plugins/StoreSeoPlugin.php | 48 + domokits/local/modules/StoreSeo/StoreSeo.php | 42 + domokits/local/modules/StoreSeo/composer.json | 11 + .../default/storeseo-configuration.html | 98 + .../Classes/StripePaymentException.php | 13 + .../Classes/StripePaymentLog.php | 60 + .../modules/StripePayment/Config/config.xml | 27 + .../modules/StripePayment/Config/module.xml | 24 + .../modules/StripePayment/Config/routing.xml | 30 + .../modules/StripePayment/Config/schema.xml | 5 + .../StripePaymentConfigController.php | 75 + .../Controller/StripePaymentController.php | 24 + .../Controller/StripeWebHooksController.php | 149 + .../EventListeners/CartEventListener.php | 212 + .../SendConfirmationEmailListener.php | 75 + .../Form/Base/StripePaymentConfigForm.php | 208 + .../Form/StripePaymentConfigForm.php | 33 + .../StripePayment/Hook/StripePaymentHook.php | 74 + .../I18n/backOffice/default/en_US.php | 12 + .../I18n/backOffice/default/fr_FR.php | 17 + .../I18n/email/default/en_US.php | 13 + .../I18n/email/default/fr_FR.php | 13 + .../modules/StripePayment/I18n/en_US.php | 21 + .../modules/StripePayment/I18n/fr_FR.php | 29 + .../I18n/frontOffice/default/fr_FR.php | 6 + .../local/modules/StripePayment/LICENSE.txt | 165 + .../local/modules/StripePayment/Readme.md | 43 + .../Resource/images/module/stripe.png | Bin 0 -> 58172 bytes .../modules/StripePayment/StripePayment.php | 529 + .../local/modules/StripePayment/composer.json | 12 + .../default/stripepayment-configuration.html | 174 + .../email/default/stripe_confirm_payment.html | 34 + .../email/default/stripe_confirm_payment.txt | 9 + .../frontOffice/default/assets/css/styles.css | 61 + .../js/order-invoice-after-js-include.html | 166 + .../default/assets/js/stripe-js.html | 29 + .../frontOffice/default/stripe-paiement.html | 16 + .../.github/workflows/npm-publish.yml | 24 + .../.github/workflows/release.yml | 7 + .../local/modules/TheliaBlocks/.gitignore | 3 + .../modules/TheliaBlocks/.husky/pre-commit | 4 + .../Command/ValidateJsonContent.php | 139 + .../TheliaBlocks/Config/TheliaMain.sql | 64 + .../modules/TheliaBlocks/Config/config.xml | 28 + .../modules/TheliaBlocks/Config/module.xml | 40 + .../modules/TheliaBlocks/Config/routing.xml | 7 + .../modules/TheliaBlocks/Config/schema.xml | 29 + .../modules/TheliaBlocks/Config/sqldb.map | 2 + .../TheliaBlocks/Config/update/1.0.1.sql | 24 + .../TheliaBlocks/Config/update/2.1.9.sql | 9 + .../Controller/Admin/BlockGroupController.php | 269 + .../Admin/ConfigurationController.php | 65 + .../Admin/ItemBlockGroupController.php | 123 + .../Controller/Front/BlockGroupController.php | 271 + .../Front/PreviewGroupController.php | 43 + .../EventListeners/ShortCodeListener.php | 164 + .../Hook/TheliaBlocksBackHook.php | 109 + .../Hook/TheliaBlocksMenuHook.php | 26 + .../local/modules/TheliaBlocks/I18n/en_US.php | 15 + .../local/modules/TheliaBlocks/I18n/fr_FR.php | 15 + .../modules/TheliaBlocks/Loop/BlockGroup.php | 122 + .../TheliaBlocks/Model/Api/BlockGroup.php | 270 + .../TheliaBlocks/Model/Api/ItemBlockGroup.php | 228 + .../modules/TheliaBlocks/Model/BlockGroup.php | 90 + .../TheliaBlocks/Model/BlockGroupI18n.php | 26 + .../Model/BlockGroupI18nQuery.php | 26 + .../TheliaBlocks/Model/BlockGroupQuery.php | 26 + .../TheliaBlocks/Model/ItemBlockGroup.php | 26 + .../Model/ItemBlockGroupQuery.php | 26 + domokits/local/modules/TheliaBlocks/Readme.md | 306 + .../Service/HtmlParserService.php | 447 + .../TheliaBlocks/Service/JsonBlockService.php | 44 + .../SmartyPlugin/JsonBlockRender.php | 44 + .../modules/TheliaBlocks/TheliaBlocks.php | 127 + .../local/modules/TheliaBlocks/composer.json | 21 + .../local/modules/TheliaBlocks/gulpfile.js | 17 + .../modules/TheliaBlocks/package-lock.json | 8238 ++++++++ .../local/modules/TheliaBlocks/package.json | 30 + .../default/hook-in-top-menu-item.html | 6 + .../default/item-configuration.html | 40 + .../backOffice/default/styles/styles.css | 178 + .../default/thelia-blocks-configuration.html | 29 + .../backOffice/default/thelia-blocks-css.html | 4 + .../thelia-blocks-item-configuration.html | 43 + .../backOffice/default/thelia-blocks-js.html | 22 + .../thelia-blocks-new-configuration.html | 29 + .../default/vendor/html-warning-KFAIZUTI.png | Bin 0 -> 39739 bytes .../backOffice/default/vendor/index.css | 8 + .../backOffice/default/vendor/index.css.map | 1 + .../backOffice/default/vendor/index.d.ts | 660 + .../backOffice/default/vendor/index.global.js | 367 + .../default/vendor/index.global.js.map | 1 + .../backOffice/default/vendor/index.js | 325 + .../backOffice/default/vendor/index.js.map | 1 + .../default/blocks/blockAccordion.html | 26 + .../default/blocks/blockButton.html | 1 + .../default/blocks/blockCategory.html | 25 + .../default/blocks/blockFullWidthImage.html | 16 + .../default/blocks/blockGroup.html | 22 + .../default/blocks/blockHighlight.html | 6 + .../frontOffice/default/blocks/blockList.html | 9 + .../default/blocks/blockProduct.html | 41 + .../frontOffice/default/blocks/blockRaw.html | 3 + .../default/blocks/blockSeparator.html | 5 + .../default/blocks/blockTable.html | 26 + .../frontOffice/default/blocks/blockText.html | 1 + .../default/blocks/blockTitle.html | 7 + .../default/blocks/blockVideo.html | 7 + .../default/blocks/multiColumns.html | 21 + .../default/blocks/rawBlockGroup.html | 1 + .../default/thelia-blocks-preview.html | 29 + .../modern/thelia-blocks-preview.html | 21 + .../.github/workflows/release.yml | 7 + .../local/modules/TheliaLibrary/.gitignore | 2 + .../modules/TheliaLibrary/.husky/pre-commit | 4 + .../ApiExtend/ProductApiListener.php | 72 + .../Command/ImageMigrateCommand.php | 122 + .../TheliaLibrary/Config/TheliaMain.sql | 120 + .../modules/TheliaLibrary/Config/config.xml | 55 + .../modules/TheliaLibrary/Config/module.xml | 43 + .../modules/TheliaLibrary/Config/routing.xml | 31 + .../modules/TheliaLibrary/Config/schema.xml | 57 + .../modules/TheliaLibrary/Config/sqldb.map | 2 + .../TheliaLibrary/Config/update/1.1.2.sql | 57 + .../Controller/Admin/ImageController.php | 197 + .../Controller/Admin/ImageTagController.php | 118 + .../Controller/Admin/ItemImageController.php | 198 + .../Controller/Admin/TagController.php | 216 + .../Controller/Front/ImageController.php | 75 + .../Front/LegacyImageController.php | 148 + .../Front/OpenApi/ImageController.php | 224 + .../Front/OpenApi/ItemImageController.php | 197 + .../modules/TheliaLibrary/Hook/BackHook.php | 31 + .../modules/TheliaLibrary/I18n/en_US.php | 15 + .../modules/TheliaLibrary/I18n/fr_FR.php | 15 + .../TheliaLibrary/Loop/LibraryImage.php | 145 + .../TheliaLibrary/Model/Api/LibraryImage.php | 233 + .../Model/Api/LibraryImageTag.php | 100 + .../Model/Api/LibraryItemImage.php | 213 + .../TheliaLibrary/Model/Api/LibraryTag.php | 101 + .../TheliaLibrary/Model/LibraryImage.php | 26 + .../TheliaLibrary/Model/LibraryImageI18n.php | 26 + .../Model/LibraryImageI18nQuery.php | 26 + .../TheliaLibrary/Model/LibraryImageQuery.php | 26 + .../TheliaLibrary/Model/LibraryImageTag.php | 26 + .../Model/LibraryImageTagQuery.php | 26 + .../TheliaLibrary/Model/LibraryItemImage.php | 65 + .../Model/LibraryItemImageQuery.php | 26 + .../TheliaLibrary/Model/LibraryTag.php | 26 + .../TheliaLibrary/Model/LibraryTagI18n.php | 26 + .../Model/LibraryTagI18nQuery.php | 26 + .../TheliaLibrary/Model/LibraryTagQuery.php | 26 + .../local/modules/TheliaLibrary/Readme.md | 15 + .../TheliaLibrary/Service/ImageService.php | 325 + .../Service/LibraryImageService.php | 172 + .../Service/LibraryImageTagService.php | 57 + .../Service/LibraryItemImageService.php | 148 + .../Service/LibraryTagService.php | 74 + .../modules/TheliaLibrary/TheliaLibrary.php | 89 + .../local/modules/TheliaLibrary/composer.json | 13 + .../local/modules/TheliaLibrary/gulpfile.js | 17 + .../modules/TheliaLibrary/package-lock.json | 8067 ++++++++ .../local/modules/TheliaLibrary/package.json | 23 + .../backOffice/default/item-edition.html | 10 + .../default/tb-plugin/import-plugin.html | 2 + .../default/tb-plugin/import-styles.html | 1 + .../default/tb-plugin/vendor/index.css | 488 + .../default/tb-plugin/vendor/index.css.map | 1 + .../default/tb-plugin/vendor/index.d.ts | 44 + .../default/tb-plugin/vendor/index.global.js | 16566 ++++++++++++++++ .../tb-plugin/vendor/index.global.js.map | 1 + .../default/tb-plugin/vendor/index.mjs | 13822 +++++++++++++ .../default/tb-plugin/vendor/index.mjs.map | 1 + .../default/blocks/blockImage.html | 14 + .../TheliaMigrateCountry/Config/config.xml | 27 + .../TheliaMigrateCountry/Config/module.xml | 26 + .../TheliaMigrateCountry/Config/routing.xml | 15 + .../Controller/MigrateController.php | 175 + .../EventListeners/MigrateCountryListener.php | 149 + .../Events/MigrateCountryEvent.php | 114 + .../Events/MigrateCountryEvents.php | 23 + .../Form/CountryStateMigrationForm.php | 51 + .../Form/Type/CountryStateMigrationType.php | 103 + .../I18n/backOffice/default/en_US.php | 41 + .../I18n/backOffice/default/fr_FR.php | 41 + .../I18n/backOffice/default/it_IT.php | 29 + .../I18n/backOffice/default/ru_RU.php | 41 + .../TheliaMigrateCountry/I18n/en_US.php | 18 + .../TheliaMigrateCountry/I18n/fr_FR.php | 18 + .../TheliaMigrateCountry/I18n/it_IT.php | 18 + .../TheliaMigrateCountry/I18n/ru_RU.php | 18 + .../modules/TheliaMigrateCountry/LICENSE.txt | 674 + .../modules/TheliaMigrateCountry/Readme.md | 18 + .../TheliaMigrateCountry.php | 37 + .../TheliaMigrateCountry/composer.json | 11 + .../configuration-shipping-bottom.html | 6 + .../backOffice/default/countries-migrate.html | 299 + .../local/modules/TheliaSmarty/CREDITS.md | 40 + .../Compiler/RegisterParserPluginPass.php | 47 + .../modules/TheliaSmarty/Config/config.xml | 74 + .../modules/TheliaSmarty/Config/module.xml | 28 + .../Events/ComponentRenderEvent.php | 107 + .../local/modules/TheliaSmarty/I18n/en_US.php | 31 + .../local/modules/TheliaSmarty/I18n/fr_FR.php | 31 + .../local/modules/TheliaSmarty/I18n/ru_RU.php | 30 + .../local/modules/TheliaSmarty/I18n/tr_TR.php | 31 + .../local/modules/TheliaSmarty/LICENSE.txt | 674 + domokits/local/modules/TheliaSmarty/Readme.md | 2 + .../Template/AbstractSmartyPlugin.php | 131 + .../Assets/EncoreModuleAssetsPathPackage.php | 34 + .../EncoreModuleAssetsVersionStrategy.php | 41 + .../Template/Assets/SmartyAssetsManager.php | 267 + .../Template/Assets/SmartyAssetsResolver.php | 315 + .../Components/AbstractSmartyComponent.php | 22 + .../Template/DataCollectorSmartyParser.php | 141 + .../Exception/SmartyPluginException.php | 22 + .../Template/Plugins/AdminUtilities.php | 188 + .../TheliaSmarty/Template/Plugins/Assets.php | 142 + .../TheliaSmarty/Template/Plugins/Cache.php | 143 + .../Template/Plugins/CartPostage.php | 261 + .../Template/Plugins/Component.php | 102 + .../Template/Plugins/DataAccessFunctions.php | 970 + .../TheliaSmarty/Template/Plugins/Encore.php | 254 + .../Template/Plugins/FlashMessage.php | 152 + .../TheliaSmarty/Template/Plugins/Form.php | 1040 + .../TheliaSmarty/Template/Plugins/Format.php | 508 + .../Template/Plugins/FrontUtils.php | 306 + .../TheliaSmarty/Template/Plugins/Hook.php | 495 + .../TheliaSmarty/Template/Plugins/Module.php | 107 + .../TheliaSmarty/Template/Plugins/Render.php | 169 + .../Template/Plugins/Security.php | 148 + .../Template/Plugins/TheliaLoop.php | 529 + .../Template/Plugins/Translation.php | 112 + .../TheliaSmarty/Template/Plugins/Type.php | 47 + .../Template/Plugins/UrlGenerator.php | 402 + .../Template/Plugins/VarDumper.php | 74 + .../TheliaSmarty/Template/SmartyHelper.php | 175 + .../TheliaSmarty/Template/SmartyParser.php | 651 + .../Template/SmartyPluginDescriptor.php | 89 + .../Template/SmartyPluginInterface.php | 17 + .../Plugin/Controller/TestController.php | 49 + .../Tests/Template/Plugin/FormTest.php | 187 + .../Tests/Template/Plugin/FormatTest.php | 228 + .../Tests/Template/Plugin/RenderTest.php | 80 + .../Template/Plugin/SmartyPluginTestCase.php | 124 + .../Tests/Template/Plugin/fixtures/test.html | 1 + .../Plugin/fixtures/testFormatMoney.html | 1 + .../Template/Plugin/fixtures/testMethod.html | 1 + .../Template/Plugin/fixtures/testParams.html | 1 + .../Plugin/fixtures/testQueryArray.html | 1 + .../Plugin/fixtures/testQueryString.html | 1 + .../Template/Plugin/fixtures/testRequest.html | 1 + .../Tests/Template/SmartyHelperTest.php | 128 + .../modules/TheliaSmarty/TheliaSmarty.php | 53 + .../local/modules/TheliaSmarty/composer.json | 11 + domokits/local/modules/Tinymce/CHANGELOG.md | 5 + .../local/modules/Tinymce/Config/config.xml | 25 + .../local/modules/Tinymce/Config/module.xml | 18 + .../local/modules/Tinymce/Config/routing.xml | 9 + .../Controller/ConfigureController.php | 115 + .../Tinymce/Form/ConfigurationForm.php | 153 + .../modules/Tinymce/Hook/HookManager.php | 30 + .../Tinymce/I18n/backOffice/default/de_DE.php | 15 + .../Tinymce/I18n/backOffice/default/en_US.php | 17 + .../Tinymce/I18n/backOffice/default/fr_FR.php | 27 + .../Tinymce/I18n/backOffice/default/ru_RU.php | 27 + .../Tinymce/I18n/backOffice/default/tr_TR.php | 17 + domokits/local/modules/Tinymce/I18n/en_US.php | 25 + domokits/local/modules/Tinymce/I18n/fr_FR.php | 25 + domokits/local/modules/Tinymce/I18n/it_IT.php | 16 + domokits/local/modules/Tinymce/I18n/ru_RU.php | 26 + domokits/local/modules/Tinymce/I18n/tr_TR.php | 25 + domokits/local/modules/Tinymce/LICENSE.txt | 674 + .../js/tinymce/filemanager/ajax_calls.php | 660 + .../js/tinymce/filemanager/config/.htaccess | 1 + .../js/tinymce/filemanager/config/config.php | 593 + .../js/tinymce/filemanager/css/style.css | 36 + .../js/tinymce/filemanager/dialog.php | 1262 ++ .../js/tinymce/filemanager/execute.php | 505 + .../js/tinymce/filemanager/force_download.php | 145 + .../filemanager/img/clipboard_apply.png | Bin 0 -> 189 bytes .../filemanager/img/clipboard_clear.png | Bin 0 -> 195 bytes .../js/tinymce/filemanager/img/copy.png | Bin 0 -> 238 bytes .../js/tinymce/filemanager/img/cut.png | Bin 0 -> 173 bytes .../js/tinymce/filemanager/img/date.png | Bin 0 -> 611 bytes .../js/tinymce/filemanager/img/dimension.png | Bin 0 -> 489 bytes .../js/tinymce/filemanager/img/down.png | Bin 0 -> 163 bytes .../js/tinymce/filemanager/img/download.png | Bin 0 -> 674 bytes .../js/tinymce/filemanager/img/duplicate.png | Bin 0 -> 245 bytes .../js/tinymce/filemanager/img/edit_img.png | Bin 0 -> 673 bytes .../js/tinymce/filemanager/img/file_edit.png | Bin 0 -> 764 bytes .../img/glyphicons-halflings-white.png | Bin 0 -> 8583 bytes .../filemanager/img/glyphicons-halflings.png | Bin 0 -> 15602 bytes .../js/tinymce/filemanager/img/ico/ac3.jpg | Bin 0 -> 1692 bytes .../js/tinymce/filemanager/img/ico/accdb.jpg | Bin 0 -> 2613 bytes .../js/tinymce/filemanager/img/ico/ade.jpg | Bin 0 -> 2290 bytes .../js/tinymce/filemanager/img/ico/adp.jpg | Bin 0 -> 2290 bytes .../js/tinymce/filemanager/img/ico/ai.jpg | Bin 0 -> 1776 bytes .../js/tinymce/filemanager/img/ico/aiff.jpg | Bin 0 -> 1717 bytes .../js/tinymce/filemanager/img/ico/avi.jpg | Bin 0 -> 1548 bytes .../js/tinymce/filemanager/img/ico/bmp.jpg | Bin 0 -> 1979 bytes .../js/tinymce/filemanager/img/ico/c4d.jpg | Bin 0 -> 6241 bytes .../js/tinymce/filemanager/img/ico/css.jpg | Bin 0 -> 1722 bytes .../js/tinymce/filemanager/img/ico/csv.jpg | Bin 0 -> 2558 bytes .../tinymce/filemanager/img/ico/default.jpg | Bin 0 -> 1723 bytes .../js/tinymce/filemanager/img/ico/dmg.jpg | Bin 0 -> 1579 bytes .../js/tinymce/filemanager/img/ico/doc.jpg | Bin 0 -> 2511 bytes .../js/tinymce/filemanager/img/ico/docx.jpg | Bin 0 -> 2511 bytes .../js/tinymce/filemanager/img/ico/dwg.jpg | Bin 0 -> 5457 bytes .../js/tinymce/filemanager/img/ico/dxf.jpg | Bin 0 -> 5419 bytes .../tinymce/filemanager/img/ico/favicon.ico | Bin 0 -> 1150 bytes .../js/tinymce/filemanager/img/ico/fla.jpg | Bin 0 -> 1859 bytes .../js/tinymce/filemanager/img/ico/flv.jpg | Bin 0 -> 1806 bytes .../js/tinymce/filemanager/img/ico/folder.png | Bin 0 -> 737 bytes .../filemanager/img/ico/folder_back.png | Bin 0 -> 1128 bytes .../js/tinymce/filemanager/img/ico/gif.jpg | Bin 0 -> 1979 bytes .../js/tinymce/filemanager/img/ico/gz.jpg | Bin 0 -> 1718 bytes .../js/tinymce/filemanager/img/ico/html.jpg | Bin 0 -> 2152 bytes .../js/tinymce/filemanager/img/ico/iso.jpg | Bin 0 -> 1496 bytes .../js/tinymce/filemanager/img/ico/jpeg.jpg | Bin 0 -> 1960 bytes .../js/tinymce/filemanager/img/ico/jpg.jpg | Bin 0 -> 1979 bytes .../js/tinymce/filemanager/img/ico/log.jpg | Bin 0 -> 1765 bytes .../js/tinymce/filemanager/img/ico/m4a.jpg | Bin 0 -> 1529 bytes .../js/tinymce/filemanager/img/ico/mdb.jpg | Bin 0 -> 2613 bytes .../js/tinymce/filemanager/img/ico/mid.jpg | Bin 0 -> 1630 bytes .../js/tinymce/filemanager/img/ico/mov.jpg | Bin 0 -> 1574 bytes .../js/tinymce/filemanager/img/ico/mp3.jpg | Bin 0 -> 1555 bytes .../js/tinymce/filemanager/img/ico/mp4.jpg | Bin 0 -> 1529 bytes .../js/tinymce/filemanager/img/ico/mpeg.jpg | Bin 0 -> 1589 bytes .../js/tinymce/filemanager/img/ico/mpg.jpg | Bin 0 -> 1532 bytes .../js/tinymce/filemanager/img/ico/odb.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/odf.jpg | Bin 0 -> 1760 bytes .../js/tinymce/filemanager/img/ico/odg.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/odp.jpg | Bin 0 -> 1760 bytes .../js/tinymce/filemanager/img/ico/ods.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/odt.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/ogg.jpg | Bin 0 -> 1557 bytes .../js/tinymce/filemanager/img/ico/otg.jpg | Bin 0 -> 1759 bytes .../js/tinymce/filemanager/img/ico/otp.jpg | Bin 0 -> 1870 bytes .../js/tinymce/filemanager/img/ico/ots.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/ott.jpg | Bin 0 -> 1748 bytes .../js/tinymce/filemanager/img/ico/pdf.jpg | Bin 0 -> 2050 bytes .../js/tinymce/filemanager/img/ico/png.jpg | Bin 0 -> 1979 bytes .../js/tinymce/filemanager/img/ico/ppt.jpg | Bin 0 -> 2386 bytes .../js/tinymce/filemanager/img/ico/pptx.jpg | Bin 0 -> 2479 bytes .../js/tinymce/filemanager/img/ico/psd.jpg | Bin 0 -> 2110 bytes .../js/tinymce/filemanager/img/ico/rar.jpg | Bin 0 -> 1718 bytes .../js/tinymce/filemanager/img/ico/rtf.jpg | Bin 0 -> 2511 bytes .../js/tinymce/filemanager/img/ico/skp.jpg | Bin 0 -> 6347 bytes .../js/tinymce/filemanager/img/ico/sql.jpg | Bin 0 -> 1695 bytes .../js/tinymce/filemanager/img/ico/stp.jpg | Bin 0 -> 5539 bytes .../js/tinymce/filemanager/img/ico/svg.jpg | Bin 0 -> 1979 bytes .../js/tinymce/filemanager/img/ico/tar.jpg | Bin 0 -> 1747 bytes .../js/tinymce/filemanager/img/ico/tiff.jpg | Bin 0 -> 1953 bytes .../js/tinymce/filemanager/img/ico/txt.jpg | Bin 0 -> 1765 bytes .../js/tinymce/filemanager/img/ico/vwx.jpg | Bin 0 -> 5463 bytes .../js/tinymce/filemanager/img/ico/wav.jpg | Bin 0 -> 1557 bytes .../js/tinymce/filemanager/img/ico/webm.jpg | Bin 0 -> 1548 bytes .../js/tinymce/filemanager/img/ico/wma.jpg | Bin 0 -> 1548 bytes .../js/tinymce/filemanager/img/ico/xhtml.jpg | Bin 0 -> 1920 bytes .../js/tinymce/filemanager/img/ico/xls.jpg | Bin 0 -> 2691 bytes .../js/tinymce/filemanager/img/ico/xlsx.jpg | Bin 0 -> 2539 bytes .../js/tinymce/filemanager/img/ico/xml.jpg | Bin 0 -> 1714 bytes .../js/tinymce/filemanager/img/ico/zip.jpg | Bin 0 -> 1718 bytes .../tinymce/filemanager/img/ico_dark/ac3.jpg | Bin 0 -> 3462 bytes .../filemanager/img/ico_dark/accdb.jpg | Bin 0 -> 4130 bytes .../tinymce/filemanager/img/ico_dark/ade.jpg | Bin 0 -> 4126 bytes .../tinymce/filemanager/img/ico_dark/adp.jpg | Bin 0 -> 4126 bytes .../tinymce/filemanager/img/ico_dark/ai.jpg | Bin 0 -> 3416 bytes .../tinymce/filemanager/img/ico_dark/aiff.jpg | Bin 0 -> 3454 bytes .../tinymce/filemanager/img/ico_dark/avi.jpg | Bin 0 -> 3461 bytes .../tinymce/filemanager/img/ico_dark/bmp.jpg | Bin 0 -> 3754 bytes .../tinymce/filemanager/img/ico_dark/css.jpg | Bin 0 -> 3444 bytes .../tinymce/filemanager/img/ico_dark/csv.jpg | Bin 0 -> 4189 bytes .../filemanager/img/ico_dark/default.jpg | Bin 0 -> 3783 bytes .../tinymce/filemanager/img/ico_dark/dmg.jpg | Bin 0 -> 3619 bytes .../tinymce/filemanager/img/ico_dark/doc.jpg | Bin 0 -> 4081 bytes .../tinymce/filemanager/img/ico_dark/docx.jpg | Bin 0 -> 4075 bytes .../filemanager/img/ico_dark/favicon.ico | Bin 0 -> 1150 bytes .../tinymce/filemanager/img/ico_dark/fla.jpg | Bin 0 -> 3608 bytes .../tinymce/filemanager/img/ico_dark/flv.jpg | Bin 0 -> 3572 bytes .../filemanager/img/ico_dark/folder.png | Bin 0 -> 535 bytes .../filemanager/img/ico_dark/folder_back.png | Bin 0 -> 1128 bytes .../tinymce/filemanager/img/ico_dark/gif.jpg | Bin 0 -> 3754 bytes .../tinymce/filemanager/img/ico_dark/gz.jpg | Bin 0 -> 3372 bytes .../tinymce/filemanager/img/ico_dark/html.jpg | Bin 0 -> 3719 bytes .../tinymce/filemanager/img/ico_dark/iso.jpg | Bin 0 -> 3576 bytes .../tinymce/filemanager/img/ico_dark/jpeg.jpg | Bin 0 -> 3700 bytes .../tinymce/filemanager/img/ico_dark/jpg.jpg | Bin 0 -> 3754 bytes .../tinymce/filemanager/img/ico_dark/log.jpg | Bin 0 -> 3804 bytes .../tinymce/filemanager/img/ico_dark/m4a.jpg | Bin 0 -> 3379 bytes .../tinymce/filemanager/img/ico_dark/mdb.jpg | Bin 0 -> 4130 bytes .../tinymce/filemanager/img/ico_dark/mid.jpg | Bin 0 -> 3383 bytes .../tinymce/filemanager/img/ico_dark/mov.jpg | Bin 0 -> 3439 bytes .../tinymce/filemanager/img/ico_dark/mp3.jpg | Bin 0 -> 3335 bytes .../tinymce/filemanager/img/ico_dark/mp4.jpg | Bin 0 -> 3415 bytes .../tinymce/filemanager/img/ico_dark/mpeg.jpg | Bin 0 -> 3470 bytes .../tinymce/filemanager/img/ico_dark/mpg.jpg | Bin 0 -> 3459 bytes .../tinymce/filemanager/img/ico_dark/odb.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/odf.jpg | Bin 0 -> 3590 bytes .../tinymce/filemanager/img/ico_dark/odg.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/odp.jpg | Bin 0 -> 3590 bytes .../tinymce/filemanager/img/ico_dark/ods.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/odt.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/ogg.jpg | Bin 0 -> 3440 bytes .../tinymce/filemanager/img/ico_dark/otg.jpg | Bin 0 -> 3561 bytes .../tinymce/filemanager/img/ico_dark/otp.jpg | Bin 0 -> 3559 bytes .../tinymce/filemanager/img/ico_dark/ots.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/ott.jpg | Bin 0 -> 3581 bytes .../tinymce/filemanager/img/ico_dark/pdf.jpg | Bin 0 -> 3705 bytes .../tinymce/filemanager/img/ico_dark/png.jpg | Bin 0 -> 3754 bytes .../tinymce/filemanager/img/ico_dark/ppt.jpg | Bin 0 -> 4035 bytes .../tinymce/filemanager/img/ico_dark/pptx.jpg | Bin 0 -> 4089 bytes .../tinymce/filemanager/img/ico_dark/psd.jpg | Bin 0 -> 3859 bytes .../tinymce/filemanager/img/ico_dark/rar.jpg | Bin 0 -> 3387 bytes .../tinymce/filemanager/img/ico_dark/rtf.jpg | Bin 0 -> 4081 bytes .../tinymce/filemanager/img/ico_dark/sql.jpg | Bin 0 -> 3766 bytes .../tinymce/filemanager/img/ico_dark/svg.jpg | Bin 0 -> 3754 bytes .../tinymce/filemanager/img/ico_dark/tar.jpg | Bin 0 -> 3346 bytes .../tinymce/filemanager/img/ico_dark/tiff.jpg | Bin 0 -> 3798 bytes .../tinymce/filemanager/img/ico_dark/txt.jpg | Bin 0 -> 3804 bytes .../tinymce/filemanager/img/ico_dark/wav.jpg | Bin 0 -> 3440 bytes .../tinymce/filemanager/img/ico_dark/webm.jpg | Bin 0 -> 3476 bytes .../tinymce/filemanager/img/ico_dark/wma.jpg | Bin 0 -> 3461 bytes .../filemanager/img/ico_dark/xhtml.jpg | Bin 0 -> 3653 bytes .../tinymce/filemanager/img/ico_dark/xls.jpg | Bin 0 -> 4183 bytes .../tinymce/filemanager/img/ico_dark/xlsx.jpg | Bin 0 -> 4250 bytes .../tinymce/filemanager/img/ico_dark/xml.jpg | Bin 0 -> 3774 bytes .../tinymce/filemanager/img/ico_dark/zip.jpg | Bin 0 -> 3372 bytes .../js/tinymce/filemanager/img/info.png | Bin 0 -> 345 bytes .../js/tinymce/filemanager/img/key.png | Bin 0 -> 185 bytes .../js/tinymce/filemanager/img/label.png | Bin 0 -> 479 bytes .../js/tinymce/filemanager/img/loading.gif | Bin 0 -> 1688 bytes .../js/tinymce/filemanager/img/logo.png | Bin 0 -> 24774 bytes .../js/tinymce/filemanager/img/preview.png | Bin 0 -> 376 bytes .../js/tinymce/filemanager/img/processing.gif | Bin 0 -> 3209 bytes .../js/tinymce/filemanager/img/rename.png | Bin 0 -> 262 bytes .../js/tinymce/filemanager/img/size.png | Bin 0 -> 660 bytes .../js/tinymce/filemanager/img/sort.png | Bin 0 -> 584 bytes .../filemanager/img/storing_animation.gif | Bin 0 -> 3887 bytes .../js/tinymce/filemanager/img/trans.jpg | Bin 0 -> 4024 bytes .../js/tinymce/filemanager/img/up.png | Bin 0 -> 163 bytes .../js/tinymce/filemanager/img/upload.png | Bin 0 -> 324 bytes .../js/tinymce/filemanager/img/url.png | Bin 0 -> 593 bytes .../js/tinymce/filemanager/img/zip.png | Bin 0 -> 819 bytes .../tinymce/filemanager/include/FtpClient.php | 895 + .../filemanager/include/FtpException.php | 24 + .../filemanager/include/FtpWrapper.php | 119 + .../tinymce/filemanager/include/Response.php | 364 + .../tinymce/filemanager/include/ftp_class.php | 96 + .../filemanager/include/mime_type_lib.php | 323 + .../include/php_image_magician.php | 3273 +++ .../js/tinymce/filemanager/include/utils.php | 1038 + .../tinymce/filemanager/js/ZeroClipboard.swf | Bin 0 -> 4036 bytes .../js/tinymce/filemanager/js/include.js | 2 + .../filemanager/js/jPlayer/MIT-LICENSE.txt | 21 + .../tinymce/filemanager/js/jPlayer/README.md | 32 + .../js/jPlayer/actionscript/Jplayer.as | 638 + .../js/jPlayer/actionscript/Jplayer.fla | Bin 0 -> 61952 bytes .../happyworm/jPlayer/ConnectManager.as | 295 + .../happyworm/jPlayer/JplayerEvent.as | 68 + .../happyworm/jPlayer/JplayerMp3.as | 367 + .../happyworm/jPlayer/JplayerMp4.as | 412 + .../happyworm/jPlayer/JplayerRtmp.as | 983 + .../happyworm/jPlayer/JplayerStatus.as | 110 + .../happyworm/jPlayer/TraceOut.as | 62 + .../js/jPlayer/add-on/jplayer.playlist.js | 496 + .../js/jPlayer/add-on/jplayer.playlist.min.js | 2 + .../add-on/jquery.jplayer.inspector.js | 338 + .../add-on/jquery.jplayer.inspector.min.js | 2 + .../js/jPlayer/jplayer.jquery.json | 33 + .../js/jPlayer/jplayer/jquery.jplayer.js | 3506 ++++ .../js/jPlayer/jplayer/jquery.jplayer.min.js | 3 + .../js/jPlayer/jplayer/jquery.jplayer.swf | Bin 0 -> 13714 bytes .../js/jPlayer/jquery.jplayer/Jplayer.swf | Bin 0 -> 14085 bytes .../jPlayer/jquery.jplayer/jquery.jplayer.js | 2840 +++ .../filemanager/js/jPlayer/package.json | 27 + .../js/jPlayer/popcorn/popcorn.jplayer.js | 579 + .../js/jPlayer/popcorn/popcorn.jplayer.min.js | 2 + .../blue.monday/css/jplayer.blue.monday.css | 551 + .../css/jplayer.blue.monday.min.css | 1 + .../blue.monday/image/jplayer.blue.monday.jpg | Bin 0 -> 23189 bytes .../image/jplayer.blue.monday.seeking.gif | Bin 0 -> 3284 bytes .../image/jplayer.blue.monday.video.play.png | Bin 0 -> 17692 bytes .../skin/blue.monday/jplayer.blue.monday.css | 640 + .../skin/blue.monday/jplayer.blue.monday.jpg | Bin 0 -> 23189 bytes .../jplayer.blue.monday.seeking.gif | Bin 0 -> 3284 bytes .../jplayer.blue.monday.video.play.png | Bin 0 -> 17692 bytes .../jplayer.blue.monday.audio.playlist.html | 42 + .../jplayer.blue.monday.audio.single.html | 37 + .../jplayer.blue.monday.audio.stream.html | 24 + .../jplayer.blue.monday.video.playlist.html | 52 + .../jplayer.blue.monday.video.single.html | 43 + .../jPlayer/skin/blue.monday/skin.handlebars | 40 + .../skin/pink.flag/css/jplayer.pink.flag.css | 572 + .../pink.flag/css/jplayer.pink.flag.min.css | 1 + .../pink.flag/image/jplayer.pink.flag.jpg | Bin 0 -> 18426 bytes .../image/jplayer.pink.flag.seeking.gif | Bin 0 -> 3284 bytes .../image/jplayer.pink.flag.video.play.png | Bin 0 -> 17692 bytes .../jplayer.pink.flag.audio.playlist.html | 42 + .../jplayer.pink.flag.audio.single.html | 37 + .../jplayer.pink.flag.audio.stream.html | 24 + .../jplayer.pink.flag.video.playlist.html | 52 + .../jplayer.pink.flag.video.single.html | 43 + .../blue.monday/jplayer.blue.monday.css | 640 + .../blue.monday/jplayer.blue.monday.jpg | Bin 0 -> 23189 bytes .../jplayer.blue.monday.seeking.gif | Bin 0 -> 3284 bytes .../jplayer.blue.monday.video.play.png | Bin 0 -> 17692 bytes .../skin_ol/blue.monday/skin.handlebars | 40 + .../skin_ol/pink.flag/jplayer.pink.flag.css | 670 + .../skin_ol/pink.flag/jplayer.pink.flag.jpg | Bin 0 -> 18426 bytes .../pink.flag/jplayer.pink.flag.seeking.gif | Bin 0 -> 3284 bytes .../jplayer.pink.flag.video.play.png | Bin 0 -> 17692 bytes .../filemanager/js/modernizr.custom.js | 1 + .../js/tinymce/filemanager/js/plugins.js | 12 + .../js/tinymce/filemanager/lang/az_AZ.php | 132 + .../js/tinymce/filemanager/lang/bg_BG.php | 132 + .../js/tinymce/filemanager/lang/ca.php | 132 + .../js/tinymce/filemanager/lang/cs.php | 132 + .../js/tinymce/filemanager/lang/da.php | 132 + .../js/tinymce/filemanager/lang/de.php | 132 + .../js/tinymce/filemanager/lang/el_GR.php | 132 + .../js/tinymce/filemanager/lang/en_EN.php | 132 + .../js/tinymce/filemanager/lang/es.php | 132 + .../js/tinymce/filemanager/lang/fa.php | 131 + .../js/tinymce/filemanager/lang/fr_FR.php | 132 + .../js/tinymce/filemanager/lang/he_IL.php | 132 + .../js/tinymce/filemanager/lang/hr.php | 132 + .../js/tinymce/filemanager/lang/hu_HU.php | 132 + .../js/tinymce/filemanager/lang/id.php | 132 + .../js/tinymce/filemanager/lang/it.php | 132 + .../js/tinymce/filemanager/lang/ja.php | 132 + .../js/tinymce/filemanager/lang/languages.php | 49 + .../js/tinymce/filemanager/lang/lt.php | 132 + .../js/tinymce/filemanager/lang/mn_MN.php | 132 + .../js/tinymce/filemanager/lang/nb_NO.php | 132 + .../js/tinymce/filemanager/lang/nl.php | 132 + .../js/tinymce/filemanager/lang/pl.php | 132 + .../js/tinymce/filemanager/lang/pt_BR.php | 132 + .../js/tinymce/filemanager/lang/pt_PT.php | 132 + .../js/tinymce/filemanager/lang/ro.php | 132 + .../js/tinymce/filemanager/lang/ru.php | 131 + .../js/tinymce/filemanager/lang/sk.php | 132 + .../js/tinymce/filemanager/lang/sl.php | 132 + .../js/tinymce/filemanager/lang/sv_SE.php | 132 + .../js/tinymce/filemanager/lang/tr_TR.php | 132 + .../js/tinymce/filemanager/lang/uk_UA.php | 132 + .../js/tinymce/filemanager/lang/vi.php | 132 + .../js/tinymce/filemanager/lang/zh_CN.php | 132 + .../js/tinymce/filemanager/plugin.min.js | 1 + .../js/tinymce/filemanager/upload.php | 267 + .../js/tinymce/filemanager/uploader/index.php | 154 + .../tinymce/filemanager/uploader/jupload.php | 805 + .../tinymce/filemanager/uploader/success.jpg | Bin 0 -> 6344 bytes .../tinymce/filemanager/uploader/success.php | 19 + .../filemanager/uploader/wjhk.jupload.jar | Bin 0 -> 343591 bytes .../Tinymce/Resources/js/tinymce/langs/cs.js | 197 + .../Tinymce/Resources/js/tinymce/langs/de.js | 197 + .../Tinymce/Resources/js/tinymce/langs/es.js | 197 + .../Resources/js/tinymce/langs/fr_FR.js | 197 + .../Tinymce/Resources/js/tinymce/langs/it.js | 197 + .../Resources/js/tinymce/langs/readme.md | 3 + .../Tinymce/Resources/js/tinymce/langs/ru.js | 197 + .../Tinymce/Resources/js/tinymce/license.txt | 502 + .../js/tinymce/plugins/advlist/plugin.min.js | 1 + .../js/tinymce/plugins/anchor/plugin.min.js | 1 + .../js/tinymce/plugins/autolink/plugin.min.js | 1 + .../tinymce/plugins/autoresize/plugin.min.js | 1 + .../js/tinymce/plugins/autosave/plugin.min.js | 1 + .../js/tinymce/plugins/bbcode/plugin.min.js | 1 + .../js/tinymce/plugins/charmap/plugin.min.js | 1 + .../js/tinymce/plugins/code/plugin.min.js | 1 + .../tinymce/plugins/codesample/css/prism.css | 138 + .../tinymce/plugins/codesample/plugin.min.js | 1 + .../tinymce/plugins/colorpicker/plugin.min.js | 1 + .../tinymce/plugins/contextmenu/plugin.min.js | 1 + .../plugins/directionality/plugin.min.js | 1 + .../plugins/emoticons/img/smiley-cool.gif | Bin 0 -> 354 bytes .../plugins/emoticons/img/smiley-cry.gif | Bin 0 -> 329 bytes .../emoticons/img/smiley-embarassed.gif | Bin 0 -> 331 bytes .../emoticons/img/smiley-foot-in-mouth.gif | Bin 0 -> 342 bytes .../plugins/emoticons/img/smiley-frown.gif | Bin 0 -> 340 bytes .../plugins/emoticons/img/smiley-innocent.gif | Bin 0 -> 336 bytes .../plugins/emoticons/img/smiley-kiss.gif | Bin 0 -> 338 bytes .../plugins/emoticons/img/smiley-laughing.gif | Bin 0 -> 343 bytes .../emoticons/img/smiley-money-mouth.gif | Bin 0 -> 321 bytes .../plugins/emoticons/img/smiley-sealed.gif | Bin 0 -> 323 bytes .../plugins/emoticons/img/smiley-smile.gif | Bin 0 -> 344 bytes .../emoticons/img/smiley-surprised.gif | Bin 0 -> 338 bytes .../emoticons/img/smiley-tongue-out.gif | Bin 0 -> 328 bytes .../emoticons/img/smiley-undecided.gif | Bin 0 -> 337 bytes .../plugins/emoticons/img/smiley-wink.gif | Bin 0 -> 350 bytes .../plugins/emoticons/img/smiley-yell.gif | Bin 0 -> 336 bytes .../tinymce/plugins/emoticons/plugin.min.js | 1 + .../js/tinymce/plugins/example/dialog.html | 8 + .../js/tinymce/plugins/example/plugin.min.js | 1 + .../plugins/example_dependency/plugin.min.js | 1 + .../js/tinymce/plugins/fullpage/plugin.min.js | 1 + .../tinymce/plugins/fullscreen/plugin.min.js | 1 + .../js/tinymce/plugins/hr/plugin.min.js | 1 + .../js/tinymce/plugins/image/plugin.min.js | 1 + .../tinymce/plugins/imagetools/plugin.min.js | 1 + .../tinymce/plugins/importcss/plugin.min.js | 1 + .../plugins/insertdatetime/plugin.min.js | 1 + .../js/tinymce/plugins/layer/plugin.min.js | 1 + .../plugins/legacyoutput/plugin.min.js | 1 + .../js/tinymce/plugins/link/plugin.min.js | 1 + .../js/tinymce/plugins/lists/plugin.min.js | 1 + .../js/tinymce/plugins/media/moxieplayer.swf | Bin 0 -> 20017 bytes .../js/tinymce/plugins/media/plugin.min.js | 1 + .../tinymce/plugins/nonbreaking/plugin.min.js | 1 + .../tinymce/plugins/noneditable/plugin.min.js | 1 + .../tinymce/plugins/pagebreak/plugin.min.js | 1 + .../js/tinymce/plugins/paste/plugin.min.js | 1 + .../js/tinymce/plugins/preview/plugin.min.js | 1 + .../js/tinymce/plugins/print/plugin.min.js | 1 + .../responsivefilemanager/editor_plugin.js | 126 + .../responsivefilemanager/img/insertfile.gif | Bin 0 -> 3325 bytes .../plugins/responsivefilemanager/plugin.js | 79 + .../responsivefilemanager/plugin.min.js | 9 + .../js/tinymce/plugins/save/plugin.min.js | 1 + .../plugins/searchreplace/plugin.min.js | 1 + .../plugins/spellchecker/plugin.min.js | 1 + .../js/tinymce/plugins/tabfocus/plugin.min.js | 1 + .../js/tinymce/plugins/table/plugin.min.js | 2 + .../js/tinymce/plugins/template/plugin.min.js | 1 + .../tinymce/plugins/textcolor/plugin.min.js | 1 + .../tinymce/plugins/textpattern/plugin.min.js | 1 + .../plugins/visualblocks/css/visualblocks.css | 135 + .../plugins/visualblocks/plugin.min.js | 1 + .../tinymce/plugins/visualchars/plugin.min.js | 1 + .../tinymce/plugins/wordcount/plugin.min.js | 1 + .../js/tinymce/plugins/youtube/README.md | 78 + .../js/tinymce/plugins/youtube/css/styles.css | 9 + .../youtube/img/Google-YouTube-128.png | Bin 0 -> 11800 bytes .../tinymce/plugins/youtube/img/youtube.gif | Bin 0 -> 212 bytes .../js/tinymce/plugins/youtube/js/main.js | 807 + .../plugins/youtube/js/vendor/jquery.js | 6 + .../js/tinymce/plugins/youtube/langs/de.js | 10 + .../js/tinymce/plugins/youtube/langs/en.js | 12 + .../js/tinymce/plugins/youtube/langs/es.js | 10 + .../js/tinymce/plugins/youtube/langs/fr_FR.js | 12 + .../js/tinymce/plugins/youtube/langs/hu.js | 10 + .../js/tinymce/plugins/youtube/langs/it.js | 10 + .../js/tinymce/plugins/youtube/langs/pl.js | 10 + .../js/tinymce/plugins/youtube/langs/pt_BR.js | 10 + .../js/tinymce/plugins/youtube/langs/ru.js | 10 + .../js/tinymce/plugins/youtube/plugin.js | 51 + .../js/tinymce/plugins/youtube/plugin.min.js | 22 + .../tinymce/plugins/youtube/view/forms.html | 65 + .../js/tinymce/plugins/youtube/youtube.html | 20 + .../skins/lightgray/content.inline.min.css | 154 + .../tinymce/skins/lightgray/content.min.css | 1 + .../skins/lightgray/fonts/tinymce-small.eot | Bin 0 -> 9492 bytes .../skins/lightgray/fonts/tinymce-small.svg | 63 + .../skins/lightgray/fonts/tinymce-small.ttf | Bin 0 -> 9304 bytes .../skins/lightgray/fonts/tinymce-small.woff | Bin 0 -> 9380 bytes .../tinymce/skins/lightgray/fonts/tinymce.eot | Bin 0 -> 14308 bytes .../tinymce/skins/lightgray/fonts/tinymce.svg | 98 + .../tinymce/skins/lightgray/fonts/tinymce.ttf | Bin 0 -> 14144 bytes .../skins/lightgray/fonts/tinymce.woff | Bin 0 -> 14220 bytes .../js/tinymce/skins/lightgray/img/anchor.gif | Bin 0 -> 53 bytes .../js/tinymce/skins/lightgray/img/loader.gif | Bin 0 -> 2608 bytes .../js/tinymce/skins/lightgray/img/object.gif | Bin 0 -> 152 bytes .../js/tinymce/skins/lightgray/img/trans.gif | Bin 0 -> 43 bytes .../tinymce/skins/lightgray/skin.ie7.min.css | 1 + .../js/tinymce/skins/lightgray/skin.min.css | 1 + .../js/tinymce/themes/modern/theme.min.js | 1 + .../Resources/js/tinymce/tinymce.min.js | 13 + .../Tinymce/Smarty/TinyMCELanguage.php | 73 + domokits/local/modules/Tinymce/Tinymce.php | 99 + domokits/local/modules/Tinymce/composer.json | 11 + .../backOffice/default/assets/css/editor.less | 6 + .../default/module_configuration.html | 106 + .../backOffice/default/tinymce_init.tpl | 123 + .../.github/workflows/release.yml | 7 + .../modules/UrlSanitizer/Config/config.xml | 13 + .../modules/UrlSanitizer/Config/module.xml | 22 + .../modules/UrlSanitizer/Config/routing.xml | 7 + .../modules/UrlSanitizer/Config/schema.xml | 7 + .../Controller/ConfigurationController.php | 59 + .../EventListener/RewriteUrlListener.php | 39 + .../UrlSanitizer/Form/ConfigurationForm.php | 21 + .../I18n/backOffice/default/fr_FR.php | 9 + domokits/local/modules/UrlSanitizer/Readme.md | 19 + .../Service/UrlSanitizerService.php | 223 + .../modules/UrlSanitizer/UrlSanitizer.php | 25 + .../local/modules/UrlSanitizer/composer.json | 15 + .../UrlSanitizer/module-configuration.html | 39 + .../VirtualProductControl/Config/config.xml | 15 + .../VirtualProductControl/Config/module.xml | 20 + .../Hook/VirtualProductHook.php | 62 + .../I18n/backOffice/default/de_DE.php | 15 + .../I18n/backOffice/default/en_US.php | 15 + .../I18n/backOffice/default/fr_FR.php | 15 + .../I18n/backOffice/default/it_IT.php | 15 + .../I18n/backOffice/default/tr_TR.php | 15 + .../VirtualProductControl/I18n/de_DE.php | 15 + .../VirtualProductControl/I18n/en_US.php | 15 + .../VirtualProductControl/I18n/fr_FR.php | 15 + .../VirtualProductControl/I18n/it_IT.php | 15 + .../VirtualProductControl/I18n/ru_RU.php | 15 + .../VirtualProductControl/I18n/tr_TR.php | 15 + .../modules/VirtualProductControl/LICENSE.txt | 674 + .../VirtualProductControl.php | 19 + .../VirtualProductControl/composer.json | 11 + .../default/virtual-delivery-warning.html | 7 + .../VirtualProductDelivery/Config/config.xml | 27 + .../VirtualProductDelivery/Config/module.xml | 24 + .../EventListeners/SendMail.php | 120 + .../EventListeners/VirtualProductEvents.php | 111 + .../Events/VirtualProductDeliveryEvents.php | 25 + .../Hook/HookManager.php | 39 + .../VirtualProductDelivery/I18n/de_DE.php | 18 + .../I18n/email/default/en_US.php | 20 + .../I18n/email/default/fr_FR.php | 20 + .../I18n/email/default/it_IT.php | 20 + .../I18n/email/default/ru_RU.php | 19 + .../I18n/email/default/tr_TR.php | 20 + .../VirtualProductDelivery/I18n/en_US.php | 18 + .../VirtualProductDelivery/I18n/fr_FR.php | 18 + .../I18n/frontOffice/default/de_DE.php | 19 + .../I18n/frontOffice/default/en_US.php | 19 + .../I18n/frontOffice/default/fr_FR.php | 19 + .../I18n/frontOffice/default/it_IT.php | 18 + .../I18n/frontOffice/default/ru_RU.php | 19 + .../I18n/frontOffice/default/tr_TR.php | 19 + .../VirtualProductDelivery/I18n/it_IT.php | 17 + .../I18n/pdf/default/de_DE.php | 15 + .../I18n/pdf/default/en_US.php | 15 + .../I18n/pdf/default/fr_FR.php | 15 + .../I18n/pdf/default/it_IT.php | 15 + .../I18n/pdf/default/ru_RU.php | 15 + .../I18n/pdf/default/tr_TR.php | 15 + .../VirtualProductDelivery/I18n/ru_RU.php | 18 + .../VirtualProductDelivery/I18n/tr_TR.php | 18 + .../VirtualProductDelivery/LICENSE.txt | 674 + .../VirtualProductDelivery.php | 105 + .../VirtualProductDelivery/composer.json | 11 + .../default/virtual-product-download.html | 29 + .../default/virtual-product-download.txt | 26 + .../default/account-order-after-products.html | 24 + .../frontOffice/default/delivery-address.html | 6 + .../pdf/default/delivery-address.html | 3 + .../modules/WebProfiler/Config/config.xml | 50 + .../modules/WebProfiler/Config/config_dev.xml | 50 + .../WebProfiler/Config/config_prod.xml | 50 + .../WebProfiler/Config/config_test.xml | 50 + .../modules/WebProfiler/Config/module.xml | 43 + .../modules/WebProfiler/Config/routing.xml | 31 + .../modules/WebProfiler/Config/schema.xml | 25 + .../DataCollector/SmartyDataCollector.php | 58 + .../DataCollector/TheliaCollector.php | 38 + .../local/modules/WebProfiler/I18n/en_US.php | 15 + .../local/modules/WebProfiler/I18n/fr_FR.php | 15 + domokits/local/modules/WebProfiler/Readme.md | 55 + .../local/modules/WebProfiler/WebProfiler.php | 62 + .../local/modules/WebProfiler/composer.json | 12 + .../WebProfilerBundle/Profiler/base.html.twig | 25 + .../Profiler/header.html.twig | 5 + .../debug/dataCollector/Icon/smarty.svg | 48 + .../debug/dataCollector/Icon/smartyColor.svg | 72 + .../debug/dataCollector/Icon/thelia.svg | 66 + .../debug/dataCollector/Icon/theliaWhite.svg | 41 + .../debug/dataCollector/smarty.html.twig | 94 + .../debug/dataCollector/thelia.html.twig | 12 + .../templates/frontOffice/custom/Gruntfile.js | 9 +- .../custom/assets/dist/css/thelia.min.css | 4 +- .../custom/assets/src/css/custom.css | 11 + .../custom/assets/src/css/thelia.css | 170 +- .../frontOffice/custom/category.html | 5 +- .../templates/frontOffice/custom/layout.tpl | 5 +- 1626 files changed, 171457 insertions(+), 131 deletions(-) create mode 100644 domokits/local/modules/BetterSeo/.github/workflows/release.yml create mode 100644 domokits/local/modules/BetterSeo/BetterSeo.php create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.1.0.sql create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.2.0.sql create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.2.1.sql create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.3.0.sql create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.3.1.sql create mode 100644 domokits/local/modules/BetterSeo/Config/Update/1.4.0.sql create mode 100644 domokits/local/modules/BetterSeo/Config/config.xml create mode 100644 domokits/local/modules/BetterSeo/Config/module.xml create mode 100644 domokits/local/modules/BetterSeo/Config/routing.xml create mode 100644 domokits/local/modules/BetterSeo/Config/schema.xml create mode 100644 domokits/local/modules/BetterSeo/Config/sqldb.map create mode 100644 domokits/local/modules/BetterSeo/Config/thelia.sql create mode 100644 domokits/local/modules/BetterSeo/Controller/BetterSeoController.php create mode 100644 domokits/local/modules/BetterSeo/EventListeners/SeoListener.php create mode 100644 domokits/local/modules/BetterSeo/Form/BetterSeoForm.php create mode 100644 domokits/local/modules/BetterSeo/Hook/MetaHook.php create mode 100644 domokits/local/modules/BetterSeo/Hook/SeoFormHook.php create mode 100644 domokits/local/modules/BetterSeo/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/BetterSeo/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/BetterSeo/I18n/en_US.php create mode 100644 domokits/local/modules/BetterSeo/I18n/fr_FR.php create mode 100644 domokits/local/modules/BetterSeo/LICENCE.md create mode 100644 domokits/local/modules/BetterSeo/Loop/BetterSeoLoop.php create mode 100644 domokits/local/modules/BetterSeo/Model/BetterSeo.php create mode 100644 domokits/local/modules/BetterSeo/Model/BetterSeoI18n.php create mode 100644 domokits/local/modules/BetterSeo/Model/BetterSeoI18nQuery.php create mode 100644 domokits/local/modules/BetterSeo/Model/BetterSeoQuery.php create mode 100644 domokits/local/modules/BetterSeo/README.md create mode 100644 domokits/local/modules/BetterSeo/Smarty/Plugins/BetterSeoMicroDataPlugin.php create mode 100644 domokits/local/modules/BetterSeo/composer.json create mode 100644 domokits/local/modules/BetterSeo/templates/backOffice/default/seo-additional-fields.html create mode 100644 domokits/local/modules/BetterSeo/templates/frontOffice/default/meta_hook.html create mode 100644 domokits/local/modules/CanonicalUrl/CHANGELOG.md create mode 100644 domokits/local/modules/CanonicalUrl/CanonicalUrl.php create mode 100644 domokits/local/modules/CanonicalUrl/Config/config.xml create mode 100644 domokits/local/modules/CanonicalUrl/Config/module.xml create mode 100644 domokits/local/modules/CanonicalUrl/Config/routing.xml create mode 100644 domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvent.php create mode 100644 domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvents.php create mode 100644 domokits/local/modules/CanonicalUrl/EventListener/CanonicalUrlListener.php create mode 100644 domokits/local/modules/CanonicalUrl/EventListener/SeoFormListener.php create mode 100644 domokits/local/modules/CanonicalUrl/Hook/MetaHook.php create mode 100644 domokits/local/modules/CanonicalUrl/Hook/SeoUpdateFormHook.php create mode 100644 domokits/local/modules/CanonicalUrl/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/CanonicalUrl/LICENSE.txt create mode 100644 domokits/local/modules/CanonicalUrl/Readme.md create mode 100644 domokits/local/modules/CanonicalUrl/Tests/CanonicalUrlTest.php create mode 100644 domokits/local/modules/CanonicalUrl/composer.json create mode 100644 domokits/local/modules/CanonicalUrl/templates/backOffice/default/hook-seo-update-form.html create mode 100644 domokits/local/modules/Carousel/CHANGELOG.md create mode 100644 domokits/local/modules/Carousel/Carousel.php create mode 100644 domokits/local/modules/Carousel/Config/TheliaMain.sql create mode 100644 domokits/local/modules/Carousel/Config/config.xml create mode 100644 domokits/local/modules/Carousel/Config/module.xml create mode 100644 domokits/local/modules/Carousel/Config/routing.xml create mode 100644 domokits/local/modules/Carousel/Config/schema.xml create mode 100644 domokits/local/modules/Carousel/Config/sql/destroy.sql create mode 100644 domokits/local/modules/Carousel/Config/sqldb.map create mode 100644 domokits/local/modules/Carousel/Config/update/2.4.0.sql create mode 100644 domokits/local/modules/Carousel/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/Carousel/Form/CarouselImageForm.php create mode 100644 domokits/local/modules/Carousel/Form/CarouselUpdateForm.php create mode 100644 domokits/local/modules/Carousel/Hook/BackHook.php create mode 100644 domokits/local/modules/Carousel/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/Carousel/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/Carousel/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/Carousel/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/Carousel/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/Carousel/I18n/de_DE.php create mode 100644 domokits/local/modules/Carousel/I18n/en_US.php create mode 100644 domokits/local/modules/Carousel/I18n/fr_FR.php create mode 100644 domokits/local/modules/Carousel/I18n/it_IT.php create mode 100644 domokits/local/modules/Carousel/I18n/ru_RU.php create mode 100644 domokits/local/modules/Carousel/I18n/tr_TR.php create mode 100644 domokits/local/modules/Carousel/Loop/Carousel.php create mode 100644 domokits/local/modules/Carousel/Model/Carousel.php create mode 100644 domokits/local/modules/Carousel/Model/CarouselI18n.php create mode 100644 domokits/local/modules/Carousel/Model/CarouselI18nQuery.php create mode 100644 domokits/local/modules/Carousel/Model/CarouselQuery.php create mode 100644 domokits/local/modules/Carousel/Readme.md create mode 100644 domokits/local/modules/Carousel/composer.json create mode 100644 domokits/local/modules/Carousel/templates/backOffice/default/assets/js/module-configuration.js create mode 100644 domokits/local/modules/Carousel/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/Carousel/templates/frontOffice/default/carousel.html create mode 100644 domokits/local/modules/Cheque/Cheque.php create mode 100644 domokits/local/modules/Cheque/Config/config.xml create mode 100644 domokits/local/modules/Cheque/Config/module.xml create mode 100644 domokits/local/modules/Cheque/Config/routing.xml create mode 100644 domokits/local/modules/Cheque/Config/setup.sql create mode 100644 domokits/local/modules/Cheque/Controller/ConfigureController.php create mode 100644 domokits/local/modules/Cheque/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/Cheque/Hook/HookManager.php create mode 100644 domokits/local/modules/Cheque/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/Cheque/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/Cheque/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/Cheque/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/Cheque/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/Cheque/I18n/de_DE.php create mode 100644 domokits/local/modules/Cheque/I18n/en_US.php create mode 100644 domokits/local/modules/Cheque/I18n/fr_FR.php create mode 100644 domokits/local/modules/Cheque/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/Cheque/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/Cheque/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/Cheque/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/Cheque/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/Cheque/I18n/ru_RU.php create mode 100644 domokits/local/modules/Cheque/I18n/tr_TR.php create mode 100644 domokits/local/modules/Cheque/LICENSE.txt create mode 100644 domokits/local/modules/Cheque/Listener/SendPaymentConfirmationEmail.php create mode 100644 domokits/local/modules/Cheque/composer.json create mode 100644 domokits/local/modules/Cheque/images/cheque.png create mode 100644 domokits/local/modules/Cheque/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/Cheque/templates/frontOffice/default/order-placed.additional-payment-info.html create mode 100644 domokits/local/modules/ChoiceFilter/ChoiceFilter.php create mode 100644 domokits/local/modules/ChoiceFilter/Config/config.xml create mode 100644 domokits/local/modules/ChoiceFilter/Config/insert.sql create mode 100644 domokits/local/modules/ChoiceFilter/Config/module.xml create mode 100644 domokits/local/modules/ChoiceFilter/Config/routing.xml create mode 100644 domokits/local/modules/ChoiceFilter/Config/schema.xml create mode 100644 domokits/local/modules/ChoiceFilter/Config/thelia.sql create mode 100644 domokits/local/modules/ChoiceFilter/Controller/ChoiceFilterController.php create mode 100644 domokits/local/modules/ChoiceFilter/Controller/Front/ChoiceFilterFrontController.php create mode 100644 domokits/local/modules/ChoiceFilter/Hook/ChoiceFilterHook.php create mode 100644 domokits/local/modules/ChoiceFilter/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/ChoiceFilter/I18n/en_US.php create mode 100644 domokits/local/modules/ChoiceFilter/I18n/fr_FR.php create mode 100644 domokits/local/modules/ChoiceFilter/LICENCE create mode 100644 domokits/local/modules/ChoiceFilter/Loop/ChoiceFilterLoop.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/Api/BrandChoiceFilter.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/Api/CategoryChoiceFilter.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilter.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilterValue.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilter.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilterOther.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilterOtherI18n.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilterOtherI18nQuery.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilterOtherQuery.php create mode 100644 domokits/local/modules/ChoiceFilter/Model/ChoiceFilterQuery.php create mode 100644 domokits/local/modules/ChoiceFilter/Readme.md create mode 100644 domokits/local/modules/ChoiceFilter/Util.php create mode 100644 domokits/local/modules/ChoiceFilter/composer.json create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/category-edit.html create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.edit-js.html create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.tab-content.html create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template-edit.bottom.html create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template.edit-js.html create mode 100644 domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/template-edit.html create mode 100644 domokits/local/modules/CustomDelivery/.github/workflows/release.yml create mode 100644 domokits/local/modules/CustomDelivery/CHANGELOG.md create mode 100644 domokits/local/modules/CustomDelivery/Config/config.xml create mode 100644 domokits/local/modules/CustomDelivery/Config/module.xml create mode 100644 domokits/local/modules/CustomDelivery/Config/routing.xml create mode 100644 domokits/local/modules/CustomDelivery/Config/schema.xml create mode 100644 domokits/local/modules/CustomDelivery/Config/sqldb.map create mode 100644 domokits/local/modules/CustomDelivery/Config/thelia.sql create mode 100644 domokits/local/modules/CustomDelivery/Controller/BackController.php create mode 100755 domokits/local/modules/CustomDelivery/CustomDelivery.php create mode 100644 domokits/local/modules/CustomDelivery/EventListeners/ApiListener.php create mode 100644 domokits/local/modules/CustomDelivery/EventListeners/CustomDeliveryEvents.php create mode 100644 domokits/local/modules/CustomDelivery/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/CustomDelivery/Form/SliceForm.php create mode 100644 domokits/local/modules/CustomDelivery/Hook/HookManager.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/email/default/en_US.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/email/default/fr_FR.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/en_US.php create mode 100644 domokits/local/modules/CustomDelivery/I18n/fr_FR.php create mode 100644 domokits/local/modules/CustomDelivery/LICENSE create mode 100644 domokits/local/modules/CustomDelivery/Loop/CustomDeliverySliceLoop.php create mode 100644 domokits/local/modules/CustomDelivery/Model/CustomDeliverySlice.php create mode 100644 domokits/local/modules/CustomDelivery/Model/CustomDeliverySliceQuery.php create mode 100644 domokits/local/modules/CustomDelivery/Readme.md create mode 100644 domokits/local/modules/CustomDelivery/composer.json create mode 100644 domokits/local/modules/CustomDelivery/templates/backOffice/default/module-config-js.html create mode 100644 domokits/local/modules/CustomDelivery/templates/backOffice/default/module-configuration.html create mode 100644 domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.html create mode 100644 domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.txt create mode 100644 domokits/local/modules/FreeOrder/Config/config.xml create mode 100644 domokits/local/modules/FreeOrder/Config/module.xml create mode 100644 domokits/local/modules/FreeOrder/FreeOrder.php create mode 100644 domokits/local/modules/FreeOrder/LICENSE.txt create mode 100644 domokits/local/modules/FreeOrder/Readme.md create mode 100644 domokits/local/modules/FreeOrder/composer.json create mode 100644 domokits/local/modules/Front/Config/config.xml create mode 100644 domokits/local/modules/Front/Config/front.xml create mode 100644 domokits/local/modules/Front/Config/module.xml create mode 100644 domokits/local/modules/Front/Controller/AddressController.php create mode 100644 domokits/local/modules/Front/Controller/CartController.php create mode 100644 domokits/local/modules/Front/Controller/ContactController.php create mode 100644 domokits/local/modules/Front/Controller/CouponController.php create mode 100644 domokits/local/modules/Front/Controller/CustomerController.php create mode 100644 domokits/local/modules/Front/Controller/FeedController.php create mode 100644 domokits/local/modules/Front/Controller/NewsletterController.php create mode 100644 domokits/local/modules/Front/Controller/OrderController.php create mode 100644 domokits/local/modules/Front/Controller/SitemapController.php create mode 100644 domokits/local/modules/Front/Front.php create mode 100644 domokits/local/modules/Front/I18n/de_DE.php create mode 100644 domokits/local/modules/Front/I18n/en_US.php create mode 100644 domokits/local/modules/Front/I18n/fr_FR.php create mode 100644 domokits/local/modules/Front/I18n/it_IT.php create mode 100644 domokits/local/modules/Front/I18n/ru_RU.php create mode 100644 domokits/local/modules/Front/I18n/tr_TR.php create mode 100644 domokits/local/modules/Front/LICENSE.txt create mode 100644 domokits/local/modules/Front/composer.json create mode 100644 domokits/local/modules/HookAdminHome/Config/config.xml create mode 100644 domokits/local/modules/HookAdminHome/Config/module.xml create mode 100644 domokits/local/modules/HookAdminHome/Config/routing.xml create mode 100644 domokits/local/modules/HookAdminHome/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/HookAdminHome/Controller/HomeController.php create mode 100644 domokits/local/modules/HookAdminHome/Form/Configuration.php create mode 100644 domokits/local/modules/HookAdminHome/Hook/AdminHook.php create mode 100644 domokits/local/modules/HookAdminHome/Hook/HookAdminManager.php create mode 100644 domokits/local/modules/HookAdminHome/HookAdminHome.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/ar_SA.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/ar_SA.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/cs_CZ.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/es_ES.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/pt_BR.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/cs_CZ.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/de_DE.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/en_US.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/es_ES.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/id_ID.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/it_IT.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookAdminHome/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookAdminHome/LICENSE.txt create mode 100644 domokits/local/modules/HookAdminHome/composer.json create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/admin-home-config.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/ajax/thelia_news_feed.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/css/home.css create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/less/home.less create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-information.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-month-sales-statistics.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news-js.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-sales-statistics.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics-js.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/block-thelia-information.html create mode 100644 domokits/local/modules/HookAdminHome/templates/backOffice/default/hook-admin-home-config.html create mode 100644 domokits/local/modules/HookAnalytics/Config/config.xml create mode 100644 domokits/local/modules/HookAnalytics/Config/module.xml create mode 100644 domokits/local/modules/HookAnalytics/Config/routing.xml create mode 100644 domokits/local/modules/HookAnalytics/Controller/Configuration.php create mode 100644 domokits/local/modules/HookAnalytics/Form/Configuration.php create mode 100644 domokits/local/modules/HookAnalytics/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookAnalytics/HookAnalytics.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/backOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/backOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/de_DE.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/en_US.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/it_IT.php create mode 100755 domokits/local/modules/HookAnalytics/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookAnalytics/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookAnalytics/LICENSE.txt create mode 100644 domokits/local/modules/HookAnalytics/composer.json create mode 100644 domokits/local/modules/HookAnalytics/templates/backOffice/default/assets/js/module-configuration.js create mode 100755 domokits/local/modules/HookAnalytics/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/HookCart/Config/config.xml create mode 100644 domokits/local/modules/HookCart/Config/module.xml create mode 100644 domokits/local/modules/HookCart/HookCart.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookCart/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookCart/LICENSE.txt create mode 100644 domokits/local/modules/HookCart/composer.json create mode 100644 domokits/local/modules/HookCart/templates/frontOffice/default/assets/css/styles.css create mode 100644 domokits/local/modules/HookCart/templates/frontOffice/default/main-navbar-secondary.html create mode 100644 domokits/local/modules/HookCart/templates/frontOffice/default/mini-cart.html create mode 100644 domokits/local/modules/HookContact/Config/config.xml create mode 100644 domokits/local/modules/HookContact/Config/module.xml create mode 100644 domokits/local/modules/HookContact/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookContact/HookContact.php create mode 100644 domokits/local/modules/HookContact/I18n/de_DE.php create mode 100644 domokits/local/modules/HookContact/I18n/en_US.php create mode 100644 domokits/local/modules/HookContact/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookContact/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookContact/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookContact/I18n/it_IT.php create mode 100644 domokits/local/modules/HookContact/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookContact/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookContact/LICENSE.txt create mode 100644 domokits/local/modules/HookContact/composer.json create mode 100644 domokits/local/modules/HookContact/templates/frontOffice/default/main-footer-body.html create mode 100644 domokits/local/modules/HookCurrency/Config/config.xml create mode 100644 domokits/local/modules/HookCurrency/Config/module.xml create mode 100644 domokits/local/modules/HookCurrency/HookCurrency.php create mode 100644 domokits/local/modules/HookCurrency/LICENSE.txt create mode 100644 domokits/local/modules/HookCurrency/composer.json create mode 100644 domokits/local/modules/HookCurrency/templates/frontOffice/default/main-navbar-secondary.html create mode 100644 domokits/local/modules/HookCustomer/Config/config.xml create mode 100644 domokits/local/modules/HookCustomer/Config/module.xml create mode 100644 domokits/local/modules/HookCustomer/HookCustomer.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookCustomer/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookCustomer/LICENSE.txt create mode 100644 domokits/local/modules/HookCustomer/composer.json create mode 100644 domokits/local/modules/HookCustomer/templates/frontOffice/default/assets/css/styles.css create mode 100644 domokits/local/modules/HookCustomer/templates/frontOffice/default/main-navbar-secondary.html create mode 100644 domokits/local/modules/HookLang/Config/config.xml create mode 100644 domokits/local/modules/HookLang/Config/module.xml create mode 100644 domokits/local/modules/HookLang/HookLang.php create mode 100644 domokits/local/modules/HookLang/LICENSE.txt create mode 100644 domokits/local/modules/HookLang/composer.json create mode 100644 domokits/local/modules/HookLang/templates/frontOffice/default/main-navbar-secondary.html create mode 100644 domokits/local/modules/HookLinks/Config/config.xml create mode 100644 domokits/local/modules/HookLinks/Config/module.xml create mode 100644 domokits/local/modules/HookLinks/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookLinks/HookLinks.php create mode 100644 domokits/local/modules/HookLinks/I18n/de_DE.php create mode 100644 domokits/local/modules/HookLinks/I18n/en_US.php create mode 100644 domokits/local/modules/HookLinks/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookLinks/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookLinks/I18n/it_IT.php create mode 100644 domokits/local/modules/HookLinks/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookLinks/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookLinks/LICENSE.txt create mode 100644 domokits/local/modules/HookLinks/composer.json create mode 100644 domokits/local/modules/HookLinks/templates/frontOffice/default/main-footer-body.html create mode 100644 domokits/local/modules/HookNavigation/Config/config.xml create mode 100644 domokits/local/modules/HookNavigation/Config/module.xml create mode 100644 domokits/local/modules/HookNavigation/Config/routing.xml create mode 100644 domokits/local/modules/HookNavigation/Controller/HookNavigationConfigController.php create mode 100644 domokits/local/modules/HookNavigation/Form/HookNavigationConfigForm.php create mode 100644 domokits/local/modules/HookNavigation/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookNavigation/HookNavigation.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookNavigation/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookNavigation/I18n/en_US.php create mode 100644 domokits/local/modules/HookNavigation/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookNavigation/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookNavigation/I18n/it_IT.php create mode 100644 domokits/local/modules/HookNavigation/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookNavigation/LICENSE.txt create mode 100644 domokits/local/modules/HookNavigation/Model/Config/Base/HookNavigationConfigValue.php create mode 100644 domokits/local/modules/HookNavigation/Model/Config/HookNavigationConfigValue.php create mode 100644 domokits/local/modules/HookNavigation/composer.json create mode 100644 domokits/local/modules/HookNavigation/templates/backOffice/default/hooknavigation-configuration.html create mode 100644 domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-body.html create mode 100644 domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-bottom.html create mode 100644 domokits/local/modules/HookNavigation/templates/frontOffice/default/main-navbar-primary.html create mode 100644 domokits/local/modules/HookNewsletter/Config/config.xml create mode 100644 domokits/local/modules/HookNewsletter/Config/module.xml create mode 100644 domokits/local/modules/HookNewsletter/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookNewsletter/HookNewsletter.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/de_DE.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/en_US.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/it_IT.php create mode 100755 domokits/local/modules/HookNewsletter/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookNewsletter/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookNewsletter/LICENSE.txt create mode 100644 domokits/local/modules/HookNewsletter/composer.json create mode 100644 domokits/local/modules/HookNewsletter/templates/frontOffice/default/main-footer-body.html create mode 100644 domokits/local/modules/HookProductsNew/Config/config.xml create mode 100644 domokits/local/modules/HookProductsNew/Config/module.xml create mode 100644 domokits/local/modules/HookProductsNew/HookProductsNew.php create mode 100644 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookProductsNew/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookProductsNew/LICENSE.txt create mode 100644 domokits/local/modules/HookProductsNew/composer.json create mode 100644 domokits/local/modules/HookProductsNew/templates/frontOffice/default/home-body.html create mode 100644 domokits/local/modules/HookProductsOffer/Config/config.xml create mode 100644 domokits/local/modules/HookProductsOffer/Config/module.xml create mode 100644 domokits/local/modules/HookProductsOffer/HookProductsOffer.php create mode 100644 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookProductsOffer/LICENSE.txt create mode 100644 domokits/local/modules/HookProductsOffer/composer.json create mode 100644 domokits/local/modules/HookProductsOffer/templates/frontOffice/default/home-body.html create mode 100644 domokits/local/modules/HookSearch/Config/config.xml create mode 100644 domokits/local/modules/HookSearch/Config/module.xml create mode 100644 domokits/local/modules/HookSearch/HookSearch.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/de_DE.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/it_IT.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookSearch/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookSearch/LICENSE.txt create mode 100644 domokits/local/modules/HookSearch/composer.json create mode 100644 domokits/local/modules/HookSearch/templates/frontOffice/default/assets/css/styles.css create mode 100644 domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-primary.html create mode 100644 domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-secondary.html create mode 100644 domokits/local/modules/HookSocial/Config/config.xml create mode 100644 domokits/local/modules/HookSocial/Config/module.xml create mode 100644 domokits/local/modules/HookSocial/Config/routing.xml create mode 100644 domokits/local/modules/HookSocial/Controller/Configuration.php create mode 100644 domokits/local/modules/HookSocial/Form/Configuration.php create mode 100644 domokits/local/modules/HookSocial/Hook/FrontHook.php create mode 100644 domokits/local/modules/HookSocial/HookSocial.php create mode 100644 domokits/local/modules/HookSocial/I18n/backOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookSocial/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/HookSocial/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookSocial/I18n/backOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookSocial/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookSocial/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookSocial/I18n/de_DE.php create mode 100755 domokits/local/modules/HookSocial/I18n/en_US.php create mode 100755 domokits/local/modules/HookSocial/I18n/fr_FR.php create mode 100644 domokits/local/modules/HookSocial/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/HookSocial/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/HookSocial/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/HookSocial/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/HookSocial/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/HookSocial/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/HookSocial/I18n/it_IT.php create mode 100755 domokits/local/modules/HookSocial/I18n/ru_RU.php create mode 100644 domokits/local/modules/HookSocial/I18n/tr_TR.php create mode 100644 domokits/local/modules/HookSocial/LICENSE.txt create mode 100644 domokits/local/modules/HookSocial/composer.json create mode 100644 domokits/local/modules/HookSocial/templates/backOffice/default/assets/js/module-configuration.js create mode 100755 domokits/local/modules/HookSocial/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/HookSocial/templates/frontOffice/default/assets/css/styles.css create mode 100644 domokits/local/modules/HookSocial/templates/frontOffice/default/main-footer-body.html create mode 100644 domokits/local/modules/LocalPickup/.github/workflows/release.yml create mode 100644 domokits/local/modules/LocalPickup/Config/config.xml create mode 100644 domokits/local/modules/LocalPickup/Config/module.xml create mode 100644 domokits/local/modules/LocalPickup/Config/routing.xml create mode 100644 domokits/local/modules/LocalPickup/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/LocalPickup/EventListeners/APIListener.php create mode 100644 domokits/local/modules/LocalPickup/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/LocalPickup/Hook/HookManager.php create mode 100644 domokits/local/modules/LocalPickup/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/LocalPickup/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/LocalPickup/I18n/email/default/en_US.php create mode 100644 domokits/local/modules/LocalPickup/I18n/email/default/fr_FR.php create mode 100644 domokits/local/modules/LocalPickup/I18n/en_US.php create mode 100644 domokits/local/modules/LocalPickup/I18n/fr_FR.php create mode 100644 domokits/local/modules/LocalPickup/I18n/frontOffice/default/en_US.php create mode 100644 domokits/local/modules/LocalPickup/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/LocalPickup/LICENSE.txt create mode 100644 domokits/local/modules/LocalPickup/Listener/UpdateDeliveryAddress.php create mode 100644 domokits/local/modules/LocalPickup/LocalPickup.php create mode 100644 domokits/local/modules/LocalPickup/Loop/LocalAddress.php create mode 100644 domokits/local/modules/LocalPickup/README.md create mode 100644 domokits/local/modules/LocalPickup/composer.json create mode 100644 domokits/local/modules/LocalPickup/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/LocalPickup/templates/email/default/order_shipping.html create mode 100644 domokits/local/modules/LocalPickup/templates/email/default/order_shipping.txt create mode 100644 domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/delivery-address.html create mode 100644 domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/order-invoice-delivery-address.html create mode 100644 domokits/local/modules/OpenApi/Compiler/ModelPass.php create mode 100644 domokits/local/modules/OpenApi/Config/config.xml create mode 100644 domokits/local/modules/OpenApi/Config/module.xml create mode 100644 domokits/local/modules/OpenApi/Config/routing.xml create mode 100644 domokits/local/modules/OpenApi/Config/schema.xml create mode 100644 domokits/local/modules/OpenApi/Constraint/Length.php create mode 100644 domokits/local/modules/OpenApi/Constraint/NotBlank.php create mode 100644 domokits/local/modules/OpenApi/Constraint/NotNull.php create mode 100644 domokits/local/modules/OpenApi/Constraint/Zipcode.php create mode 100644 domokits/local/modules/OpenApi/Constraint/ZipcodeValidator.php create mode 100644 domokits/local/modules/OpenApi/Controller/Admin/BaseAdminOpenApiController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Admin/ConfigurationController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/AddressController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/AuthController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/BaseFrontOpenApiController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/CartController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/CategoryController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/CheckoutController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/ConfigController.php create mode 100755 domokits/local/modules/OpenApi/Controller/Front/ContentController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/CouponController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/CustomerController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/DeliveryController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/FolderController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/PaymentController.php create mode 100644 domokits/local/modules/OpenApi/Controller/Front/ProductController.php create mode 100644 domokits/local/modules/OpenApi/Controller/OpenApiController.php create mode 100644 domokits/local/modules/OpenApi/EventListener/ExceptionListener.php create mode 100644 domokits/local/modules/OpenApi/EventListener/LogoutListener.php create mode 100644 domokits/local/modules/OpenApi/EventListener/OrderListener.php create mode 100644 domokits/local/modules/OpenApi/EventListener/RequestListener.php create mode 100644 domokits/local/modules/OpenApi/Events/DeliveryModuleOptionEvent.php create mode 100644 domokits/local/modules/OpenApi/Events/ModelExtendDataEvent.php create mode 100644 domokits/local/modules/OpenApi/Events/ModelValidationEvent.php create mode 100644 domokits/local/modules/OpenApi/Events/OpenApiEvents.php create mode 100644 domokits/local/modules/OpenApi/Exception/OpenApiException.php create mode 100644 domokits/local/modules/OpenApi/Form/ConfigForm.php create mode 100644 domokits/local/modules/OpenApi/Hook/BackHook.php create mode 100755 domokits/local/modules/OpenApi/I18n/en_US.php create mode 100755 domokits/local/modules/OpenApi/I18n/fr_FR.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Address.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Attribute.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/AttributeValue.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/BaseApiModel.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Brand.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Cart.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/CartItem.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Category.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Checkout.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/CivilityTitle.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Content.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Coupon.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Customer.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/DeliveryModule.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/DeliveryModuleOption.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Document.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Error.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Feature.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/FeatureValue.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/File.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Folder.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/I18n.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Image.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Lang.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/ModelFactory.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/ModelTrait/translatable.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/PaymentModule.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/PickupLocation.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Price.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Product.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/ProductSaleElement.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Result.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/SchemaViolation.php create mode 100644 domokits/local/modules/OpenApi/Model/Api/Search.php create mode 100644 domokits/local/modules/OpenApi/Normalizer/ModelApiNormalizer.php create mode 100644 domokits/local/modules/OpenApi/OpenApi.php create mode 100644 domokits/local/modules/OpenApi/Readme.md create mode 100644 domokits/local/modules/OpenApi/Service/DocumentService.php create mode 100644 domokits/local/modules/OpenApi/Service/ImageService.php create mode 100644 domokits/local/modules/OpenApi/Service/OpenApiService.php create mode 100644 domokits/local/modules/OpenApi/Service/SearchService.php create mode 100644 domokits/local/modules/OpenApi/composer.json create mode 100644 domokits/local/modules/OpenApi/templates/backOffice/default/configuration.html create mode 100644 domokits/local/modules/OpenApi/templates/frontOffice/default/swagger-ui.html create mode 100644 domokits/local/modules/PayPal/.github/workflows/release.yml create mode 100644 domokits/local/modules/PayPal/Config/Update/3.0.2.sql create mode 100644 domokits/local/modules/PayPal/Config/config.xml create mode 100644 domokits/local/modules/PayPal/Config/create.sql create mode 100644 domokits/local/modules/PayPal/Config/module.xml create mode 100644 domokits/local/modules/PayPal/Config/routing.xml create mode 100644 domokits/local/modules/PayPal/Config/schema.xml create mode 100644 domokits/local/modules/PayPal/Config/sqldb.map create mode 100644 domokits/local/modules/PayPal/Config/thelia.sql create mode 100644 domokits/local/modules/PayPal/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/PayPal/Controller/PayPalPlanifiedPaymentController.php create mode 100644 domokits/local/modules/PayPal/Controller/PayPalResponseController.php create mode 100644 domokits/local/modules/PayPal/Controller/PayPalWebHookController.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalCartEvent.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalCustomerEvent.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalEvents.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalOrderEvent.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalPlanEvent.php create mode 100644 domokits/local/modules/PayPal/Event/PayPalPlanifiedPaymentEvent.php create mode 100644 domokits/local/modules/PayPal/EventListeners/Form/TheliaOrderPaymentForm.php create mode 100644 domokits/local/modules/PayPal/EventListeners/OrderListener.php create mode 100644 domokits/local/modules/PayPal/EventListeners/PayPalCartListener.php create mode 100644 domokits/local/modules/PayPal/EventListeners/PayPalCustomerListener.php create mode 100644 domokits/local/modules/PayPal/EventListeners/PayPalOrderListener.php create mode 100644 domokits/local/modules/PayPal/EventListeners/PayPalPlanListener.php create mode 100644 domokits/local/modules/PayPal/EventListeners/PayPalPlanifiedPaymentListener.php create mode 100644 domokits/local/modules/PayPal/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/PayPal/Form/PayPalFormFields.php create mode 100644 domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentCreateForm.php create mode 100644 domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentUpdateForm.php create mode 100644 domokits/local/modules/PayPal/Form/Type/PayPalCreditCardType.php create mode 100644 domokits/local/modules/PayPal/Hook/BackHookManager.php create mode 100644 domokits/local/modules/PayPal/Hook/FrontHookManager.php create mode 100644 domokits/local/modules/PayPal/Hook/PdfHookManager.php create mode 100644 domokits/local/modules/PayPal/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/PayPal/I18n/en_US.php create mode 100644 domokits/local/modules/PayPal/I18n/fr_FR.php create mode 100644 domokits/local/modules/PayPal/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/PayPal/I18n/pdf/default/fr_FR.php create mode 100644 domokits/local/modules/PayPal/Loop/PayPalLogLoop.php create mode 100644 domokits/local/modules/PayPal/Loop/PayPalOrderLoop.php create mode 100644 domokits/local/modules/PayPal/Loop/PayPalPlanifiedPaymentLoop.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalCart.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalCartQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalCustomer.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalCustomerQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalLog.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalLogQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalOrder.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalOrderQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlan.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlanQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlanifiedPayment.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlanifiedPaymentI18n.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlanifiedPaymentI18nQuery.php create mode 100644 domokits/local/modules/PayPal/Model/PaypalPlanifiedPaymentQuery.php create mode 100644 domokits/local/modules/PayPal/PayPal.php create mode 100644 domokits/local/modules/PayPal/README.md create mode 100644 domokits/local/modules/PayPal/Service/Base/PayPalBaseService.php create mode 100644 domokits/local/modules/PayPal/Service/MyOwnSQLHandler.php create mode 100644 domokits/local/modules/PayPal/Service/PayPalAgreementService.php create mode 100644 domokits/local/modules/PayPal/Service/PayPalCustomerService.php create mode 100644 domokits/local/modules/PayPal/Service/PayPalLoggerService.php create mode 100644 domokits/local/modules/PayPal/Service/PayPalPaymentService.php create mode 100644 domokits/local/modules/PayPal/composer.json create mode 100644 domokits/local/modules/PayPal/images/logo.png create mode 100644 domokits/local/modules/PayPal/images/payment_classic.png create mode 100644 domokits/local/modules/PayPal/images/payment_classic_incontext.png create mode 100644 domokits/local/modules/PayPal/images/payment_credit_card.png create mode 100644 domokits/local/modules/PayPal/images/payment_express_checkout.png create mode 100644 domokits/local/modules/PayPal/images/payment_recursive.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_agreement.jpeg create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf1.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf2.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf3.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_live_button.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_webhook.png create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/form/create-or-update-planified-payment-form.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row-js.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/menu/menu.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/module-configuration.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/order-edit-js.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/payment-information.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/paypal-log.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment-edit.html create mode 100644 domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment.html create mode 100644 domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.html create mode 100644 domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.txt create mode 100644 domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.html create mode 100644 domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.txt create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/assets/cards-logo.jpg create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/assets/ntimes-cards-logo.png create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/assets/paypal-logo.png create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/cart-bottom.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-credit-card.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-paypal.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-planified-payment.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/login-bottom.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom-js.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-bottom.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-js.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-payment-extra.html create mode 100644 domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-placed-additional-payment-info.html create mode 100644 domokits/local/modules/PayPal/templates/pdf/default/paypal/after-payment-module.html create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/CHANGELOG.md create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/Config/config.xml create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/Config/module.xml create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/LICENSE create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/Listener/LoopProductListener.php create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/ProductLoopAttributeFilter.php create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/Readme.md create mode 100644 domokits/local/modules/ProductLoopAttributeFilter/composer.json create mode 100644 domokits/local/modules/ReCaptcha/Action/ReCaptchaAction.php create mode 100644 domokits/local/modules/ReCaptcha/Config/config.xml create mode 100644 domokits/local/modules/ReCaptcha/Config/module.xml create mode 100644 domokits/local/modules/ReCaptcha/Config/routing.xml create mode 100644 domokits/local/modules/ReCaptcha/Config/schema.xml create mode 100644 domokits/local/modules/ReCaptcha/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php create mode 100644 domokits/local/modules/ReCaptcha/Event/ReCaptchaEvents.php create mode 100644 domokits/local/modules/ReCaptcha/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/ReCaptcha/Hook/FrontHook.php create mode 100644 domokits/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/ReCaptcha/I18n/en_US.php create mode 100644 domokits/local/modules/ReCaptcha/I18n/fr_FR.php create mode 100644 domokits/local/modules/ReCaptcha/LICENSE create mode 100644 domokits/local/modules/ReCaptcha/ReCaptcha.php create mode 100644 domokits/local/modules/ReCaptcha/Readme.md create mode 100644 domokits/local/modules/ReCaptcha/composer.json create mode 100644 domokits/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html create mode 100644 domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html create mode 100644 domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html create mode 100644 domokits/local/modules/ResetPassword/Command/ResetAllPasswordCommand.php create mode 100755 domokits/local/modules/ResetPassword/Config/TheliaMain.sql create mode 100755 domokits/local/modules/ResetPassword/Config/config.xml create mode 100755 domokits/local/modules/ResetPassword/Config/module.xml create mode 100755 domokits/local/modules/ResetPassword/Config/routing.xml create mode 100755 domokits/local/modules/ResetPassword/Config/schema.xml create mode 100644 domokits/local/modules/ResetPassword/Config/sqldb.map create mode 100644 domokits/local/modules/ResetPassword/Config/update/1.0.1.sql create mode 100755 domokits/local/modules/ResetPassword/Controller/Front/ResetPasswordController.php create mode 100755 domokits/local/modules/ResetPassword/EventListener/LostPasswordListener.php create mode 100755 domokits/local/modules/ResetPassword/Form/Front/ResetPasswordAskForm.php create mode 100755 domokits/local/modules/ResetPassword/Form/Front/ResetPasswordForm.php create mode 100644 domokits/local/modules/ResetPassword/I18n/email/default/fr_FR.php create mode 100755 domokits/local/modules/ResetPassword/I18n/en_US.php create mode 100755 domokits/local/modules/ResetPassword/I18n/fr_FR.php create mode 100644 domokits/local/modules/ResetPassword/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/ResetPassword/Model/CustomerForbiddenPassword.php create mode 100644 domokits/local/modules/ResetPassword/Model/CustomerForbiddenPasswordQuery.php create mode 100755 domokits/local/modules/ResetPassword/Model/PasswordResetToken.php create mode 100755 domokits/local/modules/ResetPassword/Model/PasswordResetTokenQuery.php create mode 100755 domokits/local/modules/ResetPassword/Readme.md create mode 100755 domokits/local/modules/ResetPassword/ResetPassword.php create mode 100755 domokits/local/modules/ResetPassword/Service/ResetPasswordService.php create mode 100755 domokits/local/modules/ResetPassword/composer.json create mode 100644 domokits/local/modules/ResetPassword/templates/email/default/reset_all_password_message.html create mode 100755 domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.html create mode 100755 domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.txt create mode 100755 domokits/local/modules/ResetPassword/templates/frontOffice/default/resetPassword/reset_password.html create mode 100644 domokits/local/modules/RewriteUrl/.github/workflows/release.yml create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit-js.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/category-edit-js.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/category-edit.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/content-edit-js.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/content-edit.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit-js.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/product-edit-js.html create mode 100755 domokits/local/modules/RewriteUrl/AdminIncludes/product-edit.html create mode 100755 domokits/local/modules/RewriteUrl/Config/config.xml create mode 100755 domokits/local/modules/RewriteUrl/Config/module.xml create mode 100755 domokits/local/modules/RewriteUrl/Config/routing.xml create mode 100644 domokits/local/modules/RewriteUrl/Config/schema.xml create mode 100644 domokits/local/modules/RewriteUrl/Config/thelia.sql create mode 100644 domokits/local/modules/RewriteUrl/Config/update/1.4.8.sql create mode 100644 domokits/local/modules/RewriteUrl/Config/update/1.5.0.sql create mode 100644 domokits/local/modules/RewriteUrl/Controller/Admin/ModuleConfigController.php create mode 100644 domokits/local/modules/RewriteUrl/Controller/Admin/NotRewritenUrlsAdminController.php create mode 100755 domokits/local/modules/RewriteUrl/Controller/Admin/RewriteUrlAdminController.php create mode 100755 domokits/local/modules/RewriteUrl/Event/RewriteUrlEvent.php create mode 100755 domokits/local/modules/RewriteUrl/Event/RewriteUrlEvents.php create mode 100644 domokits/local/modules/RewriteUrl/EventListeners/KernelExceptionListener.php create mode 100755 domokits/local/modules/RewriteUrl/EventListeners/RewriteUrlListener.php create mode 100755 domokits/local/modules/RewriteUrl/Form/AddUrlForm.php create mode 100755 domokits/local/modules/RewriteUrl/Form/ReassignForm.php create mode 100755 domokits/local/modules/RewriteUrl/Form/SetDefaultForm.php create mode 100644 domokits/local/modules/RewriteUrl/Hook/ConfigurationHook.php create mode 100755 domokits/local/modules/RewriteUrl/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/RewriteUrl/I18n/fr_FR.php create mode 100755 domokits/local/modules/RewriteUrl/LICENSE.txt create mode 100644 domokits/local/modules/RewriteUrl/Loop/NotRewritenUrlCategoryLoop.php create mode 100755 domokits/local/modules/RewriteUrl/Loop/RewriteUrlLoop.php create mode 100644 domokits/local/modules/RewriteUrl/Loop/RewriteUrlRuleLoop.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewriteurlRule.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParam.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParamQuery.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewriteurlRuleQuery.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewritingRedirectType.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewritingRedirectTypeQuery.php create mode 100644 domokits/local/modules/RewriteUrl/Model/RewritingUrlOverride.php create mode 100755 domokits/local/modules/RewriteUrl/Readme.md create mode 100755 domokits/local/modules/RewriteUrl/RewriteUrl.php create mode 100644 domokits/local/modules/RewriteUrl/Service/RewritingRouterFirst.php create mode 100644 domokits/local/modules/RewriteUrl/Service/RewritingRouterLast.php create mode 100755 domokits/local/modules/RewriteUrl/composer.json create mode 100644 domokits/local/modules/RewriteUrl/logo.jpg create mode 100644 domokits/local/modules/RewriteUrl/screenshot/screenshot-1.jpeg create mode 100644 domokits/local/modules/RewriteUrl/screenshot/screenshot-2.jpeg create mode 100644 domokits/local/modules/RewriteUrl/screenshot/screenshot-3.png create mode 100644 domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration-js.html create mode 100644 domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration.html create mode 100755 domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module-js.html create mode 100755 domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module.html create mode 100644 domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-value-render.html create mode 100644 domokits/local/modules/RewriteUrl/templates/backOffice/default/configuration-catalog.html create mode 100644 domokits/local/modules/RewriteUrl/templates/backOffice/default/list-notrewritenurls.html create mode 100644 domokits/local/modules/ShortCode/Config/TheliaMain.sql create mode 100644 domokits/local/modules/ShortCode/Config/config.xml create mode 100644 domokits/local/modules/ShortCode/Config/module.xml create mode 100644 domokits/local/modules/ShortCode/Config/routing.xml create mode 100644 domokits/local/modules/ShortCode/Config/schema.xml create mode 100644 domokits/local/modules/ShortCode/Config/sqldb.map create mode 100644 domokits/local/modules/ShortCode/Event/ShortCodeEvent.php create mode 100644 domokits/local/modules/ShortCode/EventListener/ResponseListener.php create mode 100755 domokits/local/modules/ShortCode/I18n/en_US.php create mode 100755 domokits/local/modules/ShortCode/I18n/fr_FR.php create mode 100644 domokits/local/modules/ShortCode/LICENCE create mode 100644 domokits/local/modules/ShortCode/Model/ShortCode.php create mode 100644 domokits/local/modules/ShortCode/Model/ShortCodeQuery.php create mode 100644 domokits/local/modules/ShortCode/Readme.md create mode 100644 domokits/local/modules/ShortCode/ShortCode.php create mode 100644 domokits/local/modules/ShortCode/composer.json create mode 100644 domokits/local/modules/ShortCodeMeta/Config/config.xml create mode 100644 domokits/local/modules/ShortCodeMeta/Config/module.xml create mode 100644 domokits/local/modules/ShortCodeMeta/Config/routing.xml create mode 100644 domokits/local/modules/ShortCodeMeta/Config/schema.xml create mode 100644 domokits/local/modules/ShortCodeMeta/EventListener/ShortCodeListener.php create mode 100755 domokits/local/modules/ShortCodeMeta/I18n/en_US.php create mode 100755 domokits/local/modules/ShortCodeMeta/I18n/fr_FR.php create mode 100644 domokits/local/modules/ShortCodeMeta/LICENSE create mode 100644 domokits/local/modules/ShortCodeMeta/Readme.md create mode 100644 domokits/local/modules/ShortCodeMeta/ShortCodeMeta.php create mode 100644 domokits/local/modules/ShortCodeMeta/Smarty/Plugins/ShortCodeMetaPlugin.php create mode 100644 domokits/local/modules/ShortCodeMeta/composer.json create mode 100644 domokits/local/modules/ShortCodeMeta/templates/frontOffice/default/short_code_meta_hook.html create mode 100644 domokits/local/modules/SmartyRedirection/Config/config.xml create mode 100644 domokits/local/modules/SmartyRedirection/Config/module.xml create mode 100644 domokits/local/modules/SmartyRedirection/LICENSE.txt create mode 100644 domokits/local/modules/SmartyRedirection/Readme.md create mode 100644 domokits/local/modules/SmartyRedirection/Smarty/Plugins/Redirect.php create mode 100644 domokits/local/modules/SmartyRedirection/SmartyRedirection.php create mode 100644 domokits/local/modules/SmartyRedirection/composer.json create mode 100755 domokits/local/modules/StoreSeo/Config/config.xml create mode 100755 domokits/local/modules/StoreSeo/Config/module.xml create mode 100755 domokits/local/modules/StoreSeo/Config/routing.xml create mode 100755 domokits/local/modules/StoreSeo/Controller/StoreSeoConfigController.php create mode 100755 domokits/local/modules/StoreSeo/Form/StoreSeoForm.php create mode 100755 domokits/local/modules/StoreSeo/Hook/StoreSeoHook.php create mode 100755 domokits/local/modules/StoreSeo/I18n/backOffice/default/en_US.php create mode 100755 domokits/local/modules/StoreSeo/I18n/backOffice/default/fr_FR.php create mode 100755 domokits/local/modules/StoreSeo/I18n/en_US.php create mode 100755 domokits/local/modules/StoreSeo/I18n/fr_FR.php create mode 100755 domokits/local/modules/StoreSeo/Readme.md create mode 100755 domokits/local/modules/StoreSeo/Smarty/Plugins/StoreSeoPlugin.php create mode 100755 domokits/local/modules/StoreSeo/StoreSeo.php create mode 100755 domokits/local/modules/StoreSeo/composer.json create mode 100755 domokits/local/modules/StoreSeo/templates/backOffice/default/storeseo-configuration.html create mode 100644 domokits/local/modules/StripePayment/Classes/StripePaymentException.php create mode 100644 domokits/local/modules/StripePayment/Classes/StripePaymentLog.php create mode 100644 domokits/local/modules/StripePayment/Config/config.xml create mode 100644 domokits/local/modules/StripePayment/Config/module.xml create mode 100644 domokits/local/modules/StripePayment/Config/routing.xml create mode 100644 domokits/local/modules/StripePayment/Config/schema.xml create mode 100644 domokits/local/modules/StripePayment/Controller/StripePaymentConfigController.php create mode 100644 domokits/local/modules/StripePayment/Controller/StripePaymentController.php create mode 100644 domokits/local/modules/StripePayment/Controller/StripeWebHooksController.php create mode 100644 domokits/local/modules/StripePayment/EventListeners/CartEventListener.php create mode 100644 domokits/local/modules/StripePayment/EventListeners/SendConfirmationEmailListener.php create mode 100644 domokits/local/modules/StripePayment/Form/Base/StripePaymentConfigForm.php create mode 100644 domokits/local/modules/StripePayment/Form/StripePaymentConfigForm.php create mode 100644 domokits/local/modules/StripePayment/Hook/StripePaymentHook.php create mode 100644 domokits/local/modules/StripePayment/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/StripePayment/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/StripePayment/I18n/email/default/en_US.php create mode 100644 domokits/local/modules/StripePayment/I18n/email/default/fr_FR.php create mode 100644 domokits/local/modules/StripePayment/I18n/en_US.php create mode 100644 domokits/local/modules/StripePayment/I18n/fr_FR.php create mode 100644 domokits/local/modules/StripePayment/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/StripePayment/LICENSE.txt create mode 100644 domokits/local/modules/StripePayment/Readme.md create mode 100644 domokits/local/modules/StripePayment/Resource/images/module/stripe.png create mode 100644 domokits/local/modules/StripePayment/StripePayment.php create mode 100644 domokits/local/modules/StripePayment/composer.json create mode 100644 domokits/local/modules/StripePayment/templates/backOffice/default/stripepayment-configuration.html create mode 100644 domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.html create mode 100644 domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.txt create mode 100644 domokits/local/modules/StripePayment/templates/frontOffice/default/assets/css/styles.css create mode 100644 domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/order-invoice-after-js-include.html create mode 100644 domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/stripe-js.html create mode 100644 domokits/local/modules/StripePayment/templates/frontOffice/default/stripe-paiement.html create mode 100644 domokits/local/modules/TheliaBlocks/.github/workflows/npm-publish.yml create mode 100644 domokits/local/modules/TheliaBlocks/.github/workflows/release.yml create mode 100755 domokits/local/modules/TheliaBlocks/.gitignore create mode 100755 domokits/local/modules/TheliaBlocks/.husky/pre-commit create mode 100644 domokits/local/modules/TheliaBlocks/Command/ValidateJsonContent.php create mode 100644 domokits/local/modules/TheliaBlocks/Config/TheliaMain.sql create mode 100755 domokits/local/modules/TheliaBlocks/Config/config.xml create mode 100755 domokits/local/modules/TheliaBlocks/Config/module.xml create mode 100755 domokits/local/modules/TheliaBlocks/Config/routing.xml create mode 100755 domokits/local/modules/TheliaBlocks/Config/schema.xml create mode 100755 domokits/local/modules/TheliaBlocks/Config/sqldb.map create mode 100644 domokits/local/modules/TheliaBlocks/Config/update/1.0.1.sql create mode 100644 domokits/local/modules/TheliaBlocks/Config/update/2.1.9.sql create mode 100644 domokits/local/modules/TheliaBlocks/Controller/Admin/BlockGroupController.php create mode 100644 domokits/local/modules/TheliaBlocks/Controller/Admin/ConfigurationController.php create mode 100644 domokits/local/modules/TheliaBlocks/Controller/Admin/ItemBlockGroupController.php create mode 100644 domokits/local/modules/TheliaBlocks/Controller/Front/BlockGroupController.php create mode 100644 domokits/local/modules/TheliaBlocks/Controller/Front/PreviewGroupController.php create mode 100644 domokits/local/modules/TheliaBlocks/EventListeners/ShortCodeListener.php create mode 100644 domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksBackHook.php create mode 100644 domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksMenuHook.php create mode 100755 domokits/local/modules/TheliaBlocks/I18n/en_US.php create mode 100755 domokits/local/modules/TheliaBlocks/I18n/fr_FR.php create mode 100644 domokits/local/modules/TheliaBlocks/Loop/BlockGroup.php create mode 100755 domokits/local/modules/TheliaBlocks/Model/Api/BlockGroup.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/Api/ItemBlockGroup.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/BlockGroup.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/BlockGroupI18n.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/BlockGroupI18nQuery.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/BlockGroupQuery.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/ItemBlockGroup.php create mode 100644 domokits/local/modules/TheliaBlocks/Model/ItemBlockGroupQuery.php create mode 100755 domokits/local/modules/TheliaBlocks/Readme.md create mode 100644 domokits/local/modules/TheliaBlocks/Service/HtmlParserService.php create mode 100644 domokits/local/modules/TheliaBlocks/Service/JsonBlockService.php create mode 100644 domokits/local/modules/TheliaBlocks/SmartyPlugin/JsonBlockRender.php create mode 100755 domokits/local/modules/TheliaBlocks/TheliaBlocks.php create mode 100755 domokits/local/modules/TheliaBlocks/composer.json create mode 100644 domokits/local/modules/TheliaBlocks/gulpfile.js create mode 100644 domokits/local/modules/TheliaBlocks/package-lock.json create mode 100644 domokits/local/modules/TheliaBlocks/package.json create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/hook-in-top-menu-item.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/item-configuration.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/styles/styles.css create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/thelia-blocks-configuration.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/thelia-blocks-css.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/thelia-blocks-item-configuration.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/thelia-blocks-js.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/thelia-blocks-new-configuration.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/html-warning-KFAIZUTI.png create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.css create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.css.map create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.d.ts create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.global.js create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.global.js.map create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.js create mode 100644 domokits/local/modules/TheliaBlocks/templates/backOffice/default/vendor/index.js.map create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockAccordion.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockButton.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockCategory.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockFullWidthImage.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockGroup.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockHighlight.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockList.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockProduct.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockRaw.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockSeparator.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockTable.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockText.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockTitle.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/blockVideo.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/multiColumns.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/blocks/rawBlockGroup.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/default/thelia-blocks-preview.html create mode 100644 domokits/local/modules/TheliaBlocks/templates/frontOffice/modern/thelia-blocks-preview.html create mode 100644 domokits/local/modules/TheliaLibrary/.github/workflows/release.yml create mode 100644 domokits/local/modules/TheliaLibrary/.gitignore create mode 100755 domokits/local/modules/TheliaLibrary/.husky/pre-commit create mode 100644 domokits/local/modules/TheliaLibrary/ApiExtend/ProductApiListener.php create mode 100755 domokits/local/modules/TheliaLibrary/Command/ImageMigrateCommand.php create mode 100755 domokits/local/modules/TheliaLibrary/Config/TheliaMain.sql create mode 100755 domokits/local/modules/TheliaLibrary/Config/config.xml create mode 100755 domokits/local/modules/TheliaLibrary/Config/module.xml create mode 100755 domokits/local/modules/TheliaLibrary/Config/routing.xml create mode 100755 domokits/local/modules/TheliaLibrary/Config/schema.xml create mode 100755 domokits/local/modules/TheliaLibrary/Config/sqldb.map create mode 100644 domokits/local/modules/TheliaLibrary/Config/update/1.1.2.sql create mode 100755 domokits/local/modules/TheliaLibrary/Controller/Admin/ImageController.php create mode 100644 domokits/local/modules/TheliaLibrary/Controller/Admin/ImageTagController.php create mode 100755 domokits/local/modules/TheliaLibrary/Controller/Admin/ItemImageController.php create mode 100644 domokits/local/modules/TheliaLibrary/Controller/Admin/TagController.php create mode 100755 domokits/local/modules/TheliaLibrary/Controller/Front/ImageController.php create mode 100644 domokits/local/modules/TheliaLibrary/Controller/Front/LegacyImageController.php create mode 100755 domokits/local/modules/TheliaLibrary/Controller/Front/OpenApi/ImageController.php create mode 100755 domokits/local/modules/TheliaLibrary/Controller/Front/OpenApi/ItemImageController.php create mode 100644 domokits/local/modules/TheliaLibrary/Hook/BackHook.php create mode 100755 domokits/local/modules/TheliaLibrary/I18n/en_US.php create mode 100755 domokits/local/modules/TheliaLibrary/I18n/fr_FR.php create mode 100755 domokits/local/modules/TheliaLibrary/Loop/LibraryImage.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/Api/LibraryImage.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/Api/LibraryImageTag.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/Api/LibraryItemImage.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/Api/LibraryTag.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryImage.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryImageI18n.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryImageI18nQuery.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryImageQuery.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryImageTag.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryImageTagQuery.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryItemImage.php create mode 100755 domokits/local/modules/TheliaLibrary/Model/LibraryItemImageQuery.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryTag.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryTagI18n.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryTagI18nQuery.php create mode 100644 domokits/local/modules/TheliaLibrary/Model/LibraryTagQuery.php create mode 100755 domokits/local/modules/TheliaLibrary/Readme.md create mode 100755 domokits/local/modules/TheliaLibrary/Service/ImageService.php create mode 100755 domokits/local/modules/TheliaLibrary/Service/LibraryImageService.php create mode 100644 domokits/local/modules/TheliaLibrary/Service/LibraryImageTagService.php create mode 100755 domokits/local/modules/TheliaLibrary/Service/LibraryItemImageService.php create mode 100644 domokits/local/modules/TheliaLibrary/Service/LibraryTagService.php create mode 100755 domokits/local/modules/TheliaLibrary/TheliaLibrary.php create mode 100755 domokits/local/modules/TheliaLibrary/composer.json create mode 100644 domokits/local/modules/TheliaLibrary/gulpfile.js create mode 100644 domokits/local/modules/TheliaLibrary/package-lock.json create mode 100644 domokits/local/modules/TheliaLibrary/package.json create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/item-edition.html create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/import-plugin.html create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/import-styles.html create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.css create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.css.map create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.d.ts create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.global.js create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.global.js.map create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.mjs create mode 100644 domokits/local/modules/TheliaLibrary/templates/backOffice/default/tb-plugin/vendor/index.mjs.map create mode 100644 domokits/local/modules/TheliaLibrary/templates/frontOffice/default/blocks/blockImage.html create mode 100644 domokits/local/modules/TheliaMigrateCountry/Config/config.xml create mode 100644 domokits/local/modules/TheliaMigrateCountry/Config/module.xml create mode 100644 domokits/local/modules/TheliaMigrateCountry/Config/routing.xml create mode 100644 domokits/local/modules/TheliaMigrateCountry/Controller/MigrateController.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/EventListeners/MigrateCountryListener.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/Events/MigrateCountryEvent.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/Events/MigrateCountryEvents.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/Form/CountryStateMigrationForm.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/Form/Type/CountryStateMigrationType.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/backOffice/default/it_IT.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/en_US.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/fr_FR.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/it_IT.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/I18n/ru_RU.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/LICENSE.txt create mode 100644 domokits/local/modules/TheliaMigrateCountry/Readme.md create mode 100644 domokits/local/modules/TheliaMigrateCountry/TheliaMigrateCountry.php create mode 100644 domokits/local/modules/TheliaMigrateCountry/composer.json create mode 100644 domokits/local/modules/TheliaMigrateCountry/templates/backOffice/default/configuration-shipping-bottom.html create mode 100644 domokits/local/modules/TheliaMigrateCountry/templates/backOffice/default/countries-migrate.html create mode 100644 domokits/local/modules/TheliaSmarty/CREDITS.md create mode 100644 domokits/local/modules/TheliaSmarty/Compiler/RegisterParserPluginPass.php create mode 100644 domokits/local/modules/TheliaSmarty/Config/config.xml create mode 100644 domokits/local/modules/TheliaSmarty/Config/module.xml create mode 100644 domokits/local/modules/TheliaSmarty/Events/ComponentRenderEvent.php create mode 100644 domokits/local/modules/TheliaSmarty/I18n/en_US.php create mode 100644 domokits/local/modules/TheliaSmarty/I18n/fr_FR.php create mode 100644 domokits/local/modules/TheliaSmarty/I18n/ru_RU.php create mode 100644 domokits/local/modules/TheliaSmarty/I18n/tr_TR.php create mode 100644 domokits/local/modules/TheliaSmarty/LICENSE.txt create mode 100644 domokits/local/modules/TheliaSmarty/Readme.md create mode 100644 domokits/local/modules/TheliaSmarty/Template/AbstractSmartyPlugin.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Assets/EncoreModuleAssetsPathPackage.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Assets/EncoreModuleAssetsVersionStrategy.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Assets/SmartyAssetsManager.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Assets/SmartyAssetsResolver.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Components/AbstractSmartyComponent.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/DataCollectorSmartyParser.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Exception/SmartyPluginException.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/AdminUtilities.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Assets.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Cache.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/CartPostage.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Component.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/DataAccessFunctions.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Encore.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/FlashMessage.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Form.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Format.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/FrontUtils.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Hook.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Module.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Render.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Security.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/TheliaLoop.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Translation.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/Type.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/UrlGenerator.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/Plugins/VarDumper.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/SmartyHelper.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/SmartyParser.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/SmartyPluginDescriptor.php create mode 100644 domokits/local/modules/TheliaSmarty/Template/SmartyPluginInterface.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/Controller/TestController.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/FormTest.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/FormatTest.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/RenderTest.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/SmartyPluginTestCase.php create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/test.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testFormatMoney.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testMethod.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testParams.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testQueryArray.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testQueryString.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/Plugin/fixtures/testRequest.html create mode 100644 domokits/local/modules/TheliaSmarty/Tests/Template/SmartyHelperTest.php create mode 100644 domokits/local/modules/TheliaSmarty/TheliaSmarty.php create mode 100644 domokits/local/modules/TheliaSmarty/composer.json create mode 100644 domokits/local/modules/Tinymce/CHANGELOG.md create mode 100644 domokits/local/modules/Tinymce/Config/config.xml create mode 100644 domokits/local/modules/Tinymce/Config/module.xml create mode 100644 domokits/local/modules/Tinymce/Config/routing.xml create mode 100644 domokits/local/modules/Tinymce/Controller/ConfigureController.php create mode 100644 domokits/local/modules/Tinymce/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/Tinymce/Hook/HookManager.php create mode 100644 domokits/local/modules/Tinymce/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/Tinymce/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/Tinymce/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/Tinymce/I18n/backOffice/default/ru_RU.php create mode 100644 domokits/local/modules/Tinymce/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/Tinymce/I18n/en_US.php create mode 100644 domokits/local/modules/Tinymce/I18n/fr_FR.php create mode 100644 domokits/local/modules/Tinymce/I18n/it_IT.php create mode 100644 domokits/local/modules/Tinymce/I18n/ru_RU.php create mode 100644 domokits/local/modules/Tinymce/I18n/tr_TR.php create mode 100644 domokits/local/modules/Tinymce/LICENSE.txt create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/ajax_calls.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/execute.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/force_download.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_apply.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_clear.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/copy.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/cut.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/date.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/dimension.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/down.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/download.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/duplicate.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/edit_img.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/file_edit.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings-white.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ac3.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/accdb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ade.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/adp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ai.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/aiff.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/avi.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/bmp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/c4d.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/css.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/csv.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/default.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/dmg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/doc.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/docx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/dwg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/dxf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/favicon.ico create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/fla.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/flv.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/folder.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/folder_back.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gif.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gz.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/html.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/iso.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/jpeg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/jpg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/log.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/m4a.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mdb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mid.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mov.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mp3.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mp4.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpeg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ods.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ogg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/otg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/otp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ots.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ott.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pdf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/png.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ppt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pptx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/psd.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/rar.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/rtf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/skp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/sql.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/stp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/svg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tar.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tiff.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/txt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/vwx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/wav.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/webm.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/wma.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xhtml.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xls.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xlsx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xml.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/zip.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ac3.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/accdb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ade.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/adp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ai.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/aiff.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/avi.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/bmp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/css.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/csv.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/default.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/dmg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/doc.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/docx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/favicon.ico create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/fla.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/flv.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder_back.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gif.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gz.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/html.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/iso.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpeg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/log.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/m4a.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mdb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mid.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mov.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mp3.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mp4.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mpeg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mpg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odb.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ods.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ogg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/otg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/otp.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ots.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ott.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pdf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/png.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ppt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pptx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/psd.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rar.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rtf.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/sql.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/svg.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/tar.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/tiff.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/txt.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/wav.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/webm.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/wma.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xhtml.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xls.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xlsx.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xml.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/zip.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/info.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/key.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/label.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/loading.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/logo.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/preview.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/processing.gif create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/rename.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/size.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/sort.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/storing_animation.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/trans.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/up.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/upload.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/url.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/zip.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpClient.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpException.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpWrapper.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/Response.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/ftp_class.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/mime_type_lib.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/php_image_magician.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/utils.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/ZeroClipboard.swf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/include.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/MIT-LICENSE.txt create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/README.md create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/Jplayer.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/Jplayer.fla create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/ConnectManager.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/JplayerEvent.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/JplayerMp3.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/JplayerMp4.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/JplayerRtmp.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/JplayerStatus.as create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/actionscript/happyworm/jPlayer/TraceOut.as create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/add-on/jplayer.playlist.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/add-on/jplayer.playlist.min.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/add-on/jquery.jplayer.inspector.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/add-on/jquery.jplayer.inspector.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jplayer.jquery.json create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jplayer/jquery.jplayer.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jplayer/jquery.jplayer.min.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jplayer/jquery.jplayer.swf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jquery.jplayer/Jplayer.swf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/jquery.jplayer/jquery.jplayer.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/package.json create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/popcorn/popcorn.jplayer.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/popcorn/popcorn.jplayer.min.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/css/jplayer.blue.monday.css create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/css/jplayer.blue.monday.min.css create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/image/jplayer.blue.monday.jpg create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/image/jplayer.blue.monday.seeking.gif create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/image/jplayer.blue.monday.video.play.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/jplayer.blue.monday.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/jplayer.blue.monday.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/jplayer.blue.monday.seeking.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/jplayer.blue.monday.video.play.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.playlist.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.single.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/mustache/jplayer.blue.monday.audio.stream.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/mustache/jplayer.blue.monday.video.playlist.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/mustache/jplayer.blue.monday.video.single.html create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/blue.monday/skin.handlebars create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/css/jplayer.pink.flag.css create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/css/jplayer.pink.flag.min.css create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/image/jplayer.pink.flag.jpg create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/image/jplayer.pink.flag.seeking.gif create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/image/jplayer.pink.flag.video.play.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/mustache/jplayer.pink.flag.audio.playlist.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/mustache/jplayer.pink.flag.audio.single.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/mustache/jplayer.pink.flag.audio.stream.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/mustache/jplayer.pink.flag.video.playlist.html create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin/pink.flag/mustache/jplayer.pink.flag.video.single.html create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/blue.monday/jplayer.blue.monday.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/blue.monday/jplayer.blue.monday.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/blue.monday/jplayer.blue.monday.seeking.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/blue.monday/jplayer.blue.monday.video.play.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/blue.monday/skin.handlebars create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/pink.flag/jplayer.pink.flag.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/pink.flag/jplayer.pink.flag.jpg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/pink.flag/jplayer.pink.flag.seeking.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/jPlayer/skin_ol/pink.flag/jplayer.pink.flag.video.play.png create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/modernizr.custom.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/plugins.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/az_AZ.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/bg_BG.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/ca.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/cs.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/da.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/de.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/el_GR.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/en_EN.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/es.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/fa.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/fr_FR.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/he_IL.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/hr.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/hu_HU.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/id.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/it.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/ja.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/languages.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/lt.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/mn_MN.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/nb_NO.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/nl.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/pl.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/pt_BR.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/pt_PT.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/ro.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/ru.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/sk.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/sl.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/sv_SE.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/tr_TR.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/uk_UA.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/vi.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/lang/zh_CN.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/plugin.min.js create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/upload.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/uploader/index.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/uploader/jupload.php create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/uploader/success.jpg create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/uploader/success.php create mode 100755 domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/uploader/wjhk.jupload.jar create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/cs.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/de.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/es.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/fr_FR.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/it.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/readme.md create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/langs/ru.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/license.txt create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/advlist/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/anchor/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/autolink/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/autoresize/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/autosave/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/bbcode/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/charmap/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/code/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/codesample/css/prism.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/codesample/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/colorpicker/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/contextmenu/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/directionality/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-cool.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-cry.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-frown.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-innocent.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-kiss.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-laughing.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-sealed.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-smile.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-surprised.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-undecided.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-wink.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/img/smiley-yell.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/emoticons/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/example/dialog.html create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/example/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/example_dependency/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/fullpage/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/fullscreen/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/hr/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/image/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/imagetools/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/importcss/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/insertdatetime/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/layer/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/legacyoutput/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/link/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/lists/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/media/moxieplayer.swf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/media/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/nonbreaking/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/noneditable/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/pagebreak/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/paste/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/preview/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/print/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/editor_plugin.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/img/insertfile.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/plugin.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/save/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/searchreplace/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/spellchecker/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/tabfocus/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/table/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/template/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textcolor/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textpattern/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/visualblocks/css/visualblocks.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/visualblocks/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/visualchars/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/wordcount/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/README.md create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/css/styles.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/Google-YouTube-128.png create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/youtube.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/js/main.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/js/vendor/jquery.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/de.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/en.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/es.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/fr_FR.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/hu.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/it.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/pl.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/pt_BR.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/langs/ru.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/plugin.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/plugin.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/view/forms.html create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/youtube.html create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/content.inline.min.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/content.min.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce-small.eot create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce-small.svg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce-small.woff create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce.eot create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce.svg create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce.ttf create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/fonts/tinymce.woff create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/img/anchor.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/img/loader.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/img/object.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/img/trans.gif create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/skin.ie7.min.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/skins/lightgray/skin.min.css create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/themes/modern/theme.min.js create mode 100644 domokits/local/modules/Tinymce/Resources/js/tinymce/tinymce.min.js create mode 100644 domokits/local/modules/Tinymce/Smarty/TinyMCELanguage.php create mode 100644 domokits/local/modules/Tinymce/Tinymce.php create mode 100644 domokits/local/modules/Tinymce/composer.json create mode 100644 domokits/local/modules/Tinymce/templates/backOffice/default/assets/css/editor.less create mode 100644 domokits/local/modules/Tinymce/templates/backOffice/default/module_configuration.html create mode 100644 domokits/local/modules/Tinymce/templates/backOffice/default/tinymce_init.tpl create mode 100644 domokits/local/modules/UrlSanitizer/.github/workflows/release.yml create mode 100644 domokits/local/modules/UrlSanitizer/Config/config.xml create mode 100644 domokits/local/modules/UrlSanitizer/Config/module.xml create mode 100644 domokits/local/modules/UrlSanitizer/Config/routing.xml create mode 100644 domokits/local/modules/UrlSanitizer/Config/schema.xml create mode 100644 domokits/local/modules/UrlSanitizer/Controller/ConfigurationController.php create mode 100644 domokits/local/modules/UrlSanitizer/EventListener/RewriteUrlListener.php create mode 100644 domokits/local/modules/UrlSanitizer/Form/ConfigurationForm.php create mode 100644 domokits/local/modules/UrlSanitizer/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/UrlSanitizer/Readme.md create mode 100644 domokits/local/modules/UrlSanitizer/Service/UrlSanitizerService.php create mode 100644 domokits/local/modules/UrlSanitizer/UrlSanitizer.php create mode 100644 domokits/local/modules/UrlSanitizer/composer.json create mode 100644 domokits/local/modules/UrlSanitizer/templates/backOffice/default/UrlSanitizer/module-configuration.html create mode 100644 domokits/local/modules/VirtualProductControl/Config/config.xml create mode 100644 domokits/local/modules/VirtualProductControl/Config/module.xml create mode 100644 domokits/local/modules/VirtualProductControl/Hook/VirtualProductHook.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/backOffice/default/de_DE.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/backOffice/default/en_US.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/backOffice/default/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/backOffice/default/it_IT.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/backOffice/default/tr_TR.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/de_DE.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/en_US.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/it_IT.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/ru_RU.php create mode 100644 domokits/local/modules/VirtualProductControl/I18n/tr_TR.php create mode 100644 domokits/local/modules/VirtualProductControl/LICENSE.txt create mode 100644 domokits/local/modules/VirtualProductControl/VirtualProductControl.php create mode 100644 domokits/local/modules/VirtualProductControl/composer.json create mode 100644 domokits/local/modules/VirtualProductControl/templates/backOffice/default/virtual-delivery-warning.html create mode 100644 domokits/local/modules/VirtualProductDelivery/Config/config.xml create mode 100644 domokits/local/modules/VirtualProductDelivery/Config/module.xml create mode 100755 domokits/local/modules/VirtualProductDelivery/EventListeners/SendMail.php create mode 100644 domokits/local/modules/VirtualProductDelivery/EventListeners/VirtualProductEvents.php create mode 100644 domokits/local/modules/VirtualProductDelivery/Events/VirtualProductDeliveryEvents.php create mode 100644 domokits/local/modules/VirtualProductDelivery/Hook/HookManager.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/de_DE.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/email/default/en_US.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/email/default/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/email/default/it_IT.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/email/default/ru_RU.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/email/default/tr_TR.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/en_US.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/de_DE.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/en_US.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/it_IT.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/ru_RU.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/tr_TR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/it_IT.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/de_DE.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/en_US.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/fr_FR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/it_IT.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/ru_RU.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/tr_TR.php create mode 100755 domokits/local/modules/VirtualProductDelivery/I18n/ru_RU.php create mode 100644 domokits/local/modules/VirtualProductDelivery/I18n/tr_TR.php create mode 100644 domokits/local/modules/VirtualProductDelivery/LICENSE.txt create mode 100644 domokits/local/modules/VirtualProductDelivery/VirtualProductDelivery.php create mode 100644 domokits/local/modules/VirtualProductDelivery/composer.json create mode 100644 domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.html create mode 100644 domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.txt create mode 100644 domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/account-order-after-products.html create mode 100644 domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/delivery-address.html create mode 100644 domokits/local/modules/VirtualProductDelivery/templates/pdf/default/delivery-address.html create mode 100644 domokits/local/modules/WebProfiler/Config/config.xml create mode 100644 domokits/local/modules/WebProfiler/Config/config_dev.xml create mode 100644 domokits/local/modules/WebProfiler/Config/config_prod.xml create mode 100644 domokits/local/modules/WebProfiler/Config/config_test.xml create mode 100644 domokits/local/modules/WebProfiler/Config/module.xml create mode 100644 domokits/local/modules/WebProfiler/Config/routing.xml create mode 100644 domokits/local/modules/WebProfiler/Config/schema.xml create mode 100644 domokits/local/modules/WebProfiler/DataCollector/SmartyDataCollector.php create mode 100644 domokits/local/modules/WebProfiler/DataCollector/TheliaCollector.php create mode 100644 domokits/local/modules/WebProfiler/I18n/en_US.php create mode 100644 domokits/local/modules/WebProfiler/I18n/fr_FR.php create mode 100644 domokits/local/modules/WebProfiler/Readme.md create mode 100644 domokits/local/modules/WebProfiler/WebProfiler.php create mode 100644 domokits/local/modules/WebProfiler/composer.json create mode 100644 domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/base.html.twig create mode 100644 domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/header.html.twig create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smarty.svg create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smartyColor.svg create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/thelia.svg create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/theliaWhite.svg create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/smarty.html.twig create mode 100644 domokits/local/modules/WebProfiler/templates/debug/dataCollector/thelia.html.twig create mode 100644 domokits/templates/frontOffice/custom/assets/src/css/custom.css diff --git a/.idea/light-domotique-NEW.iml b/.idea/light-domotique-NEW.iml index 9d15e58..ee88408 100644 --- a/.idea/light-domotique-NEW.iml +++ b/.idea/light-domotique-NEW.iml @@ -6,6 +6,8 @@ + + @@ -100,6 +102,7 @@ + diff --git a/.idea/php.xml b/.idea/php.xml index c273597..79705eb 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -106,12 +106,18 @@ + + + + + + diff --git a/domokits/.gitignore b/domokits/.gitignore index f6592d8..7ca027e 100644 --- a/domokits/.gitignore +++ b/domokits/.gitignore @@ -17,7 +17,6 @@ /templates/pdf/default # Thelia config -/local/config /local/setup /local/media /local/session @@ -25,9 +24,6 @@ !local/media/images/store/thelia.svg !local/media/images/store/banner.png -# Thelia modules -/local/modules/* - ### Please add your dependancies here ###> symfony/framework-bundle ### @@ -46,3 +42,4 @@ npm-debug.log yarn-error.log ###< symfony/webpack-encore-bundle ### +/log/ diff --git a/domokits/composer.json b/domokits/composer.json index d7df361..be4e185 100644 --- a/domokits/composer.json +++ b/domokits/composer.json @@ -18,7 +18,8 @@ "thelia/thelia-library-module": "^1.1.7", "thelia/product-loop-attribute-filter-module": "~2.0.0", "thelia/reset-password-module": "~1.0.1", - "thelia/re-captcha-module": "~3.0.1" + "thelia/re-captcha-module": "~3.0.1", + "stripe/stripe-php": "6.*" }, "suggest": { "vlopes/maintenance-module": "Add a way to put your site in maintenance mode", diff --git a/domokits/local/modules/BetterSeo/.github/workflows/release.yml b/domokits/local/modules/BetterSeo/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/BetterSeo/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/BetterSeo/BetterSeo.php b/domokits/local/modules/BetterSeo/BetterSeo.php new file mode 100644 index 0000000..05d0001 --- /dev/null +++ b/domokits/local/modules/BetterSeo/BetterSeo.php @@ -0,0 +1,77 @@ +insertSql(null, [__DIR__ . "/Config/thelia.sql"]); + self::setConfigValue('is_initialized', 1); + } + } + + public function update($currentVersion, $newVersion, ConnectionInterface $con = null):void + { + $sqlToExecute = []; + $finder = new Finder(); + $sort = function (\SplFileInfo $a, \SplFileInfo $b) { + $a = strtolower(substr($a->getRelativePathname(), 0, -4)); + $b = strtolower(substr($b->getRelativePathname(), 0, -4)); + return version_compare($a, $b); + }; + + $files = $finder->name('*.sql') + ->in(__DIR__ . "/Config/Update/") + ->sort($sort); + + foreach ($files as $file) { + if (version_compare($file->getFilename(), $currentVersion, ">")) { + $sqlToExecute[$file->getFilename()] = $file->getRealPath(); + } + } + + $database = new Database($con); + + foreach ($sqlToExecute as $version => $sql) { + $database->insertSql(null, [$sql]); + } + } + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.1.0.sql b/domokits/local/modules/BetterSeo/Config/Update/1.1.0.sql new file mode 100644 index 0000000..17b07a6 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.1.0.sql @@ -0,0 +1 @@ +ALTER TABLE `better_seo_i18n` ADD `h1` TEXT NOT NULL AFTER `canonical_field`; \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.2.0.sql b/domokits/local/modules/BetterSeo/Config/Update/1.2.0.sql new file mode 100644 index 0000000..2fd3c3b --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.2.0.sql @@ -0,0 +1 @@ +ALTER TABLE `better_seo_i18n` ADD `mesh_text_1` TEXT NOT NULL AFTER `h1`, ADD `mesh_url_1` TEXT NOT NULL AFTER `mesh_text_1`, ADD `mesh_text_2` TEXT NOT NULL AFTER `mesh_url_1`, ADD `mesh_url_2` TEXT NOT NULL AFTER `mesh_text_2`, ADD `mesh_text_3` TEXT NOT NULL AFTER `mesh_url_2`, ADD `mesh_url_3` TEXT NOT NULL AFTER `mesh_text_3`, ADD `mesh_text_4` TEXT NOT NULL AFTER `mesh_url_3`, ADD `mesh_url_4` TEXT NOT NULL AFTER `mesh_text_4`, ADD `mesh_text_5` TEXT NOT NULL AFTER `mesh_url_4`, ADD `mesh_url_5` TEXT NOT NULL AFTER `mesh_text_5`; \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.2.1.sql b/domokits/local/modules/BetterSeo/Config/Update/1.2.1.sql new file mode 100644 index 0000000..fa52b5f --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.2.1.sql @@ -0,0 +1,10 @@ +ALTER TABLE `better_seo_i18n` CHANGE `mesh_text_1` `mesh_text_1` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_url_1` `mesh_url_1` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_text_2` `mesh_text_2` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_url_2` `mesh_url_2` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_text_3` `mesh_text_3` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_url_3` `mesh_url_3` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_text_4` `mesh_text_4` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_url_4` `mesh_url_4` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_text_5` `mesh_text_5` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_url_5` `mesh_url_5` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.3.0.sql b/domokits/local/modules/BetterSeo/Config/Update/1.3.0.sql new file mode 100644 index 0000000..e1e7297 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.3.0.sql @@ -0,0 +1,6 @@ +ALTER TABLE `better_seo_i18n` + ADD `mesh_1` TEXT NOT NULL AFTER `mesh_url_5`, + ADD `mesh_2` TEXT NOT NULL AFTER `mesh_1`, + ADD `mesh_3` TEXT NOT NULL AFTER `mesh_2`, + ADD `mesh_4` TEXT NOT NULL AFTER `mesh_3`, + ADD `mesh_5` TEXT NOT NULL AFTER `mesh_4`; \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.3.1.sql b/domokits/local/modules/BetterSeo/Config/Update/1.3.1.sql new file mode 100644 index 0000000..a9cc91b --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.3.1.sql @@ -0,0 +1,5 @@ +ALTER TABLE `better_seo_i18n` CHANGE `mesh_1` `mesh_1` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_2` `mesh_2` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_3` `mesh_3` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_4` `mesh_4` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; +ALTER TABLE `better_seo_i18n` CHANGE `mesh_5` `mesh_5` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL; \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/Config/Update/1.4.0.sql b/domokits/local/modules/BetterSeo/Config/Update/1.4.0.sql new file mode 100644 index 0000000..74bcd7a --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/Update/1.4.0.sql @@ -0,0 +1 @@ +ALTER TABLE `better_seo_i18n` ADD `json_data` TEXT NOT NULL AFTER `mesh_5`; diff --git a/domokits/local/modules/BetterSeo/Config/config.xml b/domokits/local/modules/BetterSeo/Config/config.xml new file mode 100644 index 0000000..88a5a63 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/config.xml @@ -0,0 +1,20 @@ + + + + +
+ + + + + + + + + + + + + diff --git a/domokits/local/modules/BetterSeo/Config/module.xml b/domokits/local/modules/BetterSeo/Config/module.xml new file mode 100644 index 0000000..370d2cb --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/module.xml @@ -0,0 +1,32 @@ + + + BetterSeo\BetterSeo + + Set noindex, nofollow, h1, tag on pages, and manage mesh links + + + Ajoute la balise noindex, nofollow, h1, sur les pages, plus gestion des liens maillés + + + en_US + fr_FR + + 2.1.2 + + + Nicolas Barbey + nabrbey@openstudio.fr + + + Gilles Bourgeat + gilles.bourgeat@gmail.com + + + classic + 2.5.0 + rc + 0 + 0 + diff --git a/domokits/local/modules/BetterSeo/Config/routing.xml b/domokits/local/modules/BetterSeo/Config/routing.xml new file mode 100644 index 0000000..cc2e8ce --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/routing.xml @@ -0,0 +1,10 @@ + + + + + + BetterSeo\Controller\BetterSeoController::saveAction + + diff --git a/domokits/local/modules/BetterSeo/Config/schema.xml b/domokits/local/modules/BetterSeo/Config/schema.xml new file mode 100644 index 0000000..bb2d822 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/schema.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
diff --git a/domokits/local/modules/BetterSeo/Config/sqldb.map b/domokits/local/modules/BetterSeo/Config/sqldb.map new file mode 100644 index 0000000..63a93ba --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +thelia.sql=thelia diff --git a/domokits/local/modules/BetterSeo/Config/thelia.sql b/domokits/local/modules/BetterSeo/Config/thelia.sql new file mode 100644 index 0000000..4f3bfb6 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Config/thelia.sql @@ -0,0 +1,58 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- better_seo +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `better_seo`; + +CREATE TABLE `better_seo` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `object_id` INTEGER NOT NULL, + `object_type` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- better_seo_i18n +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `better_seo_i18n`; + +CREATE TABLE `better_seo_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `noindex` TINYINT(4) DEFAULT 0 NOT NULL, + `nofollow` TINYINT(4) DEFAULT 0 NOT NULL, + `canonical_field` TEXT, + `h1` TEXT, + `mesh_text_1` TEXT, + `mesh_url_1` TEXT, + `mesh_text_2` TEXT, + `mesh_url_2` TEXT, + `mesh_text_3` TEXT, + `mesh_url_3` TEXT, + `mesh_text_4` TEXT, + `mesh_url_4` TEXT, + `mesh_text_5` TEXT, + `mesh_url_5` TEXT, + `mesh_1` TEXT, + `mesh_2` TEXT, + `mesh_3` TEXT, + `mesh_4` TEXT, + `mesh_5` TEXT, + `json_data` TEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `better_seo_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `better_seo` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/BetterSeo/Controller/BetterSeoController.php b/domokits/local/modules/BetterSeo/Controller/BetterSeoController.php new file mode 100644 index 0000000..8083744 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Controller/BetterSeoController.php @@ -0,0 +1,64 @@ +createForm(BetterSeoForm::getName()); + + $seoForm = $this->validateForm($form); + + $object_id = $request->get('object_id'); + $object_type = $request->get('object_type'); + + $lang = LangQuery::create() + ->filterById($request->get('lang_id')) + ->findOne(); + + if (null === $objectSeo = BetterSeoQuery::create() + ->filterByObjectId($object_id) + ->filterByObjectType($object_type) + ->findOne() + ) { + $objectSeo = (new BetterSeo()) + ->setObjectId($object_id) + ->setObjectType($object_type); + } + + $objectSeo + ->setLocale($lang->getLocale()) + ->setJsonData($seoForm->get('json_data')->getData()) + ->setNoindex(null === $seoForm->get('noindex_checkbox')->getData() ? 0 : 1) + ->setNofollow(null === $seoForm->get('nofollow_checkbox')->getData() ? 0 : 1) + ->setH1(null === $seoForm->get('h1')->getData() ? '' : $seoForm->get('h1')->getData()); + + for ($i = 1; $i <= 5; $i++) { + call_user_func([$objectSeo, 'setMeshUrl' . $i], $seoForm->get('mesh_url_' . $i)->getData()); + call_user_func([$objectSeo, 'setMeshText' . $i], $seoForm->get('mesh_text_' . $i)->getData()); + call_user_func([$objectSeo, 'setMesh' . $i], $seoForm->get('mesh_' . $i)->getData()); + } + + $objectSeo->save(); + + return $this->generateRedirect( + URL::getInstance()->absoluteUrl( + $request->getSession()->getReturnToUrl(), + ['current_tab' => 'seo'] + ) + ); + } +} diff --git a/domokits/local/modules/BetterSeo/EventListeners/SeoListener.php b/domokits/local/modules/BetterSeo/EventListeners/SeoListener.php new file mode 100644 index 0000000..b305cc8 --- /dev/null +++ b/domokits/local/modules/BetterSeo/EventListeners/SeoListener.php @@ -0,0 +1,75 @@ +request = $requestStack->getCurrentRequest(); + } + + public function removeHrefLang(AlternateHreflangEvent $event) + { + $objectType = $this->request->get('_view'); + $objectId = $this->request->get($objectType.'_id'); + + $betterSeoObject = $this->getBetterSeoObject($objectType, $objectId); + } + + public function checkSiteMap(SitemapEvent $event) + { + $objectId = $event->getRewritingUrl()->getViewId(); + $objectType = $event->getRewritingUrl()->getView(); + + $betterSeoObject = $this->getBetterSeoObject($objectType, $objectId); + + if (null !== $betterSeoObject){ + if ($betterSeoObject->getNoindex() === 1){ + $event->setHide(true); + } + } + } + + /** + * @return array + */ + public static function getSubscribedEvents() + { + $events = []; + if (class_exists('Sitemap\Event\SitemapEvent')){ + $events[SitemapEvent::SITEMAP_EVENT] = ['checkSiteMap',128]; + } + if (class_exists('AlternateHreflang\Event\AlternateHreflangEvent')){ + $events[AlternateHreflangEvent::BASE_EVENT_NAME] = ['removeHrefLang',128]; + } + return $events; + } + + protected function getBetterSeoObject($objectType, $objectId) + { + $lang = $this->request->getSession()->getLang()->getLocale(); + + $betterSeoObject = BetterSeoQuery::create() + ->filterByObjectType($objectType) + ->filterByObjectId($objectId) + ->findOne(); + if (null !== $betterSeoObject){ + $betterSeoObject->setLocale($lang); + } + + return $betterSeoObject; + } +} diff --git a/domokits/local/modules/BetterSeo/Form/BetterSeoForm.php b/domokits/local/modules/BetterSeo/Form/BetterSeoForm.php new file mode 100644 index 0000000..5eb79f5 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Form/BetterSeoForm.php @@ -0,0 +1,136 @@ +formBuilder; + $form + ->add( + 'noindex_checkbox', + IntegerType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'noindex', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'noindex_checkbox' + ) + ) + ) + ->add( + 'nofollow_checkbox', + IntegerType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'nofollow', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'nofollow_checkbox' + ) + ) + ) + ->add( + 'h1', + TextType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'h1', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'h1' + ) + ) + ) + ->add( + 'json_data', + TextareaType::class, + [ + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'JSON structured data', + [], + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'json_data' + ) + ] + + ); + + for ($i = 1; $i <= 5; $i++) { + $form->add( + 'mesh_text_' . $i, + TextType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'text', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'mesh_text_' . $i + ) + ) + ) + ->add( + 'mesh_url_' . $i, + UrlType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'url', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'mesh_url_' . $i + ) + ) + ) + ->add( + 'mesh_' . $i, + TextType::class, + array( + 'required' => false, + 'label' => Translator::getInstance()->trans( + 'text', + array(), + BetterSeo::DOMAIN_NAME + ), + 'label_attr' => array( + 'for' => 'mesh_' . $i + ) + ) + ); + } + } + + public static function getName() + { + return 'betterseo_form'; + } +} diff --git a/domokits/local/modules/BetterSeo/Hook/MetaHook.php b/domokits/local/modules/BetterSeo/Hook/MetaHook.php new file mode 100644 index 0000000..4bb0bd8 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Hook/MetaHook.php @@ -0,0 +1,38 @@ +request = $requestStack->getCurrentRequest(); + } + + public function onMainHeadBottom(HookRenderEvent $event) + { + $view = $this->request->get('_view'); + if ($view && preg_match('#^[a-zA-Z0-9\-_\.]+$#', $view)) { + + $id = $this->request->get($view . '_id'); + + $lang = $this->request->getSession()->getLang(); + + $event->add( + $this->render('meta_hook.html', [ + 'object_id' => $id, + 'object_type' => $view, + 'lang_id' => $lang->getId() + ]) + ); + } + } +} diff --git a/domokits/local/modules/BetterSeo/Hook/SeoFormHook.php b/domokits/local/modules/BetterSeo/Hook/SeoFormHook.php new file mode 100644 index 0000000..3751b89 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Hook/SeoFormHook.php @@ -0,0 +1,35 @@ +getArgument('id'); + $objectType = $event->getArgument('type'); + + $event->add( + $this->render( + "seo-additional-fields.html", + [ + 'object_id' => $objectId, + 'object_type' => $objectType, + ] + ) + ); + } +} \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/I18n/backOffice/default/en_US.php b/domokits/local/modules/BetterSeo/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..2a43203 --- /dev/null +++ b/domokits/local/modules/BetterSeo/I18n/backOffice/default/en_US.php @@ -0,0 +1,11 @@ + 'Save', + + 'noindex_nofollow.help' => 'Management of the meta robots noindex, nofollow. Allow to not index this page for search engines. Be careful before checking this, check that your page does not generate traffic on Google Analytics. You risk losing SEO.', + + + 'label.noindex' => 'Management of the meta robots noindex, nofollow, h1 tag and mesh links', + 'h1' => 'H1', +); diff --git a/domokits/local/modules/BetterSeo/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/BetterSeo/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..cb5aa43 --- /dev/null +++ b/domokits/local/modules/BetterSeo/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,19 @@ + 'Enregistrer', + + 'noindex_nofollow.help' => 'Gestion de la meta robots noindex, nofollow. Permet de ne pas indexer cette page pour les moteurs de recherche. Attention avant de cocher cela, bien vérifier que votre page ne génère pas de trafic sur Google Analytics. Vous risquez de perdre du référencement.', + + + 'label.noindex' => 'Gestion de la meta robots noindex, nofollow, balise H1 et liens maillés :', + 'h1' => 'H1', + 'Link' => 'Lien', + 'text' => 'texte', + 'url' => 'url', + 'Link text' => 'Texte du lien', + 'Link URL' => 'URL du lien', + 'Mesh links' => 'Liens maillés', + 'Mesh' => 'Texte de maillage', + 'Text' => 'Texte', +); diff --git a/domokits/local/modules/BetterSeo/I18n/en_US.php b/domokits/local/modules/BetterSeo/I18n/en_US.php new file mode 100644 index 0000000..afca37e --- /dev/null +++ b/domokits/local/modules/BetterSeo/I18n/en_US.php @@ -0,0 +1,5 @@ +getObjectId(); + $objectType = $this->getObjectType(); + $langId = $this->getLangId(); + + $lang = LangQuery::create() + ->filterById($langId) + ->findOne(); + + $query = BetterSeoQuery::create() + ->filterByObjectId($objectId) + ->filterByObjectType($objectType) + ->useBetterSeoI18nQuery() + ->filterByLocale($lang->getLocale()) + ->endUse() + ->withColumn(BetterSeoI18nTableMap::NOINDEX, 'noindex') + ->withColumn(BetterSeoI18nTableMap::NOFOLLOW, 'nofollow') + ->withColumn(BetterSeoI18nTableMap::H1, 'h1') + ->withColumn(BetterSeoI18nTableMap::JSON_DATA, 'json_data'); + + for ($i = 1; $i <= 5; $i++) { + $query->withColumn(constant(BetterSeoI18nTableMap::class . '::MESH_TEXT_' . $i), 'mesh_text_' . $i); + $query->withColumn(constant(BetterSeoI18nTableMap::class . '::MESH_URL_' . $i), 'mesh_url_' . $i); + $query->withColumn(constant(BetterSeoI18nTableMap::class . '::MESH_' . $i), 'mesh_' . $i); + } + + return $query; + } + + /** + * @param LoopResult $loopResult + * @return LoopResult + * @throws \Propel\Runtime\Exception\PropelException + */ + public function parseResults(LoopResult $loopResult) + { + /** @var BetterSeo $data */ + foreach ($loopResult->getResultDataCollection() as $data) { + $loopResultRow = new LoopResultRow($data); + + $loopResultRow->set('ID', $data->getId()); + $loopResultRow->set('OBJECT_ID', $data->getObjectId()); + $loopResultRow->set('OBJECT_TYPE', $data->getObjectType()); + $loopResultRow->set('NOINDEX', $data->getVirtualColumn('noindex')); + $loopResultRow->set('NOFOLLOW', $data->getVirtualColumn('nofollow')); + $loopResultRow->set('H1', $data->getVirtualColumn('h1')); + $loopResultRow->set('JSON_DATA', $data->getVirtualColumn('json_data')); + + for ($i = 1; $i <= 5; $i++) { + $loopResultRow->set('MESH_TEXT_' . $i, $data->getVirtualColumn('mesh_text_' . $i)); + $loopResultRow->set('MESH_URL_' . $i, $data->getVirtualColumn('mesh_url_' . $i)); + $loopResultRow->set('MESH_' . $i, $data->getVirtualColumn('mesh_' . $i)); + } + + $loopResult->addRow($loopResultRow); + } + return $loopResult; + } +} diff --git a/domokits/local/modules/BetterSeo/Model/BetterSeo.php b/domokits/local/modules/BetterSeo/Model/BetterSeo.php new file mode 100644 index 0000000..f0e9b59 --- /dev/null +++ b/domokits/local/modules/BetterSeo/Model/BetterSeo.php @@ -0,0 +1,10 @@ +/local/modules/``` directory and be sure that the name of the module is BetterSeo. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/better-seo-module:~1.4.1 +``` + +## Loop + +[better_seo_loop] + +### Input arguments + +|Argument |Description | +|--- |--- | +|**object_id** | The id of the object to display, exemple: object_id="12" | +|**object_type** | The type of the object to display (product, category, brand, folder, content) exemple object_type="brand"| +|**lang_id** | The id of the language| + + ### Output arguments + +|Variable |Description | +|--- |--- | +|$ID | the id in seo_noindex table | +|$OBJECT_ID | the id of the object | +|$OBJECT_TYPE | the type of the object | +|$NOINDEX | if the page of the object is index or not (value 0 or 1) | +|$NOFOLLOW | if the page of the object is follow or not (value 0 or 1) | +|$CANONICAL | Canonical Url | +|$H1 | H1 | +|$MESH_TEXT_1 | mesh text 1 | +|$MESH_URL_1 | mesh url 1 | +|$MESH_TEXT_2 | mesh text 2 | +|$MESH_URL_2 | mesh url 2 | +|$MESH_TEXT_3 | mesh text 3 | +|$MESH_URL_3 | mesh url 3 | +|$MESH_TEXT_4 | mesh text 4 | +|$MESH_URL_4 | mesh url 4 | +|$MESH_TEXT_5 | mesh text 5 | +|$MESH_URL_5 | mesh url 5 | +|$MESH_1 | mesh 1 | +|$MESH_2 | mesh 2 | +|$MESH_3 | mesh 3 | +|$MESH_4 | mesh 4 | +|$MESH_5 | mesh 5 | +|$JSON_DATA | JSON data for ld json | + +### Exemple + + {loop type="better_seo_loop" name="exemple.loop" object_id="42" object_type="category" lang_id="1"} + + +To use ld json you need to add this part to the head of your pages (product, category, brand, folder, content) + + {loop name="loop-name" type="better_seo_loop" object_id=$object_id object_type=$object_type lang_id=$langId} + + {/loop} + + diff --git a/domokits/local/modules/BetterSeo/Smarty/Plugins/BetterSeoMicroDataPlugin.php b/domokits/local/modules/BetterSeo/Smarty/Plugins/BetterSeoMicroDataPlugin.php new file mode 100644 index 0000000..c072ecf --- /dev/null +++ b/domokits/local/modules/BetterSeo/Smarty/Plugins/BetterSeoMicroDataPlugin.php @@ -0,0 +1,318 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace BetterSeo\Smarty\Plugins; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Event\Image\ImageEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Exception\TaxEngineException; +use Thelia\Model\Category; +use Thelia\Model\CategoryQuery; +use Thelia\Model\ConfigQuery; +use Thelia\Model\Content; +use Thelia\Model\ContentQuery; +use Thelia\Model\Folder; +use Thelia\Model\FolderQuery; +use Thelia\Model\Lang; +use Thelia\Model\LangQuery; +use Thelia\Model\Product; +use Thelia\Model\ProductImageQuery; +use Thelia\Model\ProductPriceQuery; +use Thelia\Model\ProductQuery; +use Thelia\Model\ProductSaleElementsQuery; +use Thelia\TaxEngine\TaxEngine; +use TheliaSmarty\Template\AbstractSmartyPlugin; +use TheliaSmarty\Template\SmartyPluginDescriptor; + +class BetterSeoMicroDataPlugin extends AbstractSmartyPlugin +{ + protected $request; + protected $taxEngine; + protected $dispatcher; + + public function __construct(RequestStack $requestStack, TaxEngine $taxEngine, EventDispatcherInterface $dispatcher) + { + $this->request = $requestStack->getCurrentRequest(); + $this->taxEngine = $taxEngine; + $this->dispatcher = $dispatcher; + } + + public function getPluginDescriptors() + { + return [ + new SmartyPluginDescriptor('function', 'BetterSeoMicroData', $this, 'betterSeoMicroData'), + ]; + } + + /** + * @param $params + * + * @return array|int|string + * + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function betterSeoMicroData($params) + { + $type = $params['type'] ?? $this->request->get('_view'); + + $lang = $this->request->getSession()->getLang(); + + if (!$lang) { + $lang = LangQuery::create()->filterByByDefault(1)->findOne(); + } + $microdata = null; + + switch ($type) { + case 'product': + $id = $params['id'] ?? $this->request->get('product_id'); + $product = ProductQuery::create()->filterById($id)->findOne(); + $relatedProducts = null; + + if (array_key_exists('related_products', $params)){ + $relatedProducts = \is_array($params['related_products']) ? $params['related_products'] : $this->explode($params['related_products']); + } + + $microdata = $this->getProductMicroData($product, $lang, $relatedProducts); + break; + case 'category': + $id = $params['id'] ?? $this->request->get('category_id'); + if ($id) { + $category = CategoryQuery::create()->filterById($id)->findOne(); + $microdata = $this->getCategoryMicroData($category, $lang); + } + break; + case 'folder': + $id = $params['id'] ?? $this->request->get('folder_id'); + if ($id) { + $folder = FolderQuery::create()->filterById($id)->findOne(); + $microdata = $this->getFolderMicroData($folder, $lang); + } + break; + case 'content': + $id = $params['id'] ?? $this->request->get('content_id'); + if ($id) { + $microdata = $this->getContentMicroData($id, $lang); + } + break; + } + + $scriptsTag = ''; + + $scriptsTag .= ''; + if (null !== $microdata) { + $scriptsTag .= ''; + } + + return $scriptsTag; + } + + /** + * @return array + */ + protected function getStoreMicroData() + { + $microData = [ + '@context' => 'https://schema.org/', + '@type' => 'Organization', + 'name' => ConfigQuery::read('store_name'), + 'description' => ConfigQuery::read('store_description'), + 'url' => ConfigQuery::read('url_site'), + 'address' => [ + '@type' => 'PostalAddress', + 'streetAddress' => ConfigQuery::read('store_address1').' '.ConfigQuery::read('store_address2').' '.ConfigQuery::read('store_address3'), + 'addressLocality' => ConfigQuery::read('store_city'), + 'postalCode' => ConfigQuery::read('store_zipcode'), + ], + ]; + + return $microData; + } + + /** + * @param array $relatedProducts + * + * @return array + * + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + protected function getProductMicroData(Product $product, Lang $lang, $relatedProducts = []) + { + $product->setLocale($lang->getLocale()); + $image = ProductImageQuery::create()->filterByProductId($product->getId())->orderByPosition()->find()[0]; + $pse = ProductSaleElementsQuery::create()->filterByProductId($product->getId())->filterByIsDefault(1)->findOne(); + $psePrice = ProductPriceQuery::create()->filterByProductSaleElementsId($pse->getId())->findOne(); + $taxCountry = $this->taxEngine->getDeliveryCountry(); + + try { + $taxedPrice = $product->getTaxedPrice( + $taxCountry, + $psePrice->getPrice() + ); + if ($pse->getPromo()) { + $taxedPrice = $product->getTaxedPromoPrice( + $taxCountry, + $psePrice->getPromoPrice() + ); + } + } catch (TaxEngineException $e) { + $taxedPrice = null; + } + + $imagePath = null; + + if ($image) { + $baseSourceFilePath = ConfigQuery::read('images_library_path'); + if ($baseSourceFilePath === null) { + $baseSourceFilePath = THELIA_LOCAL_DIR.'media'.DS.'images'; + } else { + $baseSourceFilePath = THELIA_ROOT.$baseSourceFilePath; + } + $event = new ImageEvent(); + $sourceFilePath = $baseSourceFilePath.'/product/'.$image->getFile(); + + $event->setSourceFilepath($sourceFilePath); + $event->setCacheSubdirectory('product'); + + try { + $this->dispatcher->dispatch($event, TheliaEvents::IMAGE_PROCESS); + $imagePath = $event->getFileUrl(); + } catch (\Exception $e) { + $imagePath = $image->getFile(); + } + } + + $microData = [ + '@context' => 'https://schema.org/', + '@type' => 'Product', + 'name' => $product->getTitle(), + 'image' => $imagePath, + 'description' => $product->getDescription(), + 'sku' => $product->getRef(), + 'offers' => [ + 'url' => $product->getUrl(), + 'priceCurrency' => $this->request->getSession()->getCurrency()->getCode(), + 'price' => $taxedPrice, + 'itemCondition' => 'https://schema.org/NewCondition', + 'availability' => $pse->getQuantity() > 0 ? 'http://schema.org/InStock' : 'http://schema.org/OutOfStock', + ], + ]; + + if ($pse->getEanCode()) { + $microData['gtin13'] = $pse->getEanCode(); + } + + if ($brand = $product->getBrand()) { + $microData['brand']['@type'] = 'Brand'; + $microData['brand']['name'] = $brand->getTitle(); + } + + if ($relatedProducts) { + foreach ($relatedProducts as $relatedProductId) { + $relatedProduct = ProductQuery::create()->filterById($relatedProductId)->findOne(); + $microData['isRelatedTo'][] = $this->getProductMicroData($relatedProduct, $lang); + } + } + + return $microData; + } + + /** + * @return array + */ + protected function getCategoryMicroData(Category $category, Lang $lang) + { + $category->setLocale($lang->getLocale()); + + $products = $category->getProducts(); + + $itemListElement = []; + + $i = 1; + foreach ($products as $product) { + $itemListElement[] = [ + '@type' => 'ListItem', + 'position' => $i++, + 'url' => $product->getUrl(), + ]; + } + + $microData = [ + '@context' => 'https://schema.org/', + '@type' => 'ItemList', + 'url' => $category->getUrl(), + 'numberOfItems' => \count($products), + 'itemListElement' => $itemListElement, + ]; + + return $microData; + } + + /** + * @return array + */ + protected function getFolderMicroData(Folder $folder, Lang $lang) + { + $folder->setLocale($lang->getLocale()); + + $microData = [ + '@context' => 'https://schema.org/', + '@type' => 'Guide', + 'url' => $folder->getUrl(), + "name" => $folder->getTitle(), + "abstract" => $folder->getChapo(), + ]; + + + return $microData; + } + + /** + * @return array + */ + protected function getContentMicroData($contentId, Lang $lang) + { + $content = ContentQuery::create()->filterById($contentId)->findOne(); + + if (null === $content) { + return null; + } + + $content->setLocale($lang->getLocale()); + + $microData = [ + '@context' => 'https://schema.org/', + '@type' => 'Article', + 'url' => $content->getUrl(), + "name" => $content->getTitle(), + "abstract" => $content->getChapo(), + ]; + + $defaultFoIdlder = $content->getDefaultFolderId(); + + if (null !== $defaultFoIdlder) { + $default_folder = FolderQuery::create()->findOneById($defaultFoIdlder); + if (null !== $default_folder) { + $default_folder->setLocale($lang->getLocale()); + $microData['isPartOf'] = [ + 'name' => $default_folder->getTitle(), + 'url' => $default_folder->getUrl() + ]; + } + } + + return $microData; + } +} diff --git a/domokits/local/modules/BetterSeo/composer.json b/domokits/local/modules/BetterSeo/composer.json new file mode 100644 index 0000000..79326f6 --- /dev/null +++ b/domokits/local/modules/BetterSeo/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/better-seo-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "BetterSeo" + } +} \ No newline at end of file diff --git a/domokits/local/modules/BetterSeo/templates/backOffice/default/seo-additional-fields.html b/domokits/local/modules/BetterSeo/templates/backOffice/default/seo-additional-fields.html new file mode 100644 index 0000000..39bc1db --- /dev/null +++ b/domokits/local/modules/BetterSeo/templates/backOffice/default/seo-additional-fields.html @@ -0,0 +1,196 @@ +{$pageUrl|default:null} +{$noindex_val = null} +{$nofollow_val = null} +{$json_data = null} +{$h1 = null} +{for $i=1 to 5} + {assign var="mesh_text_$i" value=null} + {assign var="mesh_url_$i" value=null} + {assign var="mesh_$i" value=null} +{/for} + +{loop type="better_seo_loop" name="better_seo_data" object_id=$object_id object_type=$object_type lang_id=$edit_language_id} +{$noindex_val = $NOINDEX} +{$nofollow_val = $NOFOLLOW} +{$json_data = $JSON_DATA} +{$h1 = $H1} +{for $i=1 to 5} + {assign var="mesh_text_$i" value={$MESH_TEXT_{$i}}} + {assign var="mesh_url_$i" value={$MESH_URL_{$i}}} + {assign var="mesh_$i" value={$MESH_{$i}}} +{/for} +{/loop} +{form name = "betterseo_form"} + +
+
+ +
+
+ + {form_hidden_fields form=$form} + {if $form_error} +
+
+
{$form_error_message}
+
+
+ {/if} + +
+ +
+ + {form_field field="noindex_checkbox"} +
+ + + {if $error} +
+ {$message} +
+ {/if} +
+ {/form_field} + + {form_field field="nofollow_checkbox"} +
+ + + {if $error} +
+ {$message} +
+ {/if} +
+ {/form_field} +
+ {intl l="noindex_nofollow.help" d="betterseo.bo.default"} +
+ + {form_field field="h1"} +
+ + + {if $error} +
+ {$message} +
+ {/if} +
+
+
+ {/form_field} + + {form_field field="json_data"} +
+ + +
+ {/form_field} + +
+ + + + + {for $i=1 to 5} + + {/for} + + + + + {for $i=1 to 5} + {$textVar = "MESH_$i"} + + + {/for} + + +
{intl l="Mesh" d="betterseo.bo.default"}
+ {intl l="Text" d="betterseo.bo.default"} {$i} +
+ {form_field field="mesh_$i"} +
+ + {if $error} +
+ {$message} +
+ {/if} +
+ {/form_field} +
+ +
+ + + + + + + + + + + + {for $i=1 to 5} + {$urlVar = "MESH_URL_$i"} + {$textVar = "MESH_TEXT_$i"} + + + + + + + {/for} + +
{intl l="Mesh links" d="betterseo.bo.default"}
+ + + {intl l="Link text" d="betterseo.bo.default"} + + {intl l="Link URL" d="betterseo.bo.default"} +
+ {intl l="Link" d="betterseo.bo.default"} {$i} + + {form_field field="mesh_text_$i"} +
+ + + {if $error} +
+ {$message} +
+ {/if} +
+ {/form_field} +
+ {form_field field="mesh_url_$i"} +
+ + + {if $error} +
+ {$message} +
+ {/if} +
+ {/form_field} +
+ + +
+
+ + +
+
+
+ +{/form} diff --git a/domokits/local/modules/BetterSeo/templates/frontOffice/default/meta_hook.html b/domokits/local/modules/BetterSeo/templates/frontOffice/default/meta_hook.html new file mode 100644 index 0000000..54ee946 --- /dev/null +++ b/domokits/local/modules/BetterSeo/templates/frontOffice/default/meta_hook.html @@ -0,0 +1,18 @@ + +{BetterSeoMicroData} + +{loop type="better_seo_loop" name="better_seo_meta_loop" object_id=$object_id object_type=$object_type lang_id=$lang_id} + {if $NOINDEX == 1 and $NOFOLLOW == 1} + + {elseif $NOINDEX == 1} + + {elseif $NOFOLLOW == 1} + + {/if} + + {if $JSON_DATA} + + {/if} +{/loop} diff --git a/domokits/local/modules/CanonicalUrl/CHANGELOG.md b/domokits/local/modules/CanonicalUrl/CHANGELOG.md new file mode 100644 index 0000000..1261d48 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/CHANGELOG.md @@ -0,0 +1,20 @@ +# 1.2.0 + +- Add canonical override in seo form + +# 1.1.1 + +- Fix exception when Thelia was not configured + +# 1.1.0 + +- Adds the unit tests in the case of a single domain +- Adds the case there is a subfolder + +# 1.0.1 + +- Fix ```installer-name``` in the composer.json file + +# 1.0.2 + +- Fix hook scope for compatibility with the other modules \ No newline at end of file diff --git a/domokits/local/modules/CanonicalUrl/CanonicalUrl.php b/domokits/local/modules/CanonicalUrl/CanonicalUrl.php new file mode 100644 index 0000000..aa9e51d --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/CanonicalUrl.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; + +class CanonicalUrl extends BaseModule +{ + /** @var string */ + const DOMAIN_NAME = 'canonicalurl'; + + const SEO_CANONICAL_META_KEY = 'seo_canonical_meta'; + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/CanonicalUrl/Config/config.xml b/domokits/local/modules/CanonicalUrl/Config/config.xml new file mode 100644 index 0000000..585a638 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Config/config.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/domokits/local/modules/CanonicalUrl/Config/module.xml b/domokits/local/modules/CanonicalUrl/Config/module.xml new file mode 100644 index 0000000..118f20b --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Config/module.xml @@ -0,0 +1,38 @@ + + + CanonicalUrl\CanonicalUrl + + Adds the canonical Url in the metas of your site + + + Ajoute l'Url canonique dans les metas de votre site + + + en_US + fr_FR + + 2.1.6 + + + Gilles Bourgeat + gilles.bourgeat@gmail.com + https://github.com/gillesbourgeat + + + Franck Allimant + CQFDev + franck@cqfdev.fr + www.cqfdev.fr + + + Vincent Lopes-Vicente + OpenStudio + vlopes@openstudio.fr + + + classic + 2.5.0 + prod + diff --git a/domokits/local/modules/CanonicalUrl/Config/routing.xml b/domokits/local/modules/CanonicalUrl/Config/routing.xml new file mode 100644 index 0000000..fc772b7 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Config/routing.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvent.php b/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvent.php new file mode 100644 index 0000000..51c9862 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvent.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\Event; + +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Class CanonicalUrlEvent. + * + * @author Gilles Bourgeat + */ +class CanonicalUrlEvent extends Event +{ + /** @var string|null */ + protected $url = null; + + /** + * @return string|null + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string|null $url + * + * @return $this + */ + public function setUrl($url) + { + if ($url !== null && $url[0] !== '/' && filter_var($url, \FILTER_VALIDATE_URL) === false) { + throw new \InvalidArgumentException('The value "'.(string) $url.'" is not a valid Url or Uri.'); + } + + $this->url = $url; + + return $this; + } +} diff --git a/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvents.php b/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvents.php new file mode 100644 index 0000000..0312382 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Event/CanonicalUrlEvents.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\Event; + +/** + * Class CanonicalUrlEvents. + * + * @author Gilles Bourgeat + */ +class CanonicalUrlEvents +{ + const GENERATE_CANONICAL = 'canonical.url.generate.canonical'; +} diff --git a/domokits/local/modules/CanonicalUrl/EventListener/CanonicalUrlListener.php b/domokits/local/modules/CanonicalUrl/EventListener/CanonicalUrlListener.php new file mode 100644 index 0000000..25a9cb7 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/EventListener/CanonicalUrlListener.php @@ -0,0 +1,249 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\EventListener; + +use BetterSeo\Model\BetterSeoQuery; +use CanonicalUrl\CanonicalUrl; +use CanonicalUrl\Event\CanonicalUrlEvent; +use CanonicalUrl\Event\CanonicalUrlEvents; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Log\Tlog; +use Thelia\Model\ConfigQuery; +use Thelia\Model\Lang; +use Thelia\Model\LangQuery; +use Thelia\Model\MetaDataQuery; + +/** + * Class CanonicalUrlListener. + * + * @author Gilles Bourgeat + */ +class CanonicalUrlListener implements EventSubscriberInterface +{ + /** @var RequestStack */ + protected $requestStack; + + /** @var Session */ + protected $session; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + public function generateUrlCanonical(CanonicalUrlEvent $event): void + { + /** @var Request $request */ + if (null === $request = $this->requestStack->getCurrentRequest()) { + return; + } + + if ($event->getUrl() !== null) { + return; + } + + if (null !== $canonicalOverride = $this->getCanonicalOverride()) { + try { + $event->setUrl($canonicalOverride); + + return; + } catch (\InvalidArgumentException $e) { + Tlog::getInstance()->addWarning($e->getMessage()); + } + } + + $parseUrlByCurrentLocale = $this->getParsedUrlByCurrentLocale(); + + if (empty($parseUrlByCurrentLocale['host'])) { + return; + } + + // Be sure to use the proper domain name + $canonicalUrl = $parseUrlByCurrentLocale['scheme'].'://'.$parseUrlByCurrentLocale['host']; + + // preserving a potential subdirectory, e.g. http://somehost.com/mydir/index.php/... + $canonicalUrl .= $request->getBaseUrl(); + + // Remove script name from path, e.g. http://somehost.com/index.php/... + $canonicalUrl = preg_replace("!/index(_dev)?\.php!", '', $canonicalUrl); + + $path = $request->getPathInfo(); + + if (!empty($path) && $path != '/') { + $canonicalUrl .= $path; + + $canonicalUrl = rtrim($canonicalUrl, '/'); + } else if (isset($parseUrlByCurrentLocale['query'])) { + $canonicalUrl .= '/?'. (array_key_exists("query", $parseUrlByCurrentLocale)) ? $parseUrlByCurrentLocale['query'] : ""; + } + + try { + $event->setUrl($canonicalUrl); + } catch (\InvalidArgumentException $e) { + Tlog::getInstance()->addWarning($e->getMessage()); + } + } + + /** + * @return array + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + CanonicalUrlEvents::GENERATE_CANONICAL => [ + 'generateUrlCanonical', 128, + ], + ]; + } + + /** + * @return array + * + * At least one element will be present within the array. + * Potential keys within this array are: + * scheme - e.g. http + * host + * port + * user + * pass + * path + * query - after the question mark ? + * fragment - after the hashmark # + */ + protected function getParsedUrlByCurrentLocale() + { + /** @var Request $request */ + $request = $this->requestStack->getCurrentRequest(); + + // for one domain by lang + if ((int) ConfigQuery::read('one_domain_foreach_lang', 0) === 1) { + // We always query the DB here, as the Lang configuration (then the related URL) may change during the + // user session lifetime, and improper URLs could be generated. This is quite odd, okay, but may happen. + $langUrl = LangQuery::create()->findPk($request->getSession()->getLang()->getId())->getUrl(); + + if (!empty($langUrl) && false !== $parse = parse_url($langUrl)) { + return $parse; + } + } + + // Configured site URL + $urlSite = ConfigQuery::read('url_site'); + if (!empty($urlSite) && false !== $parse = parse_url($urlSite)) { + return $parse; + } + + // return current URL + return parse_url($request->getUri()); + } + + /** + * @return string|null + */ + protected function getCanonicalOverride() + { + /** @var Request $request */ + $request = $this->requestStack->getCurrentRequest(); + $lang = $request->getSession()->getLang(); + + $routeParameters = $this->getRouteParameters(); + + if (null === $routeParameters) { + return null; + } + + $url = null; + + $metaCanonical = MetaDataQuery::create() + ->filterByMetaKey(CanonicalUrl::SEO_CANONICAL_META_KEY) + ->filterByElementKey($routeParameters['view']) + ->filterByElementId($routeParameters['id']) + ->findOne(); + + if (null !== $metaCanonical) { + $canonicalValues = json_decode($metaCanonical->getValue(), true); + + $url = isset($canonicalValues[$lang->getLocale()]) && ! empty($canonicalValues[$lang->getLocale()]) ? $canonicalValues[$lang->getLocale()] :null; + } + + // Try to get old field of BetterSeoModule + if (null === $url && class_exists("BetterSeo\BetterSeo")) { + try { + $betterSeoData = BetterSeoQuery::create() + ->filterByObjectType($routeParameters['view']) + ->filterByObjectId($routeParameters['id']) + ->findOne(); + + $url = $betterSeoData->setLocale($lang->getLocale()) + ->getCanonicalField(); + } catch (\Throwable $exception) { + //Catch if field doesn't exist but do nothing + } + } + + if (null === $url) { + return null; + } + + if (false === filter_var($url, \FILTER_VALIDATE_URL)) { + return rtrim($this->getSiteBaseUrlForLocale($lang), "/")."/".$url; + } + + return $url; + } + + protected function getSiteBaseUrlForLocale(Lang $lang = null) + { + if (null === $lang) { + $lang = $this->requestStack->getCurrentRequest()->getSession()->getLang(); + } + if ((int) ConfigQuery::read('one_domain_foreach_lang', 0) === 1) { + // We always query the DB here, as the Lang configuration (then the related URL) may change during the + // user session lifetime, and improper URLs could be generated. This is quite odd, okay, but may happen. + $langUrl = LangQuery::create()->findPk($lang->getId())->getUrl(); + return $langUrl; + } + + // Configured site URL + $urlSite = ConfigQuery::read('url_site'); + return $urlSite; + } + + /** + * @return array|null + */ + protected function getRouteParameters() + { + /** @var Request $request */ + $request = $this->requestStack->getCurrentRequest(); + + $view = $request->get('view'); + if (null === $view) { + $view = $request->get('_view'); + } + if (null === $view) { + return null; + } + + $id = $request->get($view.'_id'); + + if (null === $id) { + return null; + } + + return compact('view', 'id'); + } +} diff --git a/domokits/local/modules/CanonicalUrl/EventListener/SeoFormListener.php b/domokits/local/modules/CanonicalUrl/EventListener/SeoFormListener.php new file mode 100644 index 0000000..1e06cc3 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/EventListener/SeoFormListener.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\EventListener; + +use CanonicalUrl\CanonicalUrl; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Action\BaseAction; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\TheliaFormEvent; +use Thelia\Core\Event\UpdateSeoEvent; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Model\MetaDataQuery; + +class SeoFormListener extends BaseAction implements EventSubscriberInterface +{ + /** @var RequestStack */ + protected $requestStack; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + public static function getSubscribedEvents() + { + return [ + TheliaEvents::FORM_AFTER_BUILD.'.thelia_seo' => ['addCanonicalField', 128], + TheliaEvents::CATEGORY_UPDATE_SEO => ['saveCategorySeoFields', 128], + TheliaEvents::BRAND_UPDATE_SEO => ['saveBrandSeoFields', 128], + TheliaEvents::CONTENT_UPDATE_SEO => ['saveContentSeoFields', 128], + TheliaEvents::FOLDER_UPDATE_SEO => ['saveFolderSeoFields', 128], + TheliaEvents::PRODUCT_UPDATE_SEO => ['saveProductSeoFields', 128], + ]; + } + + public function saveCategorySeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + $this->saveSeoFields($event, $eventName, $dispatcher, 'category'); + } + + public function saveBrandSeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + $this->saveSeoFields($event, $eventName, $dispatcher, 'brand'); + } + + public function saveContentSeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + $this->saveSeoFields($event, $eventName, $dispatcher, 'content'); + } + + public function saveFolderSeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + $this->saveSeoFields($event, $eventName, $dispatcher, 'folder'); + } + + public function saveProductSeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + $this->saveSeoFields($event, $eventName, $dispatcher, 'product'); + } + + protected function saveSeoFields(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher, $elementKey): void + { + $form = $this->requestStack->getCurrentRequest()->get('thelia_seo'); + + if (null === $form || !\array_key_exists('id', $form) || !\array_key_exists('canonical', $form)) { + return; + } + + $canonicalValues = []; + + $canonicalMetaData = MetaDataQuery::create() + ->filterByMetaKey(CanonicalUrl::SEO_CANONICAL_META_KEY) + ->filterByElementKey($elementKey) + ->filterByElementId($form['id']) + ->findOneOrCreate(); + + if (!$canonicalMetaData->isNew()) { + $canonicalValues = json_decode($canonicalMetaData->getValue(), true); + } + + $locale = $form['locale']; + $canonicalValues[$locale] = $form['canonical']; + + $canonicalMetaData + ->setIsSerialized(0) + ->setValue(json_encode($canonicalValues)) + ->save(); + } + + public function addCanonicalField(TheliaFormEvent $event): void + { + $event->getForm()->getFormBuilder() + ->add( + 'canonical', + TextType::class + ); + } +} diff --git a/domokits/local/modules/CanonicalUrl/Hook/MetaHook.php b/domokits/local/modules/CanonicalUrl/Hook/MetaHook.php new file mode 100644 index 0000000..7f02df8 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Hook/MetaHook.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\Hook; + +use CanonicalUrl\Event\CanonicalUrlEvent; +use CanonicalUrl\Event\CanonicalUrlEvents; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class MetaHook. + * + * @author Gilles Bourgeat + */ +class MetaHook extends BaseHook +{ + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + + public function __construct(EventDispatcherInterface $eventDispatcher) + { + $this->eventDispatcher = $eventDispatcher; + } + + public function onMainHeadBottom(HookRenderEvent $hookRender): void + { + $event = new CanonicalUrlEvent(); + + $this->eventDispatcher->dispatch( + $event, + CanonicalUrlEvents::GENERATE_CANONICAL, + ); + + if ($event->getUrl()) { + $hookRender->add(''); + } + } +} diff --git a/domokits/local/modules/CanonicalUrl/Hook/SeoUpdateFormHook.php b/domokits/local/modules/CanonicalUrl/Hook/SeoUpdateFormHook.php new file mode 100644 index 0000000..90d780f --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Hook/SeoUpdateFormHook.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\Hook; + +use CanonicalUrl\CanonicalUrl; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Model\MetaDataQuery; + +class SeoUpdateFormHook extends BaseHook +{ + public function addInputs(HookRenderEvent $event): void + { + $id = $event->getArgument('id'); + $type = $event->getArgument('type'); + + $canonical = null; + $canonicalMetaData = MetaDataQuery::create() + ->filterByMetaKey(CanonicalUrl::SEO_CANONICAL_META_KEY) + ->filterByElementKey($type) + ->filterByElementId($id) + ->findOneOrCreate(); + + $canonicalMetaDataValues = json_decode($canonicalMetaData->getValue(), true); + + $lang = $this->getSession()->getAdminEditionLang(); + + if (isset($canonicalMetaDataValues[$lang->getLocale()])) { + $canonical = $canonicalMetaDataValues[$lang->getLocale()]; + } + + $event->add($this->render( + 'hook-seo-update-form.html', + [ + 'form' => $event->getArgument('form'), + 'canonical' => $canonical, + ] + )); + } +} diff --git a/domokits/local/modules/CanonicalUrl/I18n/backOffice/default/en_US.php b/domokits/local/modules/CanonicalUrl/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..e9c0307 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/I18n/backOffice/default/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Surcharge de l\'url canonique' => 'Canonical url override', +]; diff --git a/domokits/local/modules/CanonicalUrl/LICENSE.txt b/domokits/local/modules/CanonicalUrl/LICENSE.txt new file mode 100644 index 0000000..cfbc66d --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/domokits/local/modules/CanonicalUrl/Readme.md b/domokits/local/modules/CanonicalUrl/Readme.md new file mode 100644 index 0000000..5c4fa63 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Readme.md @@ -0,0 +1,47 @@ +# Canonical Url + +This module generates a canonical URL for every page of your shop. Once activated, you'll find a `` tag in the header of your pages. + +## Examples + +- If the page URL is not rewritten, the canonical URL will contain all the URL parameters. Example for : For URL ```http://demo.thelia.net/?view=product&locale=en_US&product_id=18``` + ```html + + ``` + Obviously, this is far from ideal. Consider activating URL rewriting ! + +- When the page URL contains the script name (index.php), it will be removed from the canonical URL. Example, the canonical URL of ```http://demo.thelia.net/index.php?view=product&locale=en_US&product_id=18``` is : + ```html + + ``` + + When a rewritten URL contains parameters, these parameters a removed. For ```http://demo.thelia.net/index.php/en_en-your-path.html?page=44```, the canonical URL is : + ```html + + ``` + +- If the page URL contains a domain which is not the main shop domain, this domain is replaced by the main shop domain. For ```http://demo458.thelia.net/index.php/en_en-your-path.html?page=44``` the canonical URL is : + ```html + + ``` + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is CanonicalUrl. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/canonical-url-module:~2.1 +``` + +## Usage + +You just have to activate the module and check the meta tags of your shop. + +The canonical will be generated automatically but you can define a canonical url in seo form for each item if you want override the generated url. diff --git a/domokits/local/modules/CanonicalUrl/Tests/CanonicalUrlTest.php b/domokits/local/modules/CanonicalUrl/Tests/CanonicalUrlTest.php new file mode 100644 index 0000000..40bf0e7 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/Tests/CanonicalUrlTest.php @@ -0,0 +1,245 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CanonicalUrl\Tests; + +use CanonicalUrl\Event\CanonicalUrlEvent; +use CanonicalUrl\EventListener\CanonicalUrlListener; +use Symfony\Component\HttpFoundation\Request; + +/** + * Class CanonicalUrlTest. + * + * @author Gilles Bourgeat + */ +class CanonicalUrlTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp(): void + { + /*$config = $this->getMock('Thelia\Model\ConfigQuery'); + + $config->expects($this->any()) + ->method('read') + ->with('allow_slash_ended_uri') + ->will($this->returnValue(true));*/ + } + + public function testRemoveFileIndex(): void + { + $this->performList('http://myhost.com/test', [ + 'http://myhost.com/index.php/test', + 'http://myhost.com/index.php/test/', + 'http://myhost.com/index.php/test?page=22&list=1', + 'http://myhost.com/index.php/test/?page=22&list=1', + ]); + } + + public function testRemoveFileIndexDev(): void + { + $this->performList('http://myhost.com/test', [ + 'http://myhost.com/index_dev.php/test', + 'http://myhost.com/index_dev.php/test/', + 'http://myhost.com/index_dev.php/test?page=22&list=1', + 'http://myhost.com/index_dev.php/test/?page=22&list=1', + ], $this->fakeServer( + '/var/www/web/index_dev.php', + '/index_dev.php' + )); + } + + public function testHTTPWithSubDomain(): void + { + $this->performList('http://mysubdomain.myhost.com/test', [ + 'http://mysubdomain.myhost.com/index.php/test/?page=22&list=1', + ]); + } + + public function testHTTPS(): void + { + $this->performList('https://myhost.com/test', [ + 'https://myhost.com/index.php/test/?page=22&list=1', + ]); + } + + public function testHTTPSWithSubDomain(): void + { + $this->performList('https://mysubdomain.myhost.com/test', [ + 'https://mysubdomain.myhost.com/index.php/test/?page=22&list=1', + ]); + } + + public function testHTTPWithSubdirectory(): void + { + $this->performList('http://myhost.com/web/test', [ + 'http://myhost.com/web/index.php/test', + 'http://myhost.com/web/index.php/test/', + 'http://myhost.com/web/index.php/test?page=22&list=1', + 'http://myhost.com/web/index.php/test?page=22&list=1/', + ], $this->fakeServer( + '/var/www/web/index.php', + '/web/index.php' + )); + + $this->performList('http://myhost.com/web/test', [ + 'http://myhost.com/web/index_dev.php/test', + 'http://myhost.com/web/index_dev.php/test/', + 'http://myhost.com/web/index_dev.php/test?page=22&list=1', + 'http://myhost.com/web/index_dev.php/test?page=22&list=1/', + ], $this->fakeServer( + '/var/www/web/index_dev.php', + '/web/index_dev.php' + )); + } + + public function testHTTPWithMultipleSubdirectory(): void + { + $this->performList('http://myhost.com/web/web2/web3/test', [ + 'http://myhost.com/web/web2/web3/index.php/test/?page=22&list=1', + ], $this->fakeServer( + '/var/www/web/web2/web3/index.php', + '/web/web2/web3/index.php' + )); + + $this->performList('http://myhost.com/web/web2/web3/test', [ + 'http://myhost.com/web/web2/web3/index_dev.php/test/?page=22&list=1', + ], $this->fakeServer( + '/var/www/web/web2/web3/index_dev.php', + '/web/web2/web3/index_dev.php' + )); + } + + public function testHTTPSWithSubdirectory(): void + { + $this->performList('https://myhost.com/web/test', [ + 'https://myhost.com/web/index.php/test/?page=22&list=1', + ], $this->fakeServer( + '/var/www/web/index.php', + '/web/index.php' + )); + } + + public function testHTTPSWithMultipleSubdirectory(): void + { + $this->performList('https://myhost.com/web/web2/web3/test', [ + 'https://myhost.com/web/web2/web3/index.php/test/?page=22&list=1', + ], $this->fakeServer( + '/var/www/web/web2/web3/index.php', + '/web/web2/web3/index.php' + )); + } + + public function testWithNoPath(): void + { + $this->performList('http://myhost.com/?list=22&page=1', [ + 'http://myhost.com?list=22&page=1', + 'http://myhost.com/?list=22&page=1', + 'http://myhost.com/index.php?list=22&page=1', + 'http://myhost.com/index.php/?list=22&page=1', + ]); + + $this->performList('http://myhost.com/?list=22&page=1', [ + 'http://myhost.com/index_dev.php?list=22&page=1', + 'http://myhost.com/index_dev.php/?list=22&page=1', + ], $this->fakeServer( + '/var/www/web/index_dev.php', + '/index_dev.php' + )); + } + + public function testWithNoPathAndMultipleSubdirectory(): void + { + $this->performList('http://myhost.com/web/?list=22&page=1', [ + 'http://myhost.com/web/index.php?list=22&page=1', + 'http://myhost.com/web/?list=22&page=1', + 'http://myhost.com/web/index.php?list=22&page=1', + 'http://myhost.com/web/index.php/?list=22&page=1', + ], $this->fakeServer( + '/var/www/web/index.php', + '/web/index.php' + )); + + $this->performList('http://myhost.com/web/?list=22&page=1', [ + 'http://myhost.com/web/index_dev.php?list=22&page=1', + 'http://myhost.com/web/index_dev.php/?list=22&page=1', + ], $this->fakeServer( + '/var/www/web/index_dev.php', + '/web/index_dev.php' + )); + } + + public function testWithNotRewrittenUrl(): void + { + $this->performList('http://myhost.com/web/?view=category&lang=fr_FR&category_id=48', [ + 'http://myhost.com/web/index.php?view=category&lang=fr_FR&category_id=48', + 'http://myhost.com/web/?lang=fr_FR&view=category&category_id=48', + 'http://myhost.com/web/index.php?&category_id=48&lang=fr_FR&view=category', + 'http://myhost.com/web/index.php/?category_id=48&view=category&lang=fr_FR', + ], $this->fakeServer( + '/var/www/web/index.php', + '/web/index.php' + )); + } + + public function testOverrideCanonicalEvent(): void + { + $canonicalUrlListener = new CanonicalUrlListener(Request::create('https://myhost.com/test')); + + $event = new CanonicalUrlEvent(); + + // override canonical + $canonical = 'http://myscanonical.com'; + $event->setUrl($canonical); + + $canonicalUrlListener->generateUrlCanonical($event); + + $this->assertEquals($canonical, $event->getUrl()); + } + + /** + * @param string $scriptFileName + * @param string $scriptName + * + * @return array + */ + protected function fakeServer( + $scriptFileName = '/var/www/web/index.php', + $scriptName = '/index.php' + ) { + return [ + 'SCRIPT_FILENAME' => $scriptFileName, + 'SCRIPT_NAME' => $scriptName, + ]; + } + + /** + * @param string $canonicalExpected canonical expected + * @param array $list array of uri + */ + protected function performList($canonicalExpected, array $list, array $server = []): void + { + if (empty($server)) { + $server = $this->fakeServer(); + } + + foreach ($list as $uri) { + $canonicalUrlListener = new CanonicalUrlListener( + Request::create($uri, 'GET', [], [], [], $server) + ); + + $event = new CanonicalUrlEvent(); + + $canonicalUrlListener->generateUrlCanonical($event); + + $this->assertEquals($canonicalExpected, $event->getUrl()); + } + } +} diff --git a/domokits/local/modules/CanonicalUrl/composer.json b/domokits/local/modules/CanonicalUrl/composer.json new file mode 100644 index 0000000..0d30553 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/canonical-url-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "CanonicalUrl" + } +} \ No newline at end of file diff --git a/domokits/local/modules/CanonicalUrl/templates/backOffice/default/hook-seo-update-form.html b/domokits/local/modules/CanonicalUrl/templates/backOffice/default/hook-seo-update-form.html new file mode 100644 index 0000000..502f863 --- /dev/null +++ b/domokits/local/modules/CanonicalUrl/templates/backOffice/default/hook-seo-update-form.html @@ -0,0 +1,6 @@ +{form_field form=$form field='canonical' } +
+ + +
+{/form_field} \ No newline at end of file diff --git a/domokits/local/modules/Carousel/CHANGELOG.md b/domokits/local/modules/Carousel/CHANGELOG.md new file mode 100644 index 0000000..b4525a3 --- /dev/null +++ b/domokits/local/modules/Carousel/CHANGELOG.md @@ -0,0 +1,6 @@ +# 2.3.0-alpha1 + +- Moved the images from the directory 'media' in the module to thelia/local/media/images/carousel. +- The current images will be automatically copied in the new directory during the update of the module +- Removed AdminIncludes directory +- All html,js and css files are now in 'templates' \ No newline at end of file diff --git a/domokits/local/modules/Carousel/Carousel.php b/domokits/local/modules/Carousel/Carousel.php new file mode 100644 index 0000000..ac2cd89 --- /dev/null +++ b/domokits/local/modules/Carousel/Carousel.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel; + +use Propel\Runtime\Connection\ConnectionInterface; +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Finder\SplFileInfo; +use Thelia\Install\Database; +use Thelia\Model\ConfigQuery; +use Thelia\Module\BaseModule; + +/** + * Class Carousel. + * + * @author Franck Allimant + */ +class Carousel extends BaseModule +{ + public const DOMAIN_NAME = 'carousel'; + + /** + * @return bool true to continue module activation, false to prevent it + */ + public function preActivation(ConnectionInterface $con = null) + { + if (!self::getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, [__DIR__.'/Config/TheliaMain.sql']); + + self::setConfigValue('is_initialized', true); + } + + return true; + } + + public function destroy(ConnectionInterface $con = null, $deleteModuleData = false): void + { + $database = new Database($con); + + $database->insertSql(null, [__DIR__.'/Config/sql/destroy.sql']); + } + + public function getUploadDir() + { + $uploadDir = ConfigQuery::read('images_library_path'); + + if ($uploadDir === null) { + $uploadDir = THELIA_LOCAL_DIR.'media'.DS.'images'; + } else { + $uploadDir = THELIA_ROOT.$uploadDir; + } + + return $uploadDir.DS.self::DOMAIN_NAME; + } + + /** + * @param string $currentVersion + * @param string $newVersion + * + * @author Thomas Arnaud + */ + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + $uploadDir = $this->getUploadDir(); + $fileSystem = new Filesystem(); + + if (!$fileSystem->exists($uploadDir) && $fileSystem->exists(__DIR__.DS.'media'.DS.'carousel')) { + $finder = new Finder(); + $finder->files()->in(__DIR__.DS.'media'.DS.'carousel'); + + $fileSystem->mkdir($uploadDir); + + /** @var SplFileInfo $file */ + foreach ($finder as $file) { + copy($file, $uploadDir.DS.$file->getRelativePathname()); + } + $fileSystem->remove(__DIR__.DS.'media'); + } + + $finder = (new Finder())->files()->name('#.*?\.sql#')->sortByName()->in(__DIR__.DS.'Config'.DS.'update'); + + if (0 === $finder->count()) { + return; + } + + $database = new Database($con); + + // apply update only if table exists + if ($database->execute("SHOW TABLES LIKE 'carousel'")->rowCount() === 0) { + return; + } + + /** @var SplFileInfo $updateSQLFile */ + foreach ($finder as $updateSQLFile) { + if (version_compare($currentVersion, str_replace('.sql', '', $updateSQLFile->getFilename()), '<')) { + $database->insertSql(null, [$updateSQLFile->getPathname()]); + } + } + } + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/Carousel/Config/TheliaMain.sql b/domokits/local/modules/Carousel/Config/TheliaMain.sql new file mode 100644 index 0000000..f39cc5a --- /dev/null +++ b/domokits/local/modules/Carousel/Config/TheliaMain.sql @@ -0,0 +1,51 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- carousel +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `carousel`; + +CREATE TABLE `carousel` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `file` VARCHAR(255), + `position` INTEGER, + `disable` INTEGER, + `group` VARCHAR(255), + `url` VARCHAR(255), + `limited` INTEGER, + `start_date` DATETIME, + `end_date` DATETIME, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- carousel_i18n +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `carousel_i18n`; + +CREATE TABLE `carousel_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `alt` VARCHAR(255), + `title` VARCHAR(255), + `description` LONGTEXT, + `chapo` TEXT, + `postscriptum` TEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `carousel_i18n_fk_2ec1b2` + FOREIGN KEY (`id`) + REFERENCES `carousel` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/Carousel/Config/config.xml b/domokits/local/modules/Carousel/Config/config.xml new file mode 100644 index 0000000..443a64e --- /dev/null +++ b/domokits/local/modules/Carousel/Config/config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/domokits/local/modules/Carousel/Config/module.xml b/domokits/local/modules/Carousel/Config/module.xml new file mode 100644 index 0000000..c9eeff7 --- /dev/null +++ b/domokits/local/modules/Carousel/Config/module.xml @@ -0,0 +1,24 @@ + + + Carousel\Carousel + + An image carousel + + + Un carrousel d'images + + + en_US + fr_FR + + 2.5.4 + + Manuel Raynaud, Franck Allimant + manu@raynaud.io, franck@cqfdev.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/Carousel/Config/routing.xml b/domokits/local/modules/Carousel/Config/routing.xml new file mode 100644 index 0000000..44e9590 --- /dev/null +++ b/domokits/local/modules/Carousel/Config/routing.xml @@ -0,0 +1,42 @@ + + + + + + + Carousel\Controller\ConfigurationController::uploadImage + + + + Carousel\Controller\ConfigurationController::updateAction + + + + Carousel\Controller\ConfigurationController::deleteAction + + + diff --git a/domokits/local/modules/Carousel/Config/schema.xml b/domokits/local/modules/Carousel/Config/schema.xml new file mode 100644 index 0000000..9764d90 --- /dev/null +++ b/domokits/local/modules/Carousel/Config/schema.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/Carousel/Config/sql/destroy.sql b/domokits/local/modules/Carousel/Config/sql/destroy.sql new file mode 100644 index 0000000..e611606 --- /dev/null +++ b/domokits/local/modules/Carousel/Config/sql/destroy.sql @@ -0,0 +1,6 @@ +SET FOREIGN_KEY_CHECKS = 0; + +DROP TABLE IF EXISTS `carousel`; +DROP TABLE IF EXISTS `carousel_i18n`; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/domokits/local/modules/Carousel/Config/sqldb.map b/domokits/local/modules/Carousel/Config/sqldb.map new file mode 100644 index 0000000..a58fd16 --- /dev/null +++ b/domokits/local/modules/Carousel/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +TheliaMain.sql=TheliaMain diff --git a/domokits/local/modules/Carousel/Config/update/2.4.0.sql b/domokits/local/modules/Carousel/Config/update/2.4.0.sql new file mode 100644 index 0000000..8f95a9a --- /dev/null +++ b/domokits/local/modules/Carousel/Config/update/2.4.0.sql @@ -0,0 +1 @@ +ALTER TABLE `carousel` ADD (`disable` INTEGER, `group` VARCHAR(255),`limited` INTEGER, `start_date` DATETIME, `end_date` DATETIME); diff --git a/domokits/local/modules/Carousel/Controller/ConfigurationController.php b/domokits/local/modules/Carousel/Controller/ConfigurationController.php new file mode 100644 index 0000000..a79d460 --- /dev/null +++ b/domokits/local/modules/Carousel/Controller/ConfigurationController.php @@ -0,0 +1,196 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Controller; + +use Carousel\Form\CarouselImageForm; +use Carousel\Form\CarouselUpdateForm; +use Carousel\Model\Carousel; +use Carousel\Model\CarouselQuery; +use Symfony\Component\Form\Form; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Event\File\FileCreateOrUpdateEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Form\TheliaFormFactory; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Model\Lang; +use Thelia\Model\LangQuery; +use Thelia\Tools\URL; + +/** + * Class ConfigurationController. + * + * @author manuel raynaud + */ +class ConfigurationController extends BaseAdminController +{ + public function uploadImage( + Request $request, + TheliaFormFactory $formFactory, + EventDispatcherInterface $eventDispatcher + ) { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::CREATE)) { + return $response; + } + + $form = $formFactory->createForm(CarouselImageForm::class); + $error_message = null; + try { + $formData = $this->validateForm($form)->getData(); + + /** @var UploadedFile $fileBeingUploaded */ + $fileBeingUploaded = $formData['file']; + + $fileModel = new Carousel(); + + $fileCreateOrUpdateEvent = new FileCreateOrUpdateEvent(1); + $fileCreateOrUpdateEvent->setModel($fileModel); + $fileCreateOrUpdateEvent->setUploadedFile($fileBeingUploaded); + + $eventDispatcher->dispatch( + $fileCreateOrUpdateEvent, + TheliaEvents::IMAGE_SAVE + ); + + // Compensate issue #1005 + $langs = LangQuery::create()->find(); + + /** @var Lang $lang */ + foreach ($langs as $lang) { + $fileCreateOrUpdateEvent->getModel()->setLocale($lang->getLocale())->setTitle('')->save(); + } + + $response = $this->redirectToConfigurationPage(); + } catch (FormValidationException $e) { + $error_message = $this->createStandardFormValidationErrorMessage($e); + } + + if (null !== $error_message) { + $this->setupFormErrorContext( + 'carousel upload', + $error_message, + $form + ); + + $response = $this->render( + 'module-configure', + [ + 'module_code' => 'Carousel', + ] + ); + } + + return $response; + } + + /** + * @param Form $form + * @param string $fieldName + * @param int $id + * + * @return string + */ + protected function getFormFieldValue($form, $fieldName, $id) + { + $value = $form->get(sprintf('%s%d', $fieldName, $id))->getData(); + + return $value; + } + + public function updateAction( + TheliaFormFactory $formFactory + ) { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::UPDATE)) { + return $response; + } + + $form = $formFactory->createForm(CarouselUpdateForm::class); + + $error_message = null; + + try { + $updateForm = $this->validateForm($form); + + $carousels = CarouselQuery::create()->findAllByPosition(); + + $locale = $this->getCurrentEditionLocale(); + + /** @var Carousel $carousel */ + foreach ($carousels as $carousel) { + $id = $carousel->getId(); + + $carousel + ->setPosition($this->getFormFieldValue($updateForm, 'position', $id)) + ->setDisable($this->getFormFieldValue($updateForm, 'disable', $id)) + ->setUrl($this->getFormFieldValue($updateForm, 'url', $id)) + ->setLocale($locale) + ->setTitle($this->getFormFieldValue($updateForm, 'title', $id)) + ->setAlt($this->getFormFieldValue($updateForm, 'alt', $id)) + ->setChapo($this->getFormFieldValue($updateForm, 'chapo', $id)) + ->setDescription($this->getFormFieldValue($updateForm, 'description', $id)) + ->setPostscriptum($this->getFormFieldValue($updateForm, 'postscriptum', $id)) + ->setGroup($this->getFormFieldValue($updateForm, 'group', $id)) + ->setLimited($this->getFormFieldValue($updateForm, 'limited', $id)) + ->setStartDate($this->getFormFieldValue($updateForm, 'start_date', $id)) + ->setEndDate($this->getFormFieldValue($updateForm, 'end_date', $id)) + ->save(); + } + + $response = $this->redirectToConfigurationPage(); + } catch (FormValidationException $e) { + $error_message = $this->createStandardFormValidationErrorMessage($e); + } + + if (null !== $error_message) { + $this->setupFormErrorContext( + 'carousel upload', + $error_message, + $form + ); + + $response = $this->render('module-configure', ['module_code' => 'Carousel']); + } + + return $response; + } + + public function deleteAction( + Request $request + ) { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, ['carousel'], AccessManager::DELETE)) { + return $response; + } + + $imageId = $request->get('image_id'); + + if ($imageId != '') { + $carousel = CarouselQuery::create()->findPk($imageId); + + if (null !== $carousel) { + $carousel->delete(); + } + } + + return $this->redirectToConfigurationPage(); + } + + protected function redirectToConfigurationPage() + { + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/Carousel')); + } +} diff --git a/domokits/local/modules/Carousel/Form/CarouselImageForm.php b/domokits/local/modules/Carousel/Form/CarouselImageForm.php new file mode 100644 index 0000000..02653ee --- /dev/null +++ b/domokits/local/modules/Carousel/Form/CarouselImageForm.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Form; + +use Carousel\Carousel; +use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Validator\Constraints\Image; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; + +/** + * Class CarouselImageForm. + * + * @author manuel raynaud + */ +class CarouselImageForm extends BaseForm +{ + protected function buildForm(): void + { + $translator = Translator::getInstance(); + $this->formBuilder + ->add( + 'file', + FileType::class, + [ + 'constraints' => [ + new Image(), + ], + 'label' => $translator->trans('Carousel image', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'file', + ], + ] + ); + } +} diff --git a/domokits/local/modules/Carousel/Form/CarouselUpdateForm.php b/domokits/local/modules/Carousel/Form/CarouselUpdateForm.php new file mode 100644 index 0000000..f9e0497 --- /dev/null +++ b/domokits/local/modules/Carousel/Form/CarouselUpdateForm.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Form; + +use Carousel\Carousel; +use Carousel\Model\CarouselQuery; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\UrlType; +use Thelia\Form\BaseForm; + +/** + * Class CarouselUpdateForm. + * + * @author manuel raynaud + */ +class CarouselUpdateForm extends BaseForm +{ + protected function buildForm(): void + { + $formBuilder = $this->formBuilder; + + $carousels = CarouselQuery::create()->orderByPosition()->find(); + + /** @var \Carousel\Model\Carousel $carousel */ + foreach ($carousels as $carousel) { + $id = $carousel->getId(); + + $formBuilder->add( + 'position'.$id, + TextType::class, + [ + 'label' => $this->translator->trans('Image position in carousel', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'position'.$id, + ], + 'required' => false, + 'attr' => [ + 'placeholder' => $this->translator->trans( + 'Image position in carousel', + [], + Carousel::DOMAIN_NAME + ), + ], + ] + )->add( + 'alt'.$id, + TextType::class, + [ + 'label' => $this->translator->trans('Alternative image text', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'alt'.$id, + ], + 'required' => false, + 'attr' => [ + 'placeholder' => $this->translator->trans( + 'Displayed when image is not visible', + [], + Carousel::DOMAIN_NAME + ), + ], + ] + )->add( + 'group'.$id, + TextType::class, + [ + 'label' => $this->translator->trans('Group image', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'group'.$id, + ], + 'required' => false, + 'attr' => [ + 'placeholder' => $this->translator->trans( + 'Group of images', + [], + Carousel::DOMAIN_NAME + ), + ], + ] + )->add( + 'url'.$id, + UrlType::class, + [ + 'label' => $this->translator->trans('Image URL', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'url'.$id, + ], + 'required' => false, + 'attr' => [ + 'placeholder' => $this->translator->trans( + 'Please enter a valid URL', + [], + Carousel::DOMAIN_NAME + ), + ], + ] + )->add( + 'title'.$id, + TextType::class, + [ + 'constraints' => [], + 'required' => false, + 'label' => $this->translator->trans('Title', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'title_field'.$id, + ], + 'attr' => [ + 'placeholder' => $this->translator->trans('A descriptive title', [], Carousel::DOMAIN_NAME), + ], + ] + )->add( + 'chapo'.$id, + TextareaType::class, + [ + 'constraints' => [], + 'required' => false, + 'label' => $this->translator->trans('Summary', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'summary_field'.$id, + 'help' => $this->translator->trans( + 'A short description, used when a summary or an introduction is required', + [], + Carousel::DOMAIN_NAME + ), + ], + 'attr' => [ + 'rows' => 3, + 'placeholder' => $this->translator->trans('Short description text', [], Carousel::DOMAIN_NAME), + ], + ] + )->add( + 'description'.$id, + TextareaType::class, + [ + 'constraints' => [], + 'required' => false, + 'label' => $this->translator->trans('Detailed description', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'detailed_description_field'.$id, + 'help' => $this->translator->trans('The detailed description.', [], Carousel::DOMAIN_NAME), + ], + 'attr' => [ + 'rows' => 5, + ], + ] + )->add( + 'disable'.$id, + CheckboxType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Disable image', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'enable'.$id, + ], + ] + )->add( + 'limited'.$id, + CheckboxType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Limited', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'limited'.$id, + ], + ] + )->add( + 'start_date'.$id, + DateTimeType::class, + [ + 'label' => $this->translator->trans('Start date', [], Carousel::DOMAIN_NAME), + 'widget' => 'single_text', + 'required' => false, + ] + )->add( + 'end_date'.$id, + DateTimeType::class, + [ + 'label' => $this->translator->trans('End date', [], Carousel::DOMAIN_NAME), + 'widget' => 'single_text', + 'required' => false, + ] + )->add( + 'postscriptum'.$id, + TextareaType::class, + [ + 'constraints' => [], + 'required' => false, + 'label' => $this->translator->trans('Conclusion', [], Carousel::DOMAIN_NAME), + 'label_attr' => [ + 'for' => 'conclusion_field'.$id, + 'help' => $this->translator->trans( + 'A short text, used when an additional or supplemental information is required.', + [], + Carousel::DOMAIN_NAME + ), + ], + 'attr' => [ + 'placeholder' => $this->translator->trans('Short additional text', [], Carousel::DOMAIN_NAME), + 'rows' => 3, + ], + ] + ); + } + } + + public static function getName() + { + return 'carousel_update'; + } +} diff --git a/domokits/local/modules/Carousel/Hook/BackHook.php b/domokits/local/modules/Carousel/Hook/BackHook.php new file mode 100644 index 0000000..25c4a35 --- /dev/null +++ b/domokits/local/modules/Carousel/Hook/BackHook.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Hook; + +use Carousel\Carousel; +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Tools\URL; + +/** + * Class BackHook. + * + * @author Emmanuel Nurit + */ +class BackHook extends BaseHook +{ + /** + * Add a new entry in the admin tools menu. + * + * should add to event a fragment with fields : id,class,url,title + */ + public function onMainTopMenuTools(HookRenderBlockEvent $event): void + { + $event->add( + [ + 'id' => 'tools_menu_carousel', + 'class' => '', + 'url' => URL::getInstance()->absoluteUrl('/admin/module/Carousel'), + 'title' => $this->trans('Edit your carousel', [], Carousel::DOMAIN_NAME), + ] + ); + } +} diff --git a/domokits/local/modules/Carousel/I18n/backOffice/default/de_DE.php b/domokits/local/modules/Carousel/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..00b6c40 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/backOffice/default/de_DE.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Add an image to the carousel' => 'Ein Bild zu Karussell hinzufügen', + 'Add this image to the carousel' => 'Dieses Bild zu Karussell hinzufügen', + 'Carousel image' => 'Karussell-Bild', + 'Carousel images' => 'Karussell-Bilder', + 'Delete a carousel image' => 'Ein Karussell-Bild löschen', + 'Do you really want to remove this image from the carousel ?' => 'Wollen Sie dieses Bild wirklich aus dem Karussell entfernen?', + 'Edit your carousel.' => 'Karussell bearbeiten.', + 'Remove this image' => 'Dieses Bild entfernen', + 'Your carousel contains no image. Please add one using the form above.' => 'Das Karussell enthält kein Bild. Bitte fügen Sie mit dem Formular oben eines hinzu.', + 'Position' => 'Position', +]; diff --git a/domokits/local/modules/Carousel/I18n/backOffice/default/en_US.php b/domokits/local/modules/Carousel/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..a55382d --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/backOffice/default/en_US.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Add an image to the carousel' => 'Add an image to the carousel', + 'Add this image to the carousel' => 'Add this image to the carousel', + 'Carousel image' => 'Carousel image', + 'Carousel images' => 'Carousel images', + 'Delete a carousel image' => 'Delete a carousel image', + 'Do you really want to remove this image from the carousel ?' => 'Do you really want to remove this image from the carousel ?', + 'Edit your carousel.' => 'Edit your carousel.', + 'Remove this image' => 'Remove this image', + 'Your carousel contains no image. Please add one using the form above.' => 'Your carousel contains no image. Please add one using the form above.', + 'Position' => 'Position', + 'YYYY-MM-DD' => 'YYYY-MM-DD', +]; diff --git a/domokits/local/modules/Carousel/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/Carousel/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..0b43a67 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Add an image to the carousel' => 'Ajouter une image au carrousel', + 'Add this image to the carousel' => 'Ajouter l\'image au carrousel', + 'Carousel image' => 'Image du carrousel', + 'Carousel images' => 'Images du carrousel', + 'Delete a carousel image' => 'Supprimer une image du carrousel', + 'Do you really want to remove this image from the carousel ?' => 'Voulez-vous vraiment retirer cette image du carrousel ?', + 'Edit your carousel.' => 'Modifier votre carrousel', + 'Remove this image' => 'Supprimer cette image', + 'Your carousel contains no image. Please add one using the form above.' => 'Votre carrousel ne contient aucune image. Ajoutez votre première image avec le formulaire ci-dessus', + 'Position' => 'Position', + 'YYYY-MM-DD' => 'AAAA-MM-JJ', +]; diff --git a/domokits/local/modules/Carousel/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/Carousel/I18n/backOffice/default/ru_RU.php new file mode 100644 index 0000000..5a162b4 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Add an image to the carousel' => 'Добавить изображение в карусель', + 'Add this image to the carousel' => 'Добавить это изображение в карусель', + 'Carousel image' => 'Изображение карусели', + 'Carousel images' => 'Изображения карусели', + 'Delete a carousel image' => 'Удалить изображение карусели', + 'Do you really want to remove this image from the carousel ?' => 'Вы действительно хотите удалить это изображение из карусели ?', + 'Edit your carousel.' => 'Редактировать вашу карусель.', + 'Remove this image' => 'Удалить это изображение', + 'Your carousel contains no image. Please add one using the form above.' => 'Ваша карусель не содержит изображений. Пожалуйста, добавьте одно используя форму ниже.', + 'Position' => 'Позиция', +]; diff --git a/domokits/local/modules/Carousel/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/Carousel/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..252bcb1 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Add an image to the carousel' => 'Slayt için bir resim ekle', + 'Add this image to the carousel' => 'slayt için bu resim ekleme', + 'Carousel image' => 'slayt görüntü', + 'Carousel images' => 'slayt görüntüleri', + 'Delete a carousel image' => 'Bir slayt resmi silme', + 'Do you really want to remove this image from the carousel ?' => 'Bu görüntüyü slayttan kaldırmak istiyor musunuz?', + 'Edit your carousel.' => 'slayt düzenleyin.', + 'Remove this image' => 'Bu resmi kaldırma', + 'Your carousel contains no image. Please add one using the form above.' => 'Senin slayt hiçbir görüntü içermiyor . Lütfen yukarıdaki formu kullanarak ekleyin.', + 'Position' => 'Pozisyon', +]; diff --git a/domokits/local/modules/Carousel/I18n/de_DE.php b/domokits/local/modules/Carousel/I18n/de_DE.php new file mode 100644 index 0000000..fa52b4b --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/de_DE.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'Beschreibungstitel', + 'A short description, used when a summary or an introduction is required' => 'Eine kurze beschreibung, benutzt wenn eine Zusammenfassung order eine Einleitung ist nötig', + 'A short text, used when an additional or supplemental information is required.' => 'Ein kurzer Text, der verwendet wird, wenn eine zusätzliche oder ergänzende Information erforderlich ist.', + 'Alternative image text' => 'Alternativer Bildtext', + 'Carousel image' => 'Karussell-Bild', + 'Conclusion' => 'Abschluss', + 'Detailed description' => 'Detaillierte Beschreibung', + 'Displayed when image is not visible' => 'Angezeigt, wenn das Bild nicht sichtbar ist', + 'Image URL' => 'Bild-URL', + 'Image position in carousel' => 'Position des Bildes im Karussell', + 'Please enter a valid URL' => 'Bitte geben Sie eine gültige URL ein', + 'Short additional text' => 'Kurzer zusätzlicher Text', + 'Short description text' => 'Kurzes Beschreibungstext', + 'Summary' => 'Zusammenfassung', + 'The detailed description.' => 'Die detaillierte Beschreibung.', + 'Title' => 'Titel', +]; diff --git a/domokits/local/modules/Carousel/I18n/en_US.php b/domokits/local/modules/Carousel/I18n/en_US.php new file mode 100644 index 0000000..f3423c2 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/en_US.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'A descriptive title', + 'A short description, used when a summary or an introduction is required' => 'A short description, used when a summary or an introduction is required', + 'A short text, used when an additional or supplemental information is required.' => 'A short text, used when an additional or supplemental information is required.', + 'Alternative image text' => 'Alternative image text', + 'Carousel image' => 'Carousel image', + 'Conclusion' => 'Conclusion', + 'Detailed description' => 'Detailed description', + 'Displayed when image is not visible' => 'Displayed when image is not visible', + 'Edit your carousel' => 'Edit your carousel', + 'Image URL' => 'Image URL', + 'Image position in carousel' => 'Image position in carousel', + 'Please enter a valid URL' => 'Please enter a valid URL', + 'Short additional text' => 'Short additional text', + 'Short description text' => 'Short description text', + 'Summary' => 'Summary', + 'The detailed description.' => 'The detailed description.', + 'Title' => 'Title', + 'YYYY-MM-DD' => 'AAAA-MM-JJ', +]; diff --git a/domokits/local/modules/Carousel/I18n/fr_FR.php b/domokits/local/modules/Carousel/I18n/fr_FR.php new file mode 100644 index 0000000..2822cff --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/fr_FR.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'Un titre descriptif', + 'A short description, used when a summary or an introduction is required' => 'Une courte description, utilisée lorsqu\'un résumé ou une introduction est requise', + 'A short text, used when an additional or supplemental information is required.' => 'Un texte court, utilisé quand une conclusion ou une information complémentaire est nécessaire.', + 'Alternative image text' => 'Texte alternatif de l\'image', + 'Carousel image' => 'Image du carrousel', + 'Conclusion' => 'Conclusion', + 'Detailed description' => 'Description détaillée', + 'Disable image' => 'Désactiver l\'image', + 'Displayed when image is not visible' => 'Affiché lorsque l\'image n\'est pas visible', + 'Edit your carousel' => 'Modifier votre carousel', + 'End date' => 'Date de fin', + 'Group image' => 'Groupe de l\'image', + 'Group of images' => 'Nom du groupe auquel l\'image appartient', + 'Image URL' => 'URL de l\'image', + 'Image position in carousel' => 'Position de l\'image dans le carrousel', + 'Limited' => 'Afficher l\'image entre les dates ci-dessous', + 'Please enter a valid URL' => 'Merci d\'indiquer une URL valide', + 'Short additional text' => 'Un court texte supplémentaire', + 'Short description text' => 'Un court texte de description', + 'Start date' => 'Date de début', + 'Summary' => 'Résumé', + 'The detailed description.' => 'La description détaillée.', + 'Title' => 'Titre', +]; diff --git a/domokits/local/modules/Carousel/I18n/it_IT.php b/domokits/local/modules/Carousel/I18n/it_IT.php new file mode 100644 index 0000000..62eb7e7 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/it_IT.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'Un titolo descrittivo', + 'A short description, used when a summary or an introduction is required' => 'Una breve descrizione, utilizzata quando è necessario un sommario o un\'introduzione', + 'Conclusion' => 'Conclusione', + 'Detailed description' => 'Descrizione dettagliata', + 'Summary' => 'Riassunto', + 'The detailed description.' => 'La descrizione dettagliata.', + 'Title' => 'Titolo', +]; diff --git a/domokits/local/modules/Carousel/I18n/ru_RU.php b/domokits/local/modules/Carousel/I18n/ru_RU.php new file mode 100644 index 0000000..bcd1443 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/ru_RU.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'Описательный заголовок', + 'A short description, used when a summary or an introduction is required' => 'Краткое описание, используется когда необходимо', + 'A short text, used when an additional or supplemental information is required.' => 'Краткий текст используемый, когда необходима дополнительной информации.', + 'Alternative image text' => 'Альтернативный текст изображения', + 'Carousel image' => 'Изображение карусели', + 'Conclusion' => 'Заключение', + 'Detailed description' => 'Детальное описание', + 'Displayed when image is not visible' => 'Отображается когда изображения не видно', + 'Edit your carousel' => 'Редактировать вашу карусель', + 'Image URL' => 'URL изображения', + 'Image position in carousel' => 'Позиция изображения в карусели', + 'Please enter a valid URL' => 'Пожалуйста введите корректный URL', + 'Short additional text' => 'Краткий дополнительный текст', + 'Short description text' => 'Текст краткого описания', + 'Summary' => 'Краткое описание', + 'The detailed description.' => 'Детальное описание', + 'Title' => 'Заголовок', +]; diff --git a/domokits/local/modules/Carousel/I18n/tr_TR.php b/domokits/local/modules/Carousel/I18n/tr_TR.php new file mode 100644 index 0000000..0d33e73 --- /dev/null +++ b/domokits/local/modules/Carousel/I18n/tr_TR.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'A descriptive title' => 'Açıklayıcı bir başlık', + 'A short description, used when a summary or an introduction is required' => 'Bir Özeti veya giriş gerekli olduğunda kullanılan kısa bir açıklama', + 'A short text, used when an additional or supplemental information is required.' => 'Bir ek ya da tamamlayıcı bilgi gerekli olduğunda kullanılan kısa bir metin.', + 'Alternative image text' => 'Alternatif resim metini', + 'Carousel image' => 'slayt görüntü', + 'Conclusion' => 'Sonuç', + 'Detailed description' => 'Detaylı açıklama', + 'Displayed when image is not visible' => 'resim görünür olmadığında görüntülenen', + 'Image URL' => 'Resim Bağlantı [Link]', + 'Image position in carousel' => 'slayt bulunduğu resim', + 'Please enter a valid URL' => 'Lütfen geçerli bir URL girin', + 'Short additional text' => 'Kısa ek metin', + 'Short description text' => 'Kısa açıklama metni', + 'Summary' => 'Özet', + 'The detailed description.' => 'Ayrıntılı açıklama.', + 'Title' => 'Başlık', +]; diff --git a/domokits/local/modules/Carousel/Loop/Carousel.php b/domokits/local/modules/Carousel/Loop/Carousel.php new file mode 100644 index 0000000..5c995ec --- /dev/null +++ b/domokits/local/modules/Carousel/Loop/Carousel.php @@ -0,0 +1,237 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Loop; + +use Carousel\Model\CarouselQuery; +use Propel\Runtime\ActiveQuery\Criteria; +use Thelia\Core\Event\Image\ImageEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Template\Element\LoopResult; +use Thelia\Core\Template\Element\LoopResultRow; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Core\Template\Loop\Image; +use Thelia\Log\Tlog; +use Thelia\Type\EnumListType; +use Thelia\Type\EnumType; +use Thelia\Type\TypeCollection; + +/** + * Class CarouselLoop. + * + * @author manuel raynaud + */ +class Carousel extends Image +{ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('width'), + Argument::createIntTypeArgument('height'), + Argument::createIntTypeArgument('rotation', 0), + Argument::createAnyTypeArgument('background_color'), + Argument::createIntTypeArgument('quality'), + new Argument( + 'resize_mode', + new TypeCollection( + new EnumType(['crop', 'borders', 'none']) + ), + 'none' + ), + new Argument( + 'order', + new TypeCollection( + new EnumListType(['alpha', 'alpha-reverse', 'manual', 'manual-reverse', 'random']) + ), + 'manual' + ), + Argument::createAnyTypeArgument('effects'), + Argument::createBooleanTypeArgument('allow_zoom', false), + Argument::createBooleanTypeArgument('filter_disable_slides', true), + Argument::createAlphaNumStringTypeArgument('group'), + Argument::createAlphaNumStringTypeArgument('format') + ); + } + + /** + * @throws \Propel\Runtime\Exception\PropelException + * + * @return LoopResult + */ + public function parseResults(LoopResult $loopResult) + { + /** @var \Carousel\Model\Carousel $carousel */ + foreach ($loopResult->getResultDataCollection() as $carousel) { + $imgSourcePath = $carousel->getUploadDir().DS.$carousel->getFile(); + if (!file_exists($imgSourcePath)) { + Tlog::getInstance()->error(sprintf('Carousel source image file %s does not exists.', $imgSourcePath)); + continue; + } + + $startDate = $carousel->getStartDate(); + $endDate = $carousel->getEndDate(); + + if ($carousel->getLimited()) { + $now = new \DateTime(); + if ($carousel->getDisable()) { + if ($now > $startDate && $now < $endDate) { + $carousel + ->setDisable(0) + ->save(); + } + } else { + if ($now < $startDate || $now > $endDate) { + $carousel + ->setDisable(1) + ->save(); + } + } + } + + if ($this->getFilterDisableSlides() && $carousel->getDisable()) { + continue; + } + + $loopResultRow = new LoopResultRow($carousel); + + $event = new ImageEvent(); + $event->setSourceFilepath($imgSourcePath) + ->setCacheSubdirectory('carousel'); + + switch ($this->getResizeMode()) { + case 'crop': + $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP; + break; + case 'borders': + $resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS; + break; + case 'none': + default: + $resize_mode = \Thelia\Action\Image::KEEP_IMAGE_RATIO; + } + + // Prepare tranformations + $width = $this->getWidth(); + $height = $this->getHeight(); + $rotation = $this->getRotation(); + $background_color = $this->getBackgroundColor(); + $quality = $this->getQuality(); + $effects = $this->getEffects(); + $format = $this->getFormat(); + + if (null !== $width) { + $event->setWidth($width); + } + if (null !== $height) { + $event->setHeight($height); + } + $event->setResizeMode($resize_mode); + if (null !== $rotation) { + $event->setRotation($rotation); + } + if (null !== $background_color) { + $event->setBackgroundColor($background_color); + } + if (null !== $quality) { + $event->setQuality($quality); + } + if (null !== $effects) { + $event->setEffects($effects); + } + if (null !== $format) { + $event->setFormat($format); + } + + $event->setAllowZoom($this->getAllowZoom()); + + // Dispatch image processing event + $this->dispatcher->dispatch($event, TheliaEvents::IMAGE_PROCESS); + + if ($startDate) { + $startDate = $startDate->format('Y-m-d').'T'.$startDate->format('H:i'); + } + if ($endDate) { + $endDate = $endDate->format('Y-m-d').'T'.$endDate->format('H:i'); + } + + $loopResultRow + ->set('ID', $carousel->getId()) + ->set('LOCALE', $this->locale) + ->set('IMAGE_URL', $event->getFileUrl()) + ->set('ORIGINAL_IMAGE_URL', $event->getOriginalFileUrl()) + ->set('IMAGE_PATH', $event->getCacheFilepath()) + ->set('ORIGINAL_IMAGE_PATH', $event->getSourceFilepath()) + ->set('TITLE', $carousel->getVirtualColumn('i18n_TITLE')) + ->set('CHAPO', $carousel->getVirtualColumn('i18n_CHAPO')) + ->set('DESCRIPTION', $carousel->getVirtualColumn('i18n_DESCRIPTION')) + ->set('POSTSCRIPTUM', $carousel->getVirtualColumn('i18n_POSTSCRIPTUM')) + ->set('ALT', $carousel->getVirtualColumn('i18n_ALT')) + ->set('URL', $carousel->getUrl()) + ->set('POSITION', $carousel->getPosition()) + ->set('DISABLE', $carousel->getDisable()) + ->set('GROUP', $carousel->getGroup()) + ->set('LIMITED', $carousel->getLimited()) + ->set('START_DATE', $startDate) + ->set('END_DATE', $endDate) + ; + + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } + + /** + * this method returns a Propel ModelCriteria. + * + * @return \Propel\Runtime\ActiveQuery\ModelCriteria + */ + public function buildModelCriteria() + { + $search = CarouselQuery::create(); + $group = $this->getGroup(); + + $this->configureI18nProcessing($search, ['ALT', 'TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM']); + + $orders = $this->getOrder(); + + // Results ordering + foreach ($orders as $order) { + switch ($order) { + case 'alpha': + $search->addAscendingOrderByColumn('i18n_TITLE'); + break; + case 'alpha-reverse': + $search->addDescendingOrderByColumn('i18n_TITLE'); + break; + case 'manual-reverse': + $search->orderByPosition(Criteria::DESC); + break; + case 'manual': + $search->orderByPosition(Criteria::ASC); + break; + case 'random': + $search->clearOrderByColumns(); + $search->addAscendingOrderByColumn('RAND()'); + break 2; + break; + } + } + + if ($group) { + $search->filterByGroup($group); + } + + return $search; + } +} diff --git a/domokits/local/modules/Carousel/Model/Carousel.php b/domokits/local/modules/Carousel/Model/Carousel.php new file mode 100644 index 0000000..f81a496 --- /dev/null +++ b/domokits/local/modules/Carousel/Model/Carousel.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Model; + +use Carousel\Model\Base\Carousel as BaseCarousel; +use Propel\Runtime\ActiveQuery\ModelCriteria; +use Propel\Runtime\Connection\ConnectionInterface; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Filesystem\Filesystem; +use Thelia\Files\FileModelInterface; +use Thelia\Files\FileModelParentInterface; +use Thelia\Form\BaseForm; + +class Carousel extends BaseCarousel implements FileModelInterface +{ + public function preDelete(ConnectionInterface $con = null) + { + $carousel = new \Carousel\Carousel(); + + $fs = new Filesystem(); + + try { + $fs->remove($carousel->getUploadDir().DS.$this->getFile()); + + return true; + } catch (IOException $e) { + return false; + } + } + + /** + * Set file parent id. + * + * @param int $parentId parent id + * + * @return $this + */ + public function setParentId($parentId) + { + return $this; + } + + /** + * Get file parent id. + * + * @return int parent id + */ + public function getParentId() + { + return $this->getId(); + } + + /** + * @return FileModelParentInterface the parent file model + */ + public function getParentFileModel() + { + return new static(); + } + + /** + * Get the ID of the form used to change this object information. + * + * @return BaseForm the form + */ + public function getUpdateFormId() + { + return 'carousel.image'; + } + + /** + * @return string the path to the upload directory where files are stored, without final slash + */ + public function getUploadDir() + { + $carousel = new \Carousel\Carousel(); + + return $carousel->getUploadDir(); + } + + /** + * @return string the URL to redirect to after update from the back-office + */ + public function getRedirectionUrl() + { + return '/admin/module/Carousel'; + } + + /** + * Get the Query instance for this object. + * + * @return ModelCriteria + */ + public function getQueryInstance() + { + return CarouselQuery::create(); + } + + /** + * @param bool $visible true if the file is visible, false otherwise + * + * @return FileModelInterface + */ + public function setVisible($visible) + { + // Not implemented + + return $this; + } +} diff --git a/domokits/local/modules/Carousel/Model/CarouselI18n.php b/domokits/local/modules/Carousel/Model/CarouselI18n.php new file mode 100644 index 0000000..dd31b3e --- /dev/null +++ b/domokits/local/modules/Carousel/Model/CarouselI18n.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Model; + +use Carousel\Model\Base\CarouselI18n as BaseCarouselI18n; + +class CarouselI18n extends BaseCarouselI18n +{ +} diff --git a/domokits/local/modules/Carousel/Model/CarouselI18nQuery.php b/domokits/local/modules/Carousel/Model/CarouselI18nQuery.php new file mode 100644 index 0000000..b54b2d4 --- /dev/null +++ b/domokits/local/modules/Carousel/Model/CarouselI18nQuery.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Model; + +use Carousel\Model\Base\CarouselI18nQuery as BaseCarouselI18nQuery; + +/** + * Skeleton subclass for performing query and update operations on the 'carousel_i18n' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class CarouselI18nQuery extends BaseCarouselI18nQuery +{ +} // CarouselI18nQuery diff --git a/domokits/local/modules/Carousel/Model/CarouselQuery.php b/domokits/local/modules/Carousel/Model/CarouselQuery.php new file mode 100644 index 0000000..6a478a8 --- /dev/null +++ b/domokits/local/modules/Carousel/Model/CarouselQuery.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carousel\Model; + +use Carousel\Model\Base\CarouselQuery as BaseCarouselQuery; + +/** + * Skeleton subclass for performing query and update operations on the 'carousel' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class CarouselQuery extends BaseCarouselQuery +{ + public function findAllByPosition() + { + return $this->orderByPosition() + ->find(); + } +} // CarouselQuery diff --git a/domokits/local/modules/Carousel/Readme.md b/domokits/local/modules/Carousel/Readme.md new file mode 100644 index 0000000..830f32d --- /dev/null +++ b/domokits/local/modules/Carousel/Readme.md @@ -0,0 +1,69 @@ +# Carousel + +This module for Thelia add a customizable carousel on your home page. You can upload you own image and overload the default template in your template for using the carousel. + +## Installation + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is Carousel. +* Activate it in your thelia administration panel + +## Usage + +In the configuration panel of this module, you can upload as many images as you want. + +## Hook + +The carousel is installed in the "Home page - main area" (home.body) hook. + +## Loop + +Customize images with the `carousel` loop, which has the same arguments as the `image` loop. You can define a width, a height, and many other parameters + +### Input arguments + +|Argument |Description | +|--- |--- | +|**width** | A width in pixels, for resizing image. If only the width is provided, the image ratio is preserved. Example : width="200" | +|**height** | A height in pixels, for resizing image. If only the height is provided, the image ratio is preserved. example : height="200" | +|**rotation** |The rotation angle in degrees (positive or negative) applied to the image. The background color of the empty areas is the one specified by 'background_color'. example : rotation="90" | +|**background_color** |The color applied to empty image parts during processing. Use $rgb or $rrggbb color format. example : background_color="$cc8000"| +|**quality** |The generated image quality, from 0(!) to 100%. The default value is 75% (you can hange this in the Administration panel). example : quality="70"| +|**resize_mode** | If 'crop', the image will have the exact specified width and height, and will be cropped if required. If 'borders', the image will have the exact specified width and height, and some borders may be added. The border color is the one specified by 'background_color'. If 'none' or missing, the image ratio is preserved, and depending od this ratio, may not have the exact width and height required. resize_mode="crop"| +|**effects** |One or more comma separated effects definitions, that will be applied to the image in the specified order. Please see below a detailed description of available effects. Expected values :
  • gamma:value : change the image Gamma to the specified value. Example: gamma:0.7.
  • grayscale or greyscale : switch image to grayscale.
  • colorize:color : apply a color mask to the image. The color format is $rgb or $rrggbb. Example: colorize:$ff2244.
  • negative : transform the image in its negative equivalent.
  • vflip or vertical_flip : flip the image vertically.
  • hflip or horizontal_flip : flip the image horizontally.
example : effects="greyscale,gamma:0.7,vflip" | +|**group** |The name of an image group. Return only images from the specified group| +|**filter_disable_slides** |if true (the default), the disabled slides will not be displayed| + +### Ouput arguments + +|Variable |Description | +|--- |--- | +|$ID |the image ID | +|$IMAGE_URL |The absolute URL to the generated image | +|$ORIGINAL_IMAGE_URL |The absolute URL to the original image | +|$IMAGE_PATH |The absolute path to the generated image file | +|$ORIGINAL_IMAGE_PATH |The absolute path to the original image file | +|$ALT |alt text | +|$TITLE |the slide title | +|$CHAPO |the slide summary | +|$DESCRIPTION |the slide description | +|$POSTSCRIPTUM |the slide conclusion | +|$LOCALE |the textual elements locale | +|$POSITION |the slide position in the carousel | +|$URL |the related URL | +|$LIMITED| true if slide is disabled, false otherwise | +|$START_DATE| limited slide display start date | +|$END_DATE| limited slide display end date | +|$DISABLE| true if slide display is limited | +|$GROUP| name of the group the slide belong to | + +### Exemple + +``` +{loop type="carousel" name="carousel.front" width="1200" height="390" resize_mode="borders"} + {$ALT} +{/loop} +``` + +## How to override ? + +If you want your own carousel in your tempalte, create the directory ```modules/Carousel``` then create the template ```carousel.html``` in this directory. Here you can create your own carousel and the replace the default template provided in the module. diff --git a/domokits/local/modules/Carousel/composer.json b/domokits/local/modules/Carousel/composer.json new file mode 100644 index 0000000..5cfd6d3 --- /dev/null +++ b/domokits/local/modules/Carousel/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/carousel-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "Carousel" + } +} diff --git a/domokits/local/modules/Carousel/templates/backOffice/default/assets/js/module-configuration.js b/domokits/local/modules/Carousel/templates/backOffice/default/assets/js/module-configuration.js new file mode 100644 index 0000000..54b03e5 --- /dev/null +++ b/domokits/local/modules/Carousel/templates/backOffice/default/assets/js/module-configuration.js @@ -0,0 +1,6 @@ +$(function() { + // Set proper image ID in delete from + $('a.image-delete').click(function(ev) { + $('#image_delete_id').val($(this).data('id')); + }); +}); diff --git a/domokits/local/modules/Carousel/templates/backOffice/default/module_configuration.html b/domokits/local/modules/Carousel/templates/backOffice/default/module_configuration.html new file mode 100644 index 0000000..df01b41 --- /dev/null +++ b/domokits/local/modules/Carousel/templates/backOffice/default/module_configuration.html @@ -0,0 +1,179 @@ +
+
+
+ {intl l='Edit your carousel.' d='carousel.bo.default'} +
+
+ +
+
+
+ {form name=Carousel\Form\CarouselImageForm::getName()} +
+ + {form_hidden_fields} + + {form_field field='file'} +
+ +
+ + + + +
+
+ {/form_field} +
+ {/form} +
+
+
+ +
+
+ {intl l='Carousel images' d='carousel.bo.default'} +
+
+ +
+
+
+ {ifloop rel="carousel.image"} + {form name="Carousel\Form\CarouselUpdateForm"} +
+ + {include + file = "includes/inner-form-toolbar.html" + page_url = "{url path='/admin/module/Carousel'}" + close_url = "{url path='/admin/modules'}" + } + + {form_hidden_fields} + + {loop name="carousel.image" type="carousel" width="550" height="200" resize_mode="borders" backend_context="1" lang="$edit_language_id" filter_disable_slides=false} + +
+
+
+

+ + {$ALT} + +

+ + + +
+
+ +
+
+ {form_field field="position{$ID}"} + + {/form_field} +
+
+
+
+ {form_field field="disable{$ID}"} + + + {/form_field} +
+
+ {form_field field="limited{$ID}"} + + + {/form_field} +
+ +
+ {form_field field="start_date{$ID}"} + +
+ +
+ {/form_field} +
+ +
+ {form_field field="end_date{$ID}"} + +
+ +
+ {/form_field} +
+
+
+ +
+ {* Not yet implemented + {render_form_field field="chapo{$ID} value=$CHAPO"} + *} + {render_form_field field="title{$ID}" value=$TITLE} + {render_form_field field="alt{$ID}" value=$ALT} + {render_form_field field="url{$ID}" value=$URL} + {render_form_field field="description{$ID}" extra_class="wysiwyg" value=$DESCRIPTION} + {render_form_field field="group{$ID}" value=$GROUP} + {* Not yet implemented + {render_form_field field="postscriptum{$ID}" value=$POSTSCRIPTUM} + *} +
+
+
+ {/loop} + + {include + file = "includes/inner-form-toolbar.html" + page_url = "{url path='/admin/module/Carousel'}" + close_url = "{url path='/admin/modules'}" + page_bottom = true + } +
+ {/form} + {/ifloop} + + {elseloop rel="carousel.image"} +
+ {intl d='carousel.bo.default' l="Your carousel contains no image. Please add one using the form above."} +
+ {/elseloop} +
+
+
+
+ +{capture "delete_dialog"} + +{/capture} + +{include +file = "includes/generic-confirm-dialog.html" + +dialog_id = "delete_carousel_dialog" +dialog_title = {intl l="Delete a carousel image" d="carousel.bo.default"} +dialog_message = {intl l="Do you really want to remove this image from the carousel ?" d="carousel.bo.default"} + +form_action = {url path='/admin/module/carousel/delete'} +form_content = {$smarty.capture.delete_dialog nofilter} +} + + + + diff --git a/domokits/local/modules/Carousel/templates/frontOffice/default/carousel.html b/domokits/local/modules/Carousel/templates/frontOffice/default/carousel.html new file mode 100644 index 0000000..6a714a5 --- /dev/null +++ b/domokits/local/modules/Carousel/templates/frontOffice/default/carousel.html @@ -0,0 +1,24 @@ +{ifloop rel="carousel.front"} + +{/ifloop} \ No newline at end of file diff --git a/domokits/local/modules/Cheque/Cheque.php b/domokits/local/modules/Cheque/Cheque.php new file mode 100644 index 0000000..6c95115 --- /dev/null +++ b/domokits/local/modules/Cheque/Cheque.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cheque; + +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Install\Database; +use Thelia\Model\MessageQuery; +use Thelia\Model\Order; +use Thelia\Module\AbstractPaymentModule; + +class Cheque extends AbstractPaymentModule +{ + public const MESSAGE_DOMAIN = 'Cheque'; + + public function pay(Order $order): void + { + // Nothing special to to. + } + + /** + * This method is call on Payment loop. + * + * If you return true, the payment method will de display + * If you return false, the payment method will not be display + * + * @return bool + */ + public function isValidPayment() + { + return $this->getCurrentOrderTotalAmount() > 0; + } + + public function postActivation(ConnectionInterface $con = null): void + { + $database = new Database($con); + + // Insert email message + $database->insertSql(null, [__DIR__.'/Config/setup.sql']); + } + + public function destroy(ConnectionInterface $con = null, $deleteModuleData = false): void + { + // Delete our message + if (null !== $message = MessageQuery::create()->findOneByName('order_confirmation_cheque')) { + $message->delete($con); + } + + parent::destroy($con, $deleteModuleData); + } + + /** + * if you want, you can manage stock in your module instead of order process. + * Return false if you want to manage yourself the stock. + * + * @return bool + */ + public function manageStockOnCreation() + { + return false; + } +} diff --git a/domokits/local/modules/Cheque/Config/config.xml b/domokits/local/modules/Cheque/Config/config.xml new file mode 100644 index 0000000..b09cf49 --- /dev/null +++ b/domokits/local/modules/Cheque/Config/config.xml @@ -0,0 +1,25 @@ + + + + + +
+ + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/Cheque/Config/module.xml b/domokits/local/modules/Cheque/Config/module.xml new file mode 100644 index 0000000..897c68f --- /dev/null +++ b/domokits/local/modules/Cheque/Config/module.xml @@ -0,0 +1,25 @@ + + + Cheque\Cheque + + Cheque + + + Cheque + + images + + en_US + fr_FR + + 2.5.4 + + Manuel Raynaud + manu@raynaud.io + + payment + 2.5.4 + alpha + diff --git a/domokits/local/modules/Cheque/Config/routing.xml b/domokits/local/modules/Cheque/Config/routing.xml new file mode 100644 index 0000000..8c741c0 --- /dev/null +++ b/domokits/local/modules/Cheque/Config/routing.xml @@ -0,0 +1,9 @@ + + + + + Cheque\Controller\ConfigureController::configure + + diff --git a/domokits/local/modules/Cheque/Config/setup.sql b/domokits/local/modules/Cheque/Config/setup.sql new file mode 100644 index 0000000..2f91a0e --- /dev/null +++ b/domokits/local/modules/Cheque/Config/setup.sql @@ -0,0 +1,32 @@ +-- --------------------------------------------------------------------- +-- Mail template for cheque +-- --------------------------------------------------------------------- + +-- First, delete existing entries +SET @var := 0; +SELECT @var := `id` FROM `message` WHERE name="order_confirmation_cheque"; +DELETE FROM `message` WHERE `id`=@var; + +-- Then add new entries +SELECT @max := MAX(`id`) FROM `message`; +SET @max := @max+1; + +-- insert message +INSERT INTO `message` (`id`, `name`, `secured`) VALUES + (@max, + 'order_confirmation_cheque', + '0' + ); +-- and mail templates +INSERT INTO `message_i18n` (`id`, `locale`, `title`, `subject`, `text_message`, `html_message`) VALUES + (@max, + 'en_US', + 'Confirmation of payment by cheque', + 'Payment of order {$order_ref}', 'Dear customer,\r\nThis is a confirmation of the payment by cheque of your order {$order_ref} on our shop.\r\nYour invoice is now available in your customer account at {config key="url_site"}\r\nThank you again for your purchase.\r\nThe {config key="store_name"} team.', '\r\n\r\n\r\n \r\n courriel de confirmation de commande de {config key="url_site"} \r\n \r\n\r\n\r\n
\r\n
\r\n

{config key="store_name"}

\r\n

The payment of your order is confirmed

\r\n

Reference {$order_ref}

\r\n
\r\n

\r\n Your invoice is now available in your customer account on\r\n {config key="store_name"}.\r\n

\r\n

Thank you for your order !

\r\n

The {config key="store_name"} team.

\r\n
\r\n\r\n' + ), + (@max, + 'fr_FR', + 'Confirmation de paiement par chèque', + 'Paiement de la commande : {$order_ref}', + 'Cher client,\r\nCe message confirme le paiement par chèque de votre commande numero {$order_ref} sur notre boutique.\r\nVotre facture est maintenant disponible dans votre compte client à l''adresse {config key="url_site"}\r\nMerci encore pour votre achat !\r\nL''équipe {config key="store_name"}', '\r\n\r\n\r\n \r\n Confirmation du paiement de votre commande sur {config key="url_site"} \r\n \r\n\r\n\r\n
\r\n
\r\n

{config key="store_name"}

\r\n

Confirmation du paiement de votre commande

\r\n

N° {$order_ref}

\r\n
\r\n

\r\n Le suivi de votre commande est disponible dans la rubrique mon compte sur\r\n {config key="url_site"}\r\n

\r\n

Merci pour votre achat !

\r\n

L''équipe {config key="store_name"}

\r\n
\r\n\r\n' + ); diff --git a/domokits/local/modules/Cheque/Controller/ConfigureController.php b/domokits/local/modules/Cheque/Controller/ConfigureController.php new file mode 100644 index 0000000..607ca10 --- /dev/null +++ b/domokits/local/modules/Cheque/Controller/ConfigureController.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cheque\Controller; + +use Cheque\Cheque; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Tools\URL; + +/** + * Class SetTransferConfig. + * + * @author Thelia + */ +class ConfigureController extends BaseAdminController +{ + public function configure() + { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'Cheque', AccessManager::UPDATE)) { + return $response; + } + + // Initialize the potential exception + $ex = null; + + // Create the Form from the request + $configurationForm = $this->createForm('cheque.instructions.configure'); + + try { + // Check the form against constraints violations + $form = $this->validateForm($configurationForm, 'POST'); + + // Get the form field values + $data = $form->getData(); + + Cheque::setConfigValue('instructions', $data['instructions'], $this->getCurrentEditionLocale()); + Cheque::setConfigValue('payable_to', $data['payable_to']); + + // Log configuration modification + $this->adminLogAppend( + 'cheque.configuration.message', + AccessManager::UPDATE, + 'Cheque instructions configuration updated' + ); + + // Everything is OK. + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/Cheque')); + } catch (FormValidationException $ex) { + // Form cannot be validated. Create the error message using + // the BaseAdminController helper method. + $error_msg = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + // Any other error + $error_msg = $ex->getMessage(); + } + + // At this point, the form has errors, and should be redisplayed. We don not redirect, + // just redisplay the same template. + // Setup the Form error context, to make error information available in the template. + $this->setupFormErrorContext( + $this->getTranslator()->trans('Cheque instructions configuration', [], Cheque::MESSAGE_DOMAIN), + $error_msg, + $configurationForm, + $ex + ); + + // Do not redirect at this point, or the error context will be lost. + // Just redisplay the current template. + return $this->render('module-configure', ['module_code' => 'Cheque']); + } +} diff --git a/domokits/local/modules/Cheque/Form/ConfigurationForm.php b/domokits/local/modules/Cheque/Form/ConfigurationForm.php new file mode 100644 index 0000000..312d181 --- /dev/null +++ b/domokits/local/modules/Cheque/Form/ConfigurationForm.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cheque\Form; + +use Cheque\Cheque; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; + +/** + * Class ConfigurationForm. + * + * @author Thelia + */ +class ConfigurationForm extends BaseForm +{ + protected function trans($str, $params = []) + { + return Translator::getInstance()->trans($str, $params, Cheque::MESSAGE_DOMAIN); + } + + protected function buildForm(): void + { + $this->formBuilder + ->add( + 'payable_to', + TextType::class, + [ + 'constraints' => [new NotBlank()], + 'label' => $this->trans('Cheque is payable to: '), + 'label_attr' => [ + 'for' => 'payable_to', + 'help' => $this->trans('The name to which the cheque shoud be payable to.'), + ], + 'attr' => [ + 'rows' => 10, + 'placeholder' => $this->trans('Pay cheque to'), + ], + ] + ) + ->add( + 'instructions', + TextareaType::class, + [ + 'constraints' => [], + 'required' => false, + 'label' => $this->trans('Cheque instructions'), + 'label_attr' => [ + 'for' => 'namefield', + 'help' => $this->trans('Please enter here the payment by cheque instructions'), + ], + 'attr' => [ + 'rows' => 10, + 'placeholder' => $this->trans('Payment instruction'), + ], + ] + ) + ; + } + + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return 'cheque_configuration_instructions'; + } +} diff --git a/domokits/local/modules/Cheque/Hook/HookManager.php b/domokits/local/modules/Cheque/Hook/HookManager.php new file mode 100644 index 0000000..8591131 --- /dev/null +++ b/domokits/local/modules/Cheque/Hook/HookManager.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cheque\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class HookManager. + * + * @author Franck Allimant + */ +class HookManager extends BaseHook +{ + public function onAdditionalPaymentInfo(HookRenderEvent $event): void + { + $content = $this->render('order-placed.additional-payment-info.html', [ + 'placed_order_id' => $event->getArgument('placed_order_id'), + ]); + + $event->add($content); + } +} diff --git a/domokits/local/modules/Cheque/I18n/backOffice/default/de_DE.php b/domokits/local/modules/Cheque/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..ebed375 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/backOffice/default/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions configuration' => 'Scheck-Anleitungen-Konfiguration', +]; diff --git a/domokits/local/modules/Cheque/I18n/backOffice/default/en_US.php b/domokits/local/modules/Cheque/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..d6dc1de --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/backOffice/default/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions configuration' => 'Cheque instructions configuration', +]; diff --git a/domokits/local/modules/Cheque/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/Cheque/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..3dd9d8e --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions configuration' => 'Instructions de paiement par chèque', +]; diff --git a/domokits/local/modules/Cheque/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/Cheque/I18n/backOffice/default/ru_RU.php new file mode 100644 index 0000000..a40b84d --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions configuration' => 'Конфигурация инструкций для чека', +]; diff --git a/domokits/local/modules/Cheque/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/Cheque/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..d7dbdb2 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions configuration' => 'Çek yönergeleri yapılandırma', +]; diff --git a/domokits/local/modules/Cheque/I18n/de_DE.php b/domokits/local/modules/Cheque/I18n/de_DE.php new file mode 100644 index 0000000..2f37846 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/de_DE.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions' => 'Scheck-Anweisungen', + 'Cheque instructions configuration' => 'Scheck-Anleitungen-Konfiguration', + 'Cheque is payable to: ' => 'Scheck ist zahlbar an: ', + 'Pay cheque to' => 'Scheck bezahlen an', + 'Payment instruction' => 'Zahlungsanweisungen', + 'Please enter here the payment by cheque instructions' => 'Bitte geben Sie hier die Zahlung durch Scheck Anweisungen ein', + 'The name to which the cheque shoud be payable to.' => 'Der Name, an den der Scheck bezahlbar sein soll.', +]; diff --git a/domokits/local/modules/Cheque/I18n/en_US.php b/domokits/local/modules/Cheque/I18n/en_US.php new file mode 100644 index 0000000..2ef9451 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/en_US.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions' => 'Cheque instructions', + 'Cheque instructions configuration' => 'Cheque instructions configuration', + 'Cheque is payable to: ' => 'Cheque is payable to: ', + 'Pay cheque to' => 'Pay cheque to', + 'Payment instruction' => 'Payment instruction', + 'Please enter here the payment by cheque instructions' => 'Please enter here the payment by cheque instructions', + 'The name to which the cheque shoud be payable to.' => 'The name to which the cheque shoud be payable to.', +]; diff --git a/domokits/local/modules/Cheque/I18n/fr_FR.php b/domokits/local/modules/Cheque/I18n/fr_FR.php new file mode 100644 index 0000000..0c1ab59 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/fr_FR.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions' => 'Instructions de paiement', + 'Cheque instructions configuration' => 'Instructions de paiement par chèque', + 'Cheque is payable to: ' => 'Ordre du chèque', + 'Pay cheque to' => 'Ordre du chèque', + 'Payment instruction' => 'Instructions de paiement', + 'Please enter here the payment by cheque instructions' => 'Indiquez ici les instructions particulières de paiement par chèque', + 'The name to which the cheque shoud be payable to.' => 'Le nom à fare figurer sur le chèque', +]; diff --git a/domokits/local/modules/Cheque/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/Cheque/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..46100d2 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Be sure to sign your cheque !' => 'Vergessen Sie nicht, Ihren Scheck zu unterschreiben !', + 'Please make your cheque payable to %name, and send it to the following address :' => 'Bitte stellen Sie den Scheck auf %name, und senden Sie es an die folgende Adresse : ', +]; diff --git a/domokits/local/modules/Cheque/I18n/frontOffice/default/en_US.php b/domokits/local/modules/Cheque/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..8499d61 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/frontOffice/default/en_US.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Be sure to sign your cheque !' => 'Be sure to sign your cheque !', + 'Please make your cheque payable to %name, and send it to the following address :' => 'Please make your cheque payable to %name, and send it to the following address :', +]; diff --git a/domokits/local/modules/Cheque/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/Cheque/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..5f2d4b2 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Be sure to sign your cheque !' => 'N\'oubliez pas de signer votre chèque !', + 'Please make your cheque payable to %name, and send it to the following address :' => 'Merci de libeller votre chèque à l\'ordre de %name, et de l\'expédier à l\'adresse suivante :', +]; diff --git a/domokits/local/modules/Cheque/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/Cheque/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..25c109d --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Be sure to sign your cheque !' => 'Убедитесь в том, что подписали чек !', + 'Please make your cheque payable to %name, and send it to the following address :' => 'Пожалуйста убедитесь что ваш чек предназначен %name, и вышлите его по следующему адресу :', +]; diff --git a/domokits/local/modules/Cheque/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/Cheque/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..01546fc --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Be sure to sign your cheque !' => 'Çekini imzalamak emin olun!', + 'Please make your cheque payable to %name, and send it to the following address :' => 'Lütfen, Çek %name için ödenecek olun ve aşağıdaki adrese gönderin:', +]; diff --git a/domokits/local/modules/Cheque/I18n/ru_RU.php b/domokits/local/modules/Cheque/I18n/ru_RU.php new file mode 100644 index 0000000..8c0e366 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/ru_RU.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions' => 'Инструкция для чека', + 'Cheque instructions configuration' => 'Конфигурация инструкций для чека', + 'Cheque is payable to: ' => 'Чек предназначен:', + 'Pay cheque to' => 'Оплата чеком для', + 'Payment instruction' => 'Инструкции для оплаты', + 'Please enter here the payment by cheque instructions' => 'Введите здесь инструкции для оплаты чеком', + 'The name to which the cheque shoud be payable to.' => 'Имя получателя чека.', +]; diff --git a/domokits/local/modules/Cheque/I18n/tr_TR.php b/domokits/local/modules/Cheque/I18n/tr_TR.php new file mode 100644 index 0000000..20a0076 --- /dev/null +++ b/domokits/local/modules/Cheque/I18n/tr_TR.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cheque instructions' => 'Çek yönergeleri', + 'Cheque instructions configuration' => 'Çek yönergeleri yapılandırma', + 'Cheque is payable to: ' => 'Çek için ödenir: ', + 'Pay cheque to' => 'Çek için ödeme', + 'Payment instruction' => 'Ödeme talimatı', + 'Please enter here the payment by cheque instructions' => 'Lütfen burada ödeme çek yönergeleri tarafından girin', + 'The name to which the cheque shoud be payable to.' => 'Adı için çek shoud için ödenecek.', +]; diff --git a/domokits/local/modules/Cheque/LICENSE.txt b/domokits/local/modules/Cheque/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/Cheque/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/Cheque/Listener/SendPaymentConfirmationEmail.php b/domokits/local/modules/Cheque/Listener/SendPaymentConfirmationEmail.php new file mode 100644 index 0000000..b0dcc8c --- /dev/null +++ b/domokits/local/modules/Cheque/Listener/SendPaymentConfirmationEmail.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Cheque\Listener; + +use Cheque\Cheque; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Action\BaseAction; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Mailer\MailerFactory; + +/** + * Class SendEMail. + * + * @author Thelia + */ +class SendPaymentConfirmationEmail extends BaseAction implements EventSubscriberInterface +{ + /** + * @var MailerFactory + */ + protected $mailer; + + public function __construct(MailerFactory $mailer) + { + $this->mailer = $mailer; + } + + /** + * @param orderEvent $event + * + * Check if we're the payment module, and send the payment confirmation email to the customer if it's the case + */ + public function sendConfirmationEmail(OrderEvent $event): void + { + if ($event->getOrder()->getPaymentModuleId() === Cheque::getModuleId()) { + if ($event->getOrder()->isPaid()) { + $order = $event->getOrder(); + + $this->mailer->sendEmailToCustomer( + 'order_confirmation_cheque', + $order->getCustomer(), + [ + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef(), + ] + ); + } + } + } + + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_UPDATE_STATUS => ['sendConfirmationEmail', 128], + ]; + } +} diff --git a/domokits/local/modules/Cheque/composer.json b/domokits/local/modules/Cheque/composer.json new file mode 100644 index 0000000..8dca232 --- /dev/null +++ b/domokits/local/modules/Cheque/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/cheque-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "Cheque" + } +} diff --git a/domokits/local/modules/Cheque/images/cheque.png b/domokits/local/modules/Cheque/images/cheque.png new file mode 100644 index 0000000000000000000000000000000000000000..0aad099e715aa796a29e77934cf421e7fe7b54e7 GIT binary patch literal 24812 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 Sni2mWfvltwq*&be(f + {$smarty.get.errmes} + +{/if} + +
+
+ +
+
+ {intl d='cheque.bo.default' l="Cheque instructions configuration"} +
+
+ +
+
+
+ + {form name="cheque.instructions.configure"} + + + + {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = false + + page_url = {url path="/admin/module/Cheque"} + close_url = {url path="/admin/modules"} + } + + {form_hidden_fields} + + {if $form_error} +
+
+
{$form_error_message}
+
+
+ {/if} + + {loop type="module-config" name="get-payable-to" module="Cheque" variable="payable_to"} + {render_form_field field="payable_to" value=$VALUE} + {/loop} + + {loop type="module-config" name="get-instruction" module="Cheque" variable="instructions" locale=$edit_language_locale} + {render_form_field field="instructions" extra_class="wysiwyg" value=$VALUE} + {/loop} + + {/form} +
+
+
+
+
\ No newline at end of file diff --git a/domokits/local/modules/Cheque/templates/frontOffice/default/order-placed.additional-payment-info.html b/domokits/local/modules/Cheque/templates/frontOffice/default/order-placed.additional-payment-info.html new file mode 100644 index 0000000..dba86bf --- /dev/null +++ b/domokits/local/modules/Cheque/templates/frontOffice/default/order-placed.additional-payment-info.html @@ -0,0 +1,21 @@ +{loop type="module-config" name="cheque-instructions" module="cheque" variable="payable_to"} +

{intl d='cheque.fo.default' l="Please make your cheque payable to %name, and send it to the following address :" name={$VALUE}}

+{/loop} + +
+ {config key="store_name"}
+ {config key="store_address1"}
+ {if ! empty({config key="store_address2"})}{config key="store_address2"}
{/if} + {if ! empty({config key="store_address3"})}{config key="store_address3"}
{/if} + {config key="store_zipcode"}, {config key="store_city"}
+ {if {config key="store_country"}} + {loop type="country" name="store_country" id={config key="store_country"}} + {$TITLE}
+ {/loop} + {/if} +
+

{intl d='cheque.fo.default' l="Be sure to sign your cheque !"}

+ +{loop type="module-config" name="cheque-instructions" module="cheque" variable="instructions"} +

{$VALUE nofilter}

+{/loop} \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/ChoiceFilter.php b/domokits/local/modules/ChoiceFilter/ChoiceFilter.php new file mode 100644 index 0000000..630aa5f --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/ChoiceFilter.php @@ -0,0 +1,50 @@ + + */ +class ChoiceFilter extends BaseModule +{ + /** @var string */ + public const DOMAIN_NAME = 'choicefilter'; + + public function preActivation(ConnectionInterface $con = null) + { + if (!$this->getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, [__DIR__.'/Config/thelia.sql', __DIR__.'/Config/insert.sql']); + + $this->setConfigValue('is_initialized', true); + } + + return true; + } + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/ChoiceFilter/Config/config.xml b/domokits/local/modules/ChoiceFilter/Config/config.xml new file mode 100644 index 0000000..f2a1ef9 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/ChoiceFilter/Config/insert.sql b/domokits/local/modules/ChoiceFilter/Config/insert.sql new file mode 100644 index 0000000..e7dd3bd --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/insert.sql @@ -0,0 +1,17 @@ +-- +-- Contenu de la table `choice_filter_other` +-- + +INSERT INTO `choice_filter_other` (`id`, `type`, `visible`) VALUES +(2, 'brand', 1), +(3, 'category', 1); + +-- +-- Contenu de la table `choice_filter_other_i18n` +-- + +INSERT INTO `choice_filter_other_i18n` (`id`, `locale`, `title`, `description`) VALUES +(2, 'en_US', 'Brand', NULL), +(2, 'fr_FR', 'Marque', NULL), +(3, 'en_US', 'Category', NULL), +(3, 'fr_FR', 'Catégorie', NULL); diff --git a/domokits/local/modules/ChoiceFilter/Config/module.xml b/domokits/local/modules/ChoiceFilter/Config/module.xml new file mode 100644 index 0000000..9d8b71f --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/module.xml @@ -0,0 +1,28 @@ + + + ChoiceFilter\ChoiceFilter + + This module allows the management of filters in front by template and category + + + Ce module permet la gestion des filtres en front par gabarit et catégorie + + + en_US + fr_FR + + 2.1.1 + + + Gilles Bourgeat + gbourgeat@openstudio.fr + + + classic + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/ChoiceFilter/Config/routing.xml b/domokits/local/modules/ChoiceFilter/Config/routing.xml new file mode 100644 index 0000000..7aba3b9 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/routing.xml @@ -0,0 +1,15 @@ + + + + + + ChoiceFilter\Controller\ChoiceFilterController::saveAction + + + + ChoiceFilter\Controller\ChoiceFilterController::clearAction + + + diff --git a/domokits/local/modules/ChoiceFilter/Config/schema.xml b/domokits/local/modules/ChoiceFilter/Config/schema.xml new file mode 100644 index 0000000..b1a3bb9 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/schema.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/ChoiceFilter/Config/thelia.sql b/domokits/local/modules/ChoiceFilter/Config/thelia.sql new file mode 100644 index 0000000..381e0e7 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Config/thelia.sql @@ -0,0 +1,91 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- choice_filter_other +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `choice_filter_other`; + +CREATE TABLE `choice_filter_other` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `type` VARCHAR(55), + `visible` TINYINT(1), + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- choice_filter +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `choice_filter`; + +CREATE TABLE `choice_filter` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `feature_id` INTEGER, + `attribute_id` INTEGER, + `other_id` INTEGER, + `category_id` INTEGER, + `template_id` INTEGER, + `position` INTEGER DEFAULT 0 NOT NULL, + `visible` TINYINT(1), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `choice_filter_FI_1` (`attribute_id`), + INDEX `choice_filter_FI_2` (`feature_id`), + INDEX `choice_filter_FI_3` (`other_id`), + INDEX `choice_filter_FI_4` (`category_id`), + INDEX `choice_filter_FI_5` (`template_id`), + CONSTRAINT `choice_filter_FK_1` + FOREIGN KEY (`attribute_id`) + REFERENCES `attribute` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `choice_filter_FK_2` + FOREIGN KEY (`feature_id`) + REFERENCES `feature` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `choice_filter_FK_3` + FOREIGN KEY (`other_id`) + REFERENCES `choice_filter_other` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `choice_filter_FK_4` + FOREIGN KEY (`category_id`) + REFERENCES `category` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `choice_filter_FK_5` + FOREIGN KEY (`template_id`) + REFERENCES `template` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- choice_filter_other_i18n +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `choice_filter_other_i18n`; + +CREATE TABLE `choice_filter_other_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255), + `description` LONGTEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `choice_filter_other_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `choice_filter_other` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/ChoiceFilter/Controller/ChoiceFilterController.php b/domokits/local/modules/ChoiceFilter/Controller/ChoiceFilterController.php new file mode 100644 index 0000000..870f71b --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Controller/ChoiceFilterController.php @@ -0,0 +1,130 @@ + + */ +class ChoiceFilterController extends BaseAdminController +{ + public function saveAction(Request $request) + { + $data = $request->get('ChoiceFilter'); + + if (!empty($data['template_id'])) { + ChoiceFilterQuery::create() + ->filterByTemplateId((int) $data['template_id']) + ->delete(); + + $choiceFilterBase = (new ChoiceFilter()) + ->setTemplateId((int) $data['template_id']); + + $template = 'choice-filter/template-edit'; + $parameters = [ + 'template_id' => (int) $data['template_id'] + ]; + $redirectUrl = '/admin/configuration/templates/update'; + + } elseif (!empty($data['category_id'])) { + ChoiceFilterQuery::create() + ->filterByCategoryId((int) $data['category_id']) + ->delete(); + + $choiceFilterBase = (new ChoiceFilter()) + ->setCategoryId((int) $data['category_id']); + + $template = 'choice-filter/category-edit'; + $parameters = [ + 'category_id' => (int) $data['category_id'] + ]; + $redirectUrl = '/admin/categories/update'; + + } else { + throw new \Exception("Missing parameter"); + } + + foreach ($data['filter'] as $filter) { + $choiceFilter = clone $choiceFilterBase; + + $choiceFilter + ->setVisible((int) $filter['visible']) + ->setPosition((int) $filter['position']); + + if ($filter['type'] === 'attribute') { + $choiceFilter + ->setAttributeId($filter['id']); + } elseif ($filter['type'] === 'feature') { + $choiceFilter + ->setFeatureId((int) $filter['id']); + } else { + $choiceFilter + ->setOtherId((int) $filter['id']); + } + + $choiceFilter->save(); + } + + $this->getSession()->getFlashBag()->add('choice-filter-success', 'configuration sauvegardée avec succès'); + + if ($request->isXmlHttpRequest()) { + return $this->render( + $template, + $parameters + ); + } else { + return $this->generateRedirect( + URL::getInstance()->absoluteUrl($redirectUrl, $parameters) + ); + } + } + + public function clearAction(Request $request) + { + $data = $request->get('ChoiceFilter'); + + if (!empty($data['template_id'])) { + ChoiceFilterQuery::create() + ->filterByTemplateId((int) $data['template_id']) + ->delete(); + + $template = 'choice-filter/template-edit'; + $parameters = [ + 'template_id' => (int) $data['template_id'] + ]; + $redirectUrl = '/admin/configuration/templates/update'; + + } elseif (!empty($data['category_id'])) { + ChoiceFilterQuery::create() + ->filterByCategoryId((int) $data['category_id']) + ->delete(); + + $template = 'choice-filter/category-edit'; + $parameters = [ + 'category_id' => (int) $data['category_id'] + ]; + $redirectUrl = '/admin/categories/update'; + + } else { + throw new \Exception("Missing parameter"); + } + + $this->getSession()->getFlashBag()->add('choice-filter-success', 'configuration sauvegardée avec succès'); + + if ($request->isXmlHttpRequest()) { + return $this->render( + $template, + $parameters + ); + } else { + return $this->generateRedirect( + URL::getInstance()->absoluteUrl($redirectUrl, $parameters) + ); + } + } +} diff --git a/domokits/local/modules/ChoiceFilter/Controller/Front/ChoiceFilterFrontController.php b/domokits/local/modules/ChoiceFilter/Controller/Front/ChoiceFilterFrontController.php new file mode 100644 index 0000000..973beeb --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Controller/Front/ChoiceFilterFrontController.php @@ -0,0 +1,202 @@ +get('locale', $request->getSession()->getLang()->getLocale()); + + $categoryId = $request->get('category_id'); + $visible = $request->get('visible', true); + + $features = new ObjectCollection(); + $attributes = new ObjectCollection(); + $others = new ObjectCollection(); + + $category = CategoryQuery::create()->findPk($categoryId); + + $categoryChoiceFilters = ChoiceFilterQuery::findChoiceFilterByCategory($category, $templateIdFind); + + if (null !== $templateIdFind) { + $features = ChoiceFilterQuery::findFeaturesByTemplateId( + $templateIdFind, + [$locale] + ); + $attributes = ChoiceFilterQuery::findAttributesByTemplateId( + $templateIdFind, + [$locale] + ); + $others = ChoiceFilterOtherQuery::findOther([$locale]); + } + + $filters = Util::merge($categoryChoiceFilters, $features, $attributes, $others); + + if (Type\BooleanOrBothType::ANY !== $visible) { + $visible = $visible ? 1 : 0; + $filters = array_filter($filters, function ($filter) use ($visible) {return $filter['Visible'] == $visible;}); + } + + $results = []; + + $attributeResults = array_map( + fn ($filter) => $modelFactory->buildModel('ChoiceFilter', $filter, $locale), + array_filter($filters, function ($filter) {return $filter['Type'] === "attribute";}) + ); + + if (!empty($attributeResults)) { + $results['attributes'] = $attributeResults; + } + + $featureResults = array_map( + fn ($filter) => $modelFactory->buildModel('ChoiceFilter', $filter, $locale), + array_filter($filters, function ($filter) {return $filter['Type'] === "feature";}) + ); + + if (!empty($attributeResults)) { + $results['features'] = $featureResults; + } + + $categoryIds = [$categoryId]; + $needCategories = !empty(array_filter($filters, function ($filter) {return $filter['Type'] === "category";})); + if ($needCategories) { + $con = Propel::getConnection(); + $stmt = $con->prepare(" + SELECT category.*, ci18n.title as title FROM category + LEFT JOIN category c_parent ON category.parent = c_parent.id + LEFT JOIN category c_parent_2 ON c_parent.parent = c_parent_2.id + LEFT JOIN category c_parent_3 ON c_parent_2.parent = c_parent_3.id + LEFT JOIN category c_parent_4 ON c_parent_3.parent = c_parent_4.id + LEFT JOIN category_i18n ci18n on category.id = ci18n.id AND ci18n.locale = :locale + WHERE category.id = :categoryId OR c_parent.id = :categoryId OR c_parent_2.id = :categoryId OR c_parent_3.id = :categoryId OR c_parent_4.id = :categoryId + "); + $stmt->bindValue(':locale', $locale, \PDO::PARAM_STR); + $stmt->bindValue(':categoryId', $categoryId, \PDO::PARAM_INT); + $stmt->execute(); + + $categoryResults = array_map( + fn ($category) => $modelFactory->buildModel('CategoryChoiceFilter', $category, $locale), + $stmt->fetchAll(\PDO::FETCH_ASSOC) + ); + + if (!empty($categoryResults)) { + $results['categories'] = $categoryResults; + } + + $categoryIds = array_map( + fn (CategoryChoiceFilter $categoryChoiceFilter) => $categoryChoiceFilter->getId(), + $categoryResults + ); + } + + $needBrands = !empty(array_filter($filters, function ($filter) {return $filter['Type'] === "brand";})); + if ($needBrands) { + $con = Propel::getConnection(); + $stmt = $con->prepare(" + SELECT DISTINCT brand.id as id, brand.*, bi18n.* FROM brand + INNER JOIN product p on brand.id = p.brand_id + LEFT JOIN brand_i18n bi18n on brand.id = bi18n.id AND bi18n.locale = :locale + INNER JOIN product_category ON p.id = product_category.product_id AND product_category.category_id IN (:categoryIds) + "); + $stmt->bindValue(':locale', $locale, \PDO::PARAM_STR); + $stmt->bindValue(':categoryIds', implode(",", $categoryIds), \PDO::PARAM_STR); + $stmt->execute(); + + $brandResults = array_map( + fn ($brand) => $modelFactory->buildModel('BrandChoiceFilter', $brand, $locale), + $stmt->fetchAll(\PDO::FETCH_ASSOC) + ); + + if (!empty($brandResults)) { + $results['brands'] = $brandResults; + } + } + + return OpenApiService::jsonResponse($results); + } +} diff --git a/domokits/local/modules/ChoiceFilter/Hook/ChoiceFilterHook.php b/domokits/local/modules/ChoiceFilter/Hook/ChoiceFilterHook.php new file mode 100644 index 0000000..0b98d34 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Hook/ChoiceFilterHook.php @@ -0,0 +1,142 @@ + + */ +class ChoiceFilterHook extends BaseHook +{ + protected $requestStack; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + /** + * @param HookRenderEvent $event + */ + public function onTemplateEditBottom(HookRenderEvent $event) + { + $templateId = $event->getArgument('template_id'); + + $locales = $this->getEditLocales(); + + $features = ChoiceFilterQuery::findFeaturesByTemplateId($templateId, $locales); + $attributes = ChoiceFilterQuery::findAttributesByTemplateId($templateId, $locales); + $others = ChoiceFilterOtherQuery::findOther($locales); + + /** @var ChoiceFilter[] $choiceFilters */ + $choiceFilters = ChoiceFilterQuery::create() + ->filterByTemplateId($templateId) + ->orderByPosition() + ->find(); + + if (count($choiceFilters)) { + $enabled = true; + } else { + $enabled = false; + } + + $filters = Util::merge($choiceFilters, $features, $attributes, $others); + + $event->add($this->render( + 'choice-filter/hook/template-edit.bottom.html', + $event->getArguments() + ['filters' => $filters, 'enabled' => $enabled] + )); + } + + public function onCategoryTabContent(HookRenderEvent $event) + { + if ($event->getArgument('view') !== 'category') { + return; + } + + $locales = $this->getEditLocales(); + + $category = CategoryQuery::create()->filterById($event->getArgument('id'))->findOne(); + + $templateId = null; + $categoryId = null; + $choiceFilters = ChoiceFilterQuery::findChoiceFilterByCategory($category, $templateId, $categoryId); + + $messageInfo = []; + $enabled = false; + + if ($templateId === null) { + $features = new ObjectCollection(); + $attributes = new ObjectCollection(); + $others = new ObjectCollection(); + $choiceFilters = new ObjectCollection(); + + $messageInfo[] = "Cette catégorie utilise aucune configuration des filtres"; + } else { + $features = ChoiceFilterQuery::findFeaturesByTemplateId( + $templateId, + $locales + ); + $attributes = ChoiceFilterQuery::findAttributesByTemplateId( + $templateId, + $locales + ); + $others = ChoiceFilterOtherQuery::findOther(); + + if (null === $categoryId) { + $messageInfo[] = "Cette catégorie utilise la configuration du gabarit " . $templateId; + } elseif ($categoryId == $category->getId()) { + $enabled = true; + $messageInfo[] = "Cette catégorie utilise sa propre configuration des filtres"; + } else { + $messageInfo[] = "Cette catégorie utilise la configuration des filtres de la catégorie " . $categoryId; + } + } + + $filters = Util::merge($choiceFilters, $features, $attributes, $others); + + $event->add($this->render( + 'choice-filter/hook/category.tab-content.html', + $event->getArguments() + ['category_id' => $event->getArgument('id'), 'filters' => $filters, 'enabled' => $enabled, 'messageInfo' => $messageInfo] + )); + } + + public function onCategoryEditJs(HookRenderEvent $event) + { + $event->add($this->render( + 'choice-filter/hook/category.edit-js.html', + $event->getArguments() + )); + } + + public function onTemplateEditJs(HookRenderEvent $event) + { + $event->add($this->render( + 'choice-filter/hook/template.edit-js.html', + $event->getArguments() + )); + } + + /** + * @return string[] list of locale + */ + protected function getEditLocales() + { + /** @var Session $session */ + $session = $this->requestStack->getCurrentRequest()->getSession(); + + $locale = $session->getAdminEditionLang()->getLocale(); + + return [$locale]; + } +} diff --git a/domokits/local/modules/ChoiceFilter/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/ChoiceFilter/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..c3c7b21 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,17 @@ + 'Personnaliser la configuration des filtres pour cette catégorie', + 'ID' => 'ID', + 'No' => 'Non', + 'Position' => 'Position', + 'Position of the filters in front for this category' => 'Position des filtres en front pour cette category', + 'Position of the filters in front for this template' => 'Position des filtres en front pour ce gabarit', + 'Reset default values' => 'Réinitialiser les valeurs par défaut', + 'Save' => 'Sauvegarder', + 'The position of the filters is for now the default one.' => 'La position des filtres est pour le moment celle par défaut.', + 'Title' => 'Titre', + 'Type' => 'Type', + 'Visible' => 'Visible', + 'Yes' => 'Oui', +); diff --git a/domokits/local/modules/ChoiceFilter/I18n/en_US.php b/domokits/local/modules/ChoiceFilter/I18n/en_US.php new file mode 100644 index 0000000..0b4fa14 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/domokits/local/modules/ChoiceFilter/I18n/fr_FR.php b/domokits/local/modules/ChoiceFilter/I18n/fr_FR.php new file mode 100644 index 0000000..3708624 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/I18n/fr_FR.php @@ -0,0 +1,4 @@ + 'La traduction française de la chaine', +); diff --git a/domokits/local/modules/ChoiceFilter/LICENCE b/domokits/local/modules/ChoiceFilter/LICENCE new file mode 100644 index 0000000..3312f1f --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/Loop/ChoiceFilterLoop.php b/domokits/local/modules/ChoiceFilter/Loop/ChoiceFilterLoop.php new file mode 100644 index 0000000..1e65416 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Loop/ChoiceFilterLoop.php @@ -0,0 +1,152 @@ + + */ +class ChoiceFilterLoop extends BaseLoop implements ArraySearchLoopInterface +{ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('template_id'), + Argument::createIntTypeArgument('category_id'), + Argument::createBooleanOrBothTypeArgument('visible', true), + new Argument( + 'order', + new Type\TypeCollection( + new Type\EnumListType( + [ + 'position', + 'position_reverse' + ] + ) + ), + 'position' + ) + ); + } + + public function buildArray() + { + $templateId = $this->getTemplateId(); + $categoryId = $this->getCategoryId(); + + if (null === $templateId && null === $categoryId) { + throw new LoopException('The argument template_id or category_id is required'); + } + + if (null !== $templateId && null !== $categoryId) { + throw new LoopException('The argument template_id or category_id can not be set together'); + } + + if (null !== $categoryId) { + $category = CategoryQuery::create()->findPk($categoryId); + + $templateIdFind = null; + $categoryIdFind = null; + $choiceFilters = ChoiceFilterQuery::findChoiceFilterByCategory($category, $templateIdFind, $categoryId); + + if ($templateIdFind === null) { + $features = new ObjectCollection(); + $attributes = new ObjectCollection(); + $others = new ObjectCollection(); + $choiceFilters = new ObjectCollection(); + } else { + $features = ChoiceFilterQuery::findFeaturesByTemplateId( + $templateIdFind + ); + $attributes = ChoiceFilterQuery::findAttributesByTemplateId( + $templateIdFind + ); + $others = ChoiceFilterOtherQuery::findOther(); + } + + $filters = Util::merge($choiceFilters, $features, $attributes, $others); + } elseif (null !== $templateId) { + $features = ChoiceFilterQuery::findFeaturesByTemplateId($templateId); + $attributes = ChoiceFilterQuery::findAttributesByTemplateId($templateId); + $others = ChoiceFilterOtherQuery::findOther(); + + /** @var ChoiceFilter[] $choiceFilters */ + $choiceFilters = ChoiceFilterQuery::create() + ->filterByTemplateId($templateId) + ->orderByPosition() + ->find(); + + $filters = Util::merge($choiceFilters, $features, $attributes, $others); + } + + if (null !== $orders = $this->getOrder()) { + foreach ($orders as $order) { + switch ($order) { + case "position_reverse": + return array_reverse($filters); + break; + } + } + } + + if ($this->getVisible() !== Type\BooleanOrBothType::ANY) { + $visible = $this->getVisible() ? 1 : 0; + foreach ($filters as $key => $filter) { + if ($filter['Visible'] != $visible) { + unset($filters[$key]); + } + } + } + + return $filters; + } + + /** + * @param LoopResult $loopResult + * + * @return LoopResult + */ + public function parseResults(LoopResult $loopResult) + { + /** @var ChoiceFilter $choiceFilter */ + foreach ($loopResult->getResultDataCollection() as $choiceFilter) { + $loopResultRow = new LoopResultRow($choiceFilter); + + $loopResultRow + ->set('TYPE', $choiceFilter['Type']) + ->set('ID', $choiceFilter['Id']) + ->set('VISIBLE', $choiceFilter['Visible']) + ->set('POSITION', $choiceFilter['Position']); + + $this->addOutputFields($loopResultRow, $choiceFilter); + + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/Api/BrandChoiceFilter.php b/domokits/local/modules/ChoiceFilter/Model/Api/BrandChoiceFilter.php new file mode 100644 index 0000000..d8d04e5 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/Api/BrandChoiceFilter.php @@ -0,0 +1,122 @@ +id; + } + + public function setId(int $id): BrandChoiceFilter + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(?string $title): BrandChoiceFilter + { + $this->title = $title; + + return $this; + } + + public function isVisible(): bool + { + return $this->visible; + } + + /** + * @param bool $visible + */ + public function setVisible(?bool $visible = true): BrandChoiceFilter + { + $this->visible = $visible; + + return $this; + } + + /** + * @return int + */ + public function getPosition(): ?int + { + return $this->position; + } + + /** + * @param int $position + */ + public function setPosition(?int $position): BrandChoiceFilter + { + $this->position = $position; + + return $this; + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/Api/CategoryChoiceFilter.php b/domokits/local/modules/ChoiceFilter/Model/Api/CategoryChoiceFilter.php new file mode 100644 index 0000000..821c5a8 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/Api/CategoryChoiceFilter.php @@ -0,0 +1,149 @@ +id; + } + + public function setId(int $id): CategoryChoiceFilter + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(?string $title): CategoryChoiceFilter + { + $this->title = $title; + + return $this; + } + + public function isVisible(): bool + { + return $this->visible; + } + + /** + * @param bool $visible + */ + public function setVisible(?bool $visible = true): CategoryChoiceFilter + { + $this->visible = $visible; + + return $this; + } + + /** + * @return int + */ + public function getPosition(): ?int + { + return $this->position; + } + + /** + * @param int $position + */ + public function setPosition(?int $position): CategoryChoiceFilter + { + $this->position = $position; + + return $this; + } + + /** + * @return int + */ + public function getParent(): ?int + { + return $this->parent; + } + + /** + * @param int|null $parent + * @return CategoryChoiceFilter + */ + public function setParent(?int $parent): CategoryChoiceFilter + { + $this->parent = $parent; + + return $this; + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilter.php b/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilter.php new file mode 100644 index 0000000..81e89f7 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilter.php @@ -0,0 +1,226 @@ +id; + } + + public function setId(int $id): ChoiceFilter + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(?string $title): ChoiceFilter + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getType(): ?string + { + return $this->type; + } + + /** + * @param string $title + */ + public function setType(?string $type): ChoiceFilter + { + $this->type = $type; + + return $this; + } + + public function isVisible(): bool + { + return $this->visible; + } + + /** + * @param bool $visible + */ + public function setVisible(?bool $visible = true): ChoiceFilter + { + $this->visible = $visible; + + return $this; + } + + /** + * @return int + */ + public function getPosition(): ?int + { + return $this->position; + } + + /** + * @param int $position + */ + public function setPosition(?int $position): ChoiceFilter + { + $this->position = $position; + + return $this; + } + + public function getValues(): array + { + return $this->values; + } + + /** + * @param int $values + */ + public function setValues(?array $values): ChoiceFilter + { + $this->values = $values; + + return $this; + } + + protected function getTheliaModel($propelModelName = null) + { + return parent::getTheliaModel(\ChoiceFilter\Model\ChoiceFilter::class); + } + + public function createOrUpdateFromData($data, $locale = null): void + { + parent::createOrUpdateFromData($data, $locale); + + $values = []; + + $modelFactory = $this->modelFactory; + if ($this->type === "feature") { + $values = array_map( + function (FeatureAv $featureAv) use ($modelFactory) { + return $modelFactory->buildModel('ChoiceFilterValue', + [ + 'id' => $featureAv->getId(), + 'title' => $featureAv->getTitle(), + 'position' => $featureAv->getPosition() + ] + ); + }, + iterator_to_array( + FeatureAvQuery::create() + ->filterByFeatureId($this->getId()) + ->useFeatureAvI18nQuery() + ->filterByLocale($locale) + ->endUse() + ->find() + ) + ); + } + if ($this->type === "attribute") { + $values = array_map( + function (AttributeAv $attributeAv) use ($modelFactory) { + return $modelFactory->buildModel('ChoiceFilterValue', + [ + 'id' => $attributeAv->getId(), + 'title' => $attributeAv->getTitle(), + 'position' => $attributeAv->getPosition() + ] + ); + }, + iterator_to_array( + AttributeAvQuery::create() + ->filterByAttributeId($this->getId()) + ->useAttributeAvI18nQuery() + ->filterByLocale($locale) + ->endUse() + ->find() + ) + ); + } + + $this->setValues($values); + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilterValue.php b/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilterValue.php new file mode 100644 index 0000000..acd4330 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/Api/ChoiceFilterValue.php @@ -0,0 +1,88 @@ +id; + } + + public function setId(int $id): ChoiceFilterValue + { + $this->id = $id; + + return $this; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(string $title): ChoiceFilterValue + { + $this->title = $title; + + return $this; + } + + /** + * @return int + */ + public function getPosition(): ?int + { + return $this->position; + } + + /** + * @param int $position + */ + public function setPosition(?int $position): ChoiceFilterValue + { + $this->position = $position; + + return $this; + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/ChoiceFilter.php b/domokits/local/modules/ChoiceFilter/Model/ChoiceFilter.php new file mode 100644 index 0000000..28ce769 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/ChoiceFilter.php @@ -0,0 +1,10 @@ +useChoiceFilterOtherI18nQuery(null, Criteria::LEFT_JOIN) + ->endUse(); + + $locales = array_map(function ($value) { + return '"' . $value . '"'; + }, $locales); + + $otherQuery->addJoinCondition('ChoiceFilterOtherI18n', 'ChoiceFilterOtherI18n.locale IN (' . implode(',', $locales) . ')'); + + $otherQuery->withColumn('ChoiceFilterOtherI18n.title', 'Title'); + + $otherQuery->groupBy('id'); + + return $otherQuery->find(); + } +} diff --git a/domokits/local/modules/ChoiceFilter/Model/ChoiceFilterQuery.php b/domokits/local/modules/ChoiceFilter/Model/ChoiceFilterQuery.php new file mode 100644 index 0000000..2f88ee4 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Model/ChoiceFilterQuery.php @@ -0,0 +1,192 @@ +useAttributeTemplateQuery() + ->filterByTemplateId($templateId) + ->endUse(); + + $attributeQuery->useAttributeI18nQuery(null, Criteria::LEFT_JOIN) + ->endUse(); + + $locales = array_map(function ($value) { + return '"' . $value . '"'; + }, $locales); + + $attributeQuery->addJoinCondition('AttributeI18n', 'AttributeI18n.locale IN (' . implode(',', $locales) . ')'); + + $attributeQuery->withColumn('AttributeI18n.title', 'Title'); + $attributeQuery->withColumn('AttributeTemplate.position', 'Position'); + + $attributeQuery->groupBy('id'); + + $attributeQuery->orderBy('position'); + + return $attributeQuery->find(); + } + + /** + * @param int $templateId + * @param string[] list of locale + * @return Feature[]|ObjectCollection + */ + public static function findFeaturesByTemplateId($templateId, $locales = ['en_US']) + { + $featureQuery = FeatureQuery::create(); + + $featureQuery->useFeatureTemplateQuery() + ->filterByTemplateId($templateId) + ->endUse(); + + $featureQuery->useFeatureI18nQuery(null, Criteria::LEFT_JOIN) + ->endUse(); + + $locales = array_map(function ($value) { + return '"' . $value . '"'; + }, $locales); + + $featureQuery->addJoinCondition('FeatureI18n', 'FeatureI18n.locale IN (' . implode(',', $locales) . ')'); + + $featureQuery->withColumn('FeatureI18n.title', 'Title'); + $featureQuery->withColumn('FeatureTemplate.position', 'Position'); + + $featureQuery->groupBy('id'); + + $featureQuery->orderBy('position'); + + return $featureQuery->find(); + } + + /** + * @param Category $category + * @return Category[] + */ + protected static function getParentCategoriesHasTemplate(Category $category) + { + $categories = []; + if (0 !== (int) $category->getParent()) { + $category = CategoryQuery::create()->filterById($category->getParent())->findOne(); + + if (null !== $category->getDefaultTemplateId()) { + $categories[] = $category; + } + + $categories = $categories + static::getParentCategoriesHasTemplate($category); + } + + return $categories; + } + + public static function findChoiceFilterByCategory( + Category $category, + &$templateId = null, + &$categoryId = null + ) { + $choiceFilters = ChoiceFilterQuery::create() + ->filterByCategoryId($category->getId()) + ->orderByPosition() + ->find(); + + $parents = static::getParentCategoriesHasTemplate($category); + + if (count($choiceFilters)) { + if (null !== $category->getDefaultTemplateId()) { + $templateId = $category->getDefaultTemplateId(); + $categoryId = $category->getId(); + return $choiceFilters; + } else { + foreach ($parents as $parent) { + if (null !== $parent->getDefaultTemplateId()) { + $templateId = $parent->getDefaultTemplateId(); + $categoryId = $category->getId(); + return $choiceFilters; + } + } + } + } + + if (null !== $category->getDefaultTemplateId()) { + $choiceFilters = ChoiceFilterQuery::create() + ->filterByCategoryId($category->getId()) + ->orderByPosition() + ->find(); + + if (count($choiceFilters)) { + $templateId = $category->getDefaultTemplateId(); + $categoryId = $category->getId(); + return $choiceFilters; + } + } + + foreach ($parents as $parent) { + $choiceFilters = ChoiceFilterQuery::create() + ->filterByCategoryId($parent->getId()) + ->orderByPosition() + ->find(); + + if (count($choiceFilters)) { + $templateId = $parent->getDefaultTemplateId(); + $categoryId = $parent->getId(); + return $choiceFilters; + } + } + + if (null !== $category->getDefaultTemplateId()) { + $choiceFilters = ChoiceFilterQuery::create() + ->filterByTemplateId($category->getDefaultTemplateId()) + ->orderByPosition() + ->find(); + + $templateId = $category->getDefaultTemplateId(); + $categoryId = null; + return $choiceFilters; + } + + foreach ($parents as $parent) { + $choiceFilters = ChoiceFilterQuery::create() + ->filterByTemplateId($parent->getDefaultTemplateId()) + ->orderByPosition() + ->find(); + + if (count($choiceFilters)) { + $templateId = $parent->getDefaultTemplateId(); + $categoryId = null; + return $choiceFilters; + } + } + + return new ObjectCollection(); + } +} diff --git a/domokits/local/modules/ChoiceFilter/Readme.md b/domokits/local/modules/ChoiceFilter/Readme.md new file mode 100644 index 0000000..a71e1ca --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Readme.md @@ -0,0 +1,108 @@ +# Choice Filter + +This module allows the management of filters in front by template and category + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is ChoiceFilter. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/choice-filter-module:~2.0.0 +``` + +## Usage + +You can choose the position of the filters +- When you edit a template +- When you edit a category + +## Loop + +[choice_filter] + +### Input arguments + +|Argument |Description | +|--- |--- | +|**template_id** | id of template | +|**category_id** | id of category | +|**order** | `position` or `position_reverse` | + +### Output arguments + +|Variable |Description | +|--- |--- | +|**$TYPE** | `feature` or `attribute` or other | +|**$ID** | id of filter | +|**$POSITION** | position of filter | +|**$VISIBLE** | visible of filter | + +### Exemple + +#### For a template +```smarty +{loop name="choice_filter" type="choice_filter" template_id=$template_id} + {if $TYPE == "feature" and $VISIBLE} + {loop type="feature" name="feature-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "attribute" and $VISIBLE} + {loop type="attribute" name="attribute-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "brand" and $VISIBLE} + {* your code *} + {elseif $TYPE == "price" and $VISIBLE} + {* your code *} + {/if} +{/loop} +``` + +#### For a category +```smarty +{loop name="choice_filter" type="choice_filter" category_id=$category_id} + {if $TYPE == "feature" and $VISIBLE} + {loop type="feature" name="feature-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "attribute" and $VISIBLE} + {loop type="attribute" name="attribute-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "brand" and $VISIBLE} + {* your code *} + {elseif $TYPE == "price" and $VISIBLE} + {* your code *} + {/if} +{/loop} +``` + +for performance, it is best to use a cache block +http://doc.thelia.net/en/documentation/templates/smarty/cache.html + +```smarty +{cache key="choice-filter" ttl=600 category_id==$category_id} + {loop name="choice_filter" type="choice_filter" category_id=$category_id} + {if $TYPE == "feature" and $VISIBLE} + {loop type="feature" name="feature-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "attribute" and $VISIBLE} + {loop type="attribute" name="attribute-$ID" id=$ID} + {* your code *} + {/loop} + {elseif $TYPE == "brand" and $VISIBLE} + {* your code *} + {elseif $TYPE == "price" and $VISIBLE} + {* your code *} + {/if} + {/loop} +{/cache} +``` diff --git a/domokits/local/modules/ChoiceFilter/Util.php b/domokits/local/modules/ChoiceFilter/Util.php new file mode 100644 index 0000000..78bbef6 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/Util.php @@ -0,0 +1,79 @@ + 'feature', 'Visible' => 1]); + }, $features->toArray()); + + $attributesArray = array_map(function ($attribute) { + return array_merge($attribute, ['Type' => 'attribute', 'Visible' => 1]); + }, $attributes->toArray()); + + $othersArray = array_map(function ($other) { + return $other; + }, $others->toArray()); + + if (count($choiceFilters)) { + $merge = []; + foreach ($choiceFilters as $choiceFilter) { + if (null !== $attributeId = $choiceFilter->getAttributeId()) { + foreach ($attributesArray as $key => $attributeArray) { + if ($attributeId == $attributeArray['Id']) { + $attributeArray['Visible'] = $choiceFilter->getVisible() ? 1 : 0; + $merge[] = $attributeArray; + unset($attributesArray[$key]); + } + } + } elseif (null !== $featureId = $choiceFilter->getFeatureId()) { + foreach ($featuresArray as $key => $featureArray) { + if ($featureId == $featureArray['Id']) { + $featureArray['Visible'] = $choiceFilter->getVisible() ? 1 : 0; + $merge[] = $featureArray; + unset($featuresArray[$key]); + } + } + } elseif (null !== $type = $choiceFilter->getChoiceFilterOther()->getType()) { // todo ajouter une jointure pour le type + foreach ($othersArray as $key => $otherArray) { + if ($type == $otherArray['Type']) { + $otherArray['Visible'] = $choiceFilter->getVisible() ? 1 : 0; + $merge[] = $otherArray; + unset($othersArray[$key]); + } + } + } + } + + $merge = array_merge($merge, $attributesArray); + $merge = array_merge($merge, $featuresArray); + $merge = array_merge($merge, $othersArray); + } else { + $merge = array_merge($attributesArray, $featuresArray); + $merge = array_merge($merge, $othersArray); + } + + $p = 1; + $merge = array_map(function ($array) use (&$p) { + return array_merge($array, ['Position' => $p++]); + }, $merge); + + return $merge; + } +} diff --git a/domokits/local/modules/ChoiceFilter/composer.json b/domokits/local/modules/ChoiceFilter/composer.json new file mode 100644 index 0000000..d711527 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/composer.json @@ -0,0 +1,12 @@ +{ + "name": "thelia/choice-filter-module", + "description": "Allows the management of filters in front by template and category", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "ChoiceFilter" + } +} diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/category-edit.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/category-edit.html new file mode 100644 index 0000000..3e2dbe6 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/category-edit.html @@ -0,0 +1 @@ +{hook name="category.tab-content" category_id=$category_id id=$category_id view="category"} \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.edit-js.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.edit-js.html new file mode 100644 index 0000000..af65a05 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.edit-js.html @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.tab-content.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.tab-content.html new file mode 100644 index 0000000..a4908c7 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/category.tab-content.html @@ -0,0 +1 @@ +{include file="choice-filter/hook/template-edit.bottom.html" category_id=$category_id enabled=$enabled messageInfo=$messageInfo} \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template-edit.bottom.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template-edit.bottom.html new file mode 100644 index 0000000..5f1657d --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template-edit.bottom.html @@ -0,0 +1,117 @@ +
+
+
+

+ {if isset($template_id)} + {intl l="Position of the filters in front for this template" d="choicefilter.bo.default"} + {/if} + {if isset($category_id)} + {intl l="Position of the filters in front for this category" d="choicefilter.bo.default"} + {/if} +

+ + {flash type="choice-filter-success"} +
+ {$MESSAGE} +
+ {/flash} + {if $messageInfo|default:[]|count} +
+ {foreach from=$messageInfo item=message} + {$message}
+ {/foreach} +
+ {/if} + + {if !$enabled} +
+ {intl l="The position of the filters is for now the default one." d="choicefilter.bo.default"} +
+ {/if} + +
+ + {if isset($template_id)} + + {/if} + + {if isset($category_id)} + + {/if} + + {if !$enabled} + + {/if} + + + + + + + + + + + + + {foreach from=$filters key=key item=filter} + + + + + + + + {/foreach} + + + + + + +
{intl l="ID" d="choicefilter.bo.default"}{intl l="Type" d="choicefilter.bo.default"}{intl l="Title" d="choicefilter.bo.default"}{intl l="Visible" d="choicefilter.bo.default"}{intl l="Position" d="choicefilter.bo.default"}
+ + {$filter.Id} + + + {$filter.Type} + + {$filter.Title} + + + + +
+ +
+
+ + {if $enabled} +
+ {if isset($template_id)} + + {/if} + + {if isset($category_id)} + + {/if} + + +
+
+
+ {/if} +
+
+
diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template.edit-js.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template.edit-js.html new file mode 100644 index 0000000..4bdc391 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/hook/template.edit-js.html @@ -0,0 +1 @@ +{include file="choice-filter/hook/category.edit-js.html"} \ No newline at end of file diff --git a/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/template-edit.html b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/template-edit.html new file mode 100644 index 0000000..b46fd82 --- /dev/null +++ b/domokits/local/modules/ChoiceFilter/templates/backOffice/default/choice-filter/template-edit.html @@ -0,0 +1 @@ +{hook name="template-edit.bottom" template_id=$template_id|default:null} diff --git a/domokits/local/modules/CustomDelivery/.github/workflows/release.yml b/domokits/local/modules/CustomDelivery/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/CustomDelivery/CHANGELOG.md b/domokits/local/modules/CustomDelivery/CHANGELOG.md new file mode 100644 index 0000000..c9970d4 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/CHANGELOG.md @@ -0,0 +1,17 @@ +# 1.0.7 + +- The dispatcher is now passed to Session::getSessionCart() + +# 1.0.3 + +- Fixed stability tag in module.xml + +# 1.0.2 + +- Removed bootbox dependency +- Added alert when no shipping zones defined +- Better float validation + +# 1.0.1 + +- Resolve #4 Add js dependency bootbox diff --git a/domokits/local/modules/CustomDelivery/Config/config.xml b/domokits/local/modules/CustomDelivery/Config/config.xml new file mode 100644 index 0000000..64b71cb --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/config.xml @@ -0,0 +1,38 @@ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/CustomDelivery/Config/module.xml b/domokits/local/modules/CustomDelivery/Config/module.xml new file mode 100644 index 0000000..6aaff34 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/module.xml @@ -0,0 +1,24 @@ + + + CustomDelivery\CustomDelivery + + Custom Delivery + + + Livraison Personnalisée + + + en_US + fr_FR + + 3.1.3 + + Julien Chanséaume + julien@thelia.net + + delivery + 2.5.0 + prod + diff --git a/domokits/local/modules/CustomDelivery/Config/routing.xml b/domokits/local/modules/CustomDelivery/Config/routing.xml new file mode 100644 index 0000000..413e2b8 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/routing.xml @@ -0,0 +1,19 @@ + + + + + + CustomDelivery\Controller\BackController::saveAction + + + + CustomDelivery\Controller\BackController::deleteAction + + + + CustomDelivery\Controller\BackController::saveConfigurationAction + + + diff --git a/domokits/local/modules/CustomDelivery/Config/schema.xml b/domokits/local/modules/CustomDelivery/Config/schema.xml new file mode 100644 index 0000000..2dd4af5 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/schema.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/CustomDelivery/Config/sqldb.map b/domokits/local/modules/CustomDelivery/Config/sqldb.map new file mode 100644 index 0000000..63a93ba --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +thelia.sql=thelia diff --git a/domokits/local/modules/CustomDelivery/Config/thelia.sql b/domokits/local/modules/CustomDelivery/Config/thelia.sql new file mode 100644 index 0000000..298b293 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Config/thelia.sql @@ -0,0 +1,29 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- custom_delivery_slice +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `custom_delivery_slice`; + +CREATE TABLE `custom_delivery_slice` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `area_id` INTEGER NOT NULL, + `price_max` FLOAT DEFAULT 0, + `weight_max` FLOAT DEFAULT 0, + `price` FLOAT DEFAULT 0, + PRIMARY KEY (`id`), + INDEX `FI_area_id` (`area_id`), + CONSTRAINT `fk_area_id` + FOREIGN KEY (`area_id`) + REFERENCES `area` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/CustomDelivery/Controller/BackController.php b/domokits/local/modules/CustomDelivery/Controller/BackController.php new file mode 100644 index 0000000..fa790ae --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Controller/BackController.php @@ -0,0 +1,245 @@ + + */ +class BackController extends BaseAdminController +{ + protected $currentRouter = 'router.customdelivery'; + + protected $useFallbackTemplate = true; + + /** + * Save slice + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function saveAction(Request $request) + { + $response = $this->checkAuth([], ['customdelivery'], AccessManager::UPDATE); + + if (null !== $response) { + return $response; + } + + $this->checkXmlHttpRequest(); + + $responseData = [ + "success" => false, + "message" => '', + "slice" => null + ]; + + $messages = []; + $response = null; + $config = CustomDelivery::getConfig(); + + try { + if (0 !== $id = (int)$request->get('id', 0)) { + $slice = CustomDeliverySliceQuery::create()->findPk($id); + } else { + $slice = new CustomDeliverySlice(); + } + + if (0 !== $areaId = (int)$request->get('area', 0)) { + $slice->setAreaId($areaId); + } else { + $messages[] = Translator::getInstance()->trans( + 'The area is not valid', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + } + + if ($config['method'] !== CustomDelivery::METHOD_WEIGHT) { + $priceMax = $this->getFloatVal($request->get('priceMax', 0)); + if (0 < $priceMax) { + $slice->setPriceMax($priceMax); + } else { + $messages[] = Translator::getInstance()->trans( + 'The price max value is not valid', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + } + } + + if ($config['method'] !== CustomDelivery::METHOD_PRICE) { + $weightMax = $this->getFloatVal($request->get('weightMax', 0)); + if (0 < $weightMax) { + $slice->setWeightMax($weightMax); + } else { + $messages[] = Translator::getInstance()->trans( + 'The weight max value is not valid', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + } + } + + $price = $this->getFloatVal($request->get('price', 0)); + if (0 <= $price) { + $slice->setPrice($price); + } else { + $messages[] = Translator::getInstance()->trans( + 'The price value is not valid', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + } + + if (0 === count($messages)) { + $slice->save(); + $messages[] = Translator::getInstance()->trans( + 'Your slice has been saved', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + + $responseData['success'] = true; + $responseData['slice'] = $slice->toArray(TableMap::TYPE_STUDLYPHPNAME); + } + } catch (\Exception $e) { + $message[] = $e->getMessage(); + } + + $responseData['message'] = $messages; + + return $this->jsonResponse(json_encode($responseData)); + } + + protected function getFloatVal($val, $default=-1) + { + if (preg_match("#^([\d.,]+)$#", $val, $match)) { + return (float) str_replace(array('.', ','), array('', '.'), $match[0]); + } + + return $default; + } + + /** + * Save slice + * + * @return Response + */ + public function deleteAction(Request $request) + { + $response = $this->checkAuth([], ['customdelivery'], AccessManager::DELETE); + + if (null !== $response) { + return $response; + } + + $this->checkXmlHttpRequest(); + + $responseData = [ + "success" => false, + "message" => '', + "slice" => null + ]; + + $response = null; + + try { + if (0 !== $id = (int)$request->get('id', 0)) { + $slice = CustomDeliverySliceQuery::create()->findPk($id); + $slice->delete(); + $responseData['success'] = true; + } else { + $responseData['message'] = Translator::getInstance()->trans( + 'The slice has not been deleted', + [], + CustomDelivery::MESSAGE_DOMAIN + ); + } + } catch (\Exception $e) { + $responseData['message'] = $e->getMessage(); + } + + return $this->jsonResponse(json_encode($responseData)); + } + + /** + * Save module configuration + * + * @param ParserContext $parserContext + * @return \Symfony\Component\HttpFoundation\Response + */ + public function saveConfigurationAction() + { + $response = $this->checkAuth([AdminResources::MODULE], ['customdelivery'], AccessManager::UPDATE); + + if (null !== $response) { + return $response; + } + + $form = $this->createForm('customdelivery.configuration.form'); + $message = ""; + + $response = null; + + try { + $vform = $this->validateForm($form); + $data = $vform->getData(); + + ConfigQuery::write( + CustomDelivery::CONFIG_TRACKING_URL, + $data['url'] + ); + ConfigQuery::write( + CustomDelivery::CONFIG_PICKING_METHOD, + $data['method'] + ); + ConfigQuery::write( + CustomDelivery::CONFIG_TAX_RULE_ID, + $data['tax'] + ); + } catch (\Exception $e) { + $message = $e->getMessage(); + } + if ($message) { + $form->setErrorMessage($message); + $this->getParserContext() + ->addForm($form) + ->setGeneralError($message); + + return $this->render( + "module-configure", + ["module_code" => CustomDelivery::getModuleCode()] + ); + } + + return $this->generateRedirect( + URL::getInstance()->absoluteUrl("/admin/module/" . CustomDelivery::getModuleCode()) + ); + } +} diff --git a/domokits/local/modules/CustomDelivery/CustomDelivery.php b/domokits/local/modules/CustomDelivery/CustomDelivery.php new file mode 100755 index 0000000..5f6ca1e --- /dev/null +++ b/domokits/local/modules/CustomDelivery/CustomDelivery.php @@ -0,0 +1,288 @@ + ( + ConfigQuery::read(self::CONFIG_TRACKING_URL, self::DEFAULT_TRACKING_URL) + ), + 'method' => ( + intval(ConfigQuery::read(self::CONFIG_PICKING_METHOD, self::DEFAULT_PICKING_METHOD)) + ), + 'tax' => ( + intval(ConfigQuery::read(self::CONFIG_TAX_RULE_ID)) + ) + ]; + + return $config; + } + + public function postActivation(ConnectionInterface $con = null): void + { + if (!$this->getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, array(__DIR__ . '/Config/thelia.sql')); + + $this->setConfigValue('is_initialized', true); + } + + // register config variables + if (null === ConfigQuery::read(self::CONFIG_TRACKING_URL, null)) { + ConfigQuery::write(self::CONFIG_TRACKING_URL, self::DEFAULT_TRACKING_URL); + } + + if (null === ConfigQuery::read(self::CONFIG_PICKING_METHOD, null)) { + ConfigQuery::write(self::CONFIG_PICKING_METHOD, self::DEFAULT_PICKING_METHOD); + } + + // create new message + if (null === MessageQuery::create()->findOneByName('mail_custom_delivery')) { + + $message = new Message(); + $message + ->setName('mail_custom_delivery') + ->setHtmlTemplateFileName('custom-delivery-shipping.html') + ->setHtmlLayoutFileName('') + ->setTextTemplateFileName('custom-delivery-shipping.txt') + ->setTextLayoutFileName('') + ->setSecured(0); + + $languages = LangQuery::create()->find(); + + foreach ($languages as $language) { + $locale = $language->getLocale(); + + $message->setLocale($locale); + + $message->setTitle( + $this->trans('Custom delivery shipping message', [], $locale) + ); + $message->setSubject( + $this->trans('Your order {$order_ref} has been shipped', [], $locale) + ); + } + + $message->save(); + } + } + + /** + * This method is called by the Delivery loop, to check if the current module has to be displayed to the customer. + * Override it to implements your delivery rules/ + * + * If you return true, the delivery method will de displayed to the customer + * If you return false, the delivery method will not be displayed + * + * @param Country $country the country to deliver to. + * @param State $state the state to deliver to. + * + * @return boolean + */ + public function isValidDelivery(Country $country, State $state = null) + { + // Retrieve the cart + $cart = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher()); + + /** @var CustomDeliverySlice $slice */ + $slice = $this->getSlicePostage($cart, $country, $state); + + return null !== $slice; + } + + /** + * Calculate and return delivery price in the shop's default currency + * + * @param Country $country the country to deliver to. + * @param State $state the state to deliver to. + * + * @return OrderPostage the delivery price + * @throws DeliveryException if the postage price cannot be calculated. + */ + public function getPostage(Country $country, State $state = null) + { + $cart = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher()); + + /** @var CustomDeliverySlice $slice */ + $postage = $this->getSlicePostage($cart, $country, $state); + + if (null === $postage) { + throw new DeliveryException(); + } + + return $postage; + } + + /** + * + * This method return true if your delivery manages virtual product delivery. + * + * @return bool + */ + public function handleVirtualProductDelivery() + { + return false; + } + + protected function trans($id, array $parameters = [], $locale = null) + { + if (null === $this->translator) { + $this->translator = Translator::getInstance(); + } + + return $this->translator->trans($id, $parameters, CustomDelivery::MESSAGE_DOMAIN, $locale); + } + + public function getDeliveryMode() + { + return 'delivery'; + } + + /** + * If a state is given and has slices, use them. + * If state is given but has no slices, check if the country has slices. + * If the country has slices, use them. + * If the country has no slices, the module is not valid for delivery + * + * @param Cart $cart + * @param Country $country + * @param State $state + * @return OrderPostage|null + */ + protected function getSlicePostage(Cart $cart, Country $country, State $state = null) + { + $config = self::getConfig(); + $currency = $cart->getCurrency(); + /** @var CustomDeliverySlice $slice */ + $slice = null; + + if (null !== $state && null !== $areas = CountryAreaQuery::create() + ->filterByStateId($state->getId()) + ->select([CountryAreaTableMap::AREA_ID]) + ->find() + ) { + $slice = $this->getAreaSlice($areas, $cart, $currency, $config); + } + + if (null === $slice && null !== $areas = CountryAreaQuery::create() + ->filterByCountryId($country->getId()) + ->filterByStateId(null) + ->select([CountryAreaTableMap::AREA_ID]) + ->find() + ) { + $slice = $this->getAreaSlice($areas, $cart, $currency, $config); + } + + if ($slice === null) { + return null; + } + + return $this->getAreaPostage($slice, $currency, $country, $config); + } + + /** + * @param $areas + * @param Cart $cart + * @param Currency $currency + * @param $config + * @return CustomDeliverySlice + */ + protected function getAreaSlice($areas, Cart $cart, Currency $currency, $config) + { + $query = CustomDeliverySliceQuery::create()->filterByAreaId($areas, Criteria::IN); + + if ($config['method'] != CustomDelivery::METHOD_PRICE) { + $query->filterByWeightMax($cart->getWeight(), Criteria::GREATER_THAN); + $query->orderByWeightMax(Criteria::ASC); + } + + if ($config['method'] != CustomDelivery::METHOD_WEIGHT) { + $total = $cart->getTotalAmount(); + // convert amount to the default currency + if (0 == $currency->getByDefault()) { + $total = $total / $currency->getRate(); + } + + $query->filterByPriceMax($total, Criteria::GREATER_THAN); + $query->orderByPriceMax(Criteria::ASC); + } + + return $query->findOne(); + } + + /** + * @param CustomDeliverySlice $slice + * @param Currency $currency + * @param Country $country + * @param $config + * @return OrderPostage + */ + protected function getAreaPostage(CustomDeliverySlice $slice, Currency $currency, Country $country, $config) + { + if (0 == $currency->getByDefault()) { + $untaxedPostage = $slice->getPrice() * $currency->getRate(); + } else { + $untaxedPostage = $slice->getPrice(); + } + $untaxedPostage = round($untaxedPostage, 2); + + $locale = $this->getRequest()->getSession()->getLang()->getLocale(); + + return $this->buildOrderPostage($untaxedPostage, $country, $locale, $config['tax']); + } +} diff --git a/domokits/local/modules/CustomDelivery/EventListeners/ApiListener.php b/domokits/local/modules/CustomDelivery/EventListeners/ApiListener.php new file mode 100644 index 0000000..52b7a84 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/EventListeners/ApiListener.php @@ -0,0 +1,104 @@ +container = $container; + $this->request = $requestStack->getCurrentRequest(); + } + + public function getDeliveryModuleOptions(DeliveryModuleOptionEvent $deliveryModuleOptionEvent) + { + if ($deliveryModuleOptionEvent->getModule()->getId() !== CustomDelivery::getModuleId()) { + return ; + } + $isValid = true; + $postage = null; + $postageTax = null; + + $locale = $this->request->getSession()->getLang()->getLocale(); + + $propelModule = ModuleQuery::create() + ->filterById(CustomDelivery::getModuleId()) + ->findOne() + ->setLocale($locale); + + try { + $module = $propelModule->getModuleInstance($this->container); + $country = $deliveryModuleOptionEvent->getCountry(); + $state = $deliveryModuleOptionEvent->getState(); + + if (empty($module->isValidDelivery($country, $state))) { + throw new DeliveryException(Translator::getInstance()->trans("Custom delivery is not available")); + } + + /** @var OrderPostage $orderPostage */ + $orderPostage = $module->getPostage($country, $state); + $postage = $orderPostage->getAmount(); + $postageTax = $orderPostage->getAmountTax(); + } catch (\Exception $exception) { + $isValid = false; + } + + $minimumDeliveryDate = ''; // TODO (calculate delivery date from day of order) + $maximumDeliveryDate = ''; // TODO (calculate delivery date from day of order + + /** @var DeliveryModuleOption $deliveryModuleOption */ + $deliveryModuleOption = ($this->container->get('open_api.model.factory'))->buildModel('DeliveryModuleOption'); + $deliveryModuleOption + ->setCode(CustomDelivery::getModuleCode()) + ->setValid($isValid) + ->setTitle($propelModule->getTitle()) + ->setImage('') + ->setMinimumDeliveryDate($minimumDeliveryDate) + ->setMaximumDeliveryDate($maximumDeliveryDate) + ->setPostage($postage) + ->setPostageTax($postageTax) + ->setPostageUntaxed($postage - $postageTax) + ; + + $deliveryModuleOptionEvent->appendDeliveryModuleOptions($deliveryModuleOption); + } + + public static function getSubscribedEvents() + { + $listenedEvents = []; + + /** Check for old versions of Thelia where the events used by the API didn't exists */ + if (class_exists(DeliveryModuleOptionEvent::class)) { + $listenedEvents[OpenApiEvents::MODULE_DELIVERY_GET_OPTIONS] = array("getDeliveryModuleOptions", 129); + } + + return $listenedEvents; + } +} diff --git a/domokits/local/modules/CustomDelivery/EventListeners/CustomDeliveryEvents.php b/domokits/local/modules/CustomDelivery/EventListeners/CustomDeliveryEvents.php new file mode 100644 index 0000000..5f3c28d --- /dev/null +++ b/domokits/local/modules/CustomDelivery/EventListeners/CustomDeliveryEvents.php @@ -0,0 +1,127 @@ + + */ +class CustomDeliveryEvents implements EventSubscriberInterface +{ + protected $parser; + + protected $mailer; + + public function __construct(ParserInterface $parser, MailerFactory $mailer) + { + $this->parser = $parser; + $this->mailer = $mailer; + } + + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_UPDATE_STATUS => ["updateStatus", 128] + ]; + } + + public function updateStatus(OrderEvent $event) + { + $order = $event->getOrder(); + $customDelivery = new CustomDelivery(); + + if ($order->isSent() && $order->getDeliveryModuleId() == $customDelivery->getModuleModel()->getId()) { + $contactEmail = ConfigQuery::getStoreEmail(); + + if ($contactEmail) { + + $message = MessageQuery::create() + ->filterByName('mail_custom_delivery') + ->findOne(); + + if (false === $message) { + throw new \Exception("Failed to load message 'mail_custom_delivery'."); + } + + $order = $event->getOrder(); + $customer = $order->getCustomer(); + $package = $order->getDeliveryRef(); + $trackingUrl = null; + + if (!empty($package)) { + $config = CustomDelivery::getConfig(); + $trackingUrl = $config['url']; + if (!empty($trackingUrl)) { + $trackingUrl = str_replace('%ID%', $package, $trackingUrl); + } + } + + $this->mailer->sendEmailMessage( + 'mail_custom_delivery', + [$contactEmail => ConfigQuery::getStoreName()], + [$customer->getEmail() => $customer->getFirstname() . " " . $customer->getLastname()], + [ + 'customer_id' => $customer->getId(), + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef(), + 'order_date' => $order->getCreatedAt(), + 'update_date' => $order->getUpdatedAt(), + 'package' => $package, + 'tracking_url' => $trackingUrl + ] + ); + + Tlog::getInstance()->debug( + "Custom Delivery shipping message sent to customer " . $customer->getEmail() + ); + } else { + $customer = $order->getCustomer(); + Tlog::getInstance()->debug( + "Custom Delivery shipping message no contact email customer_id ".$customer->getId() + ); + } + } + } +} diff --git a/domokits/local/modules/CustomDelivery/Form/ConfigurationForm.php b/domokits/local/modules/CustomDelivery/Form/ConfigurationForm.php new file mode 100644 index 0000000..1a8ec86 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Form/ConfigurationForm.php @@ -0,0 +1,130 @@ + + */ +class ConfigurationForm extends BaseForm +{ + public function checkTaxRuleId($value, ExecutionContextInterface $context) + { + if (0 !== intval($value)) { + if (null === TaxRuleQuery::create()->findPk($value)) { + $context->addViolation( + $this->trans( + "The Tax Rule id '%id' doesn't exist", + [ + "%id" => $value, + ] + ) + ); + } + } + } + + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return "customdelivery-configuration-form"; + } + + protected function buildForm() + { + $form = $this->formBuilder; + + $config = CustomDelivery::getConfig(); + + $form + ->add( + "url", + TextType::class, + [ + 'constraints' => [ + new NotBlank() + ], + 'data' => $config['url'], + 'label' => $this->trans("Tracking URL"), + 'label_attr' => [ + 'for' => "url", + 'help' => $this->trans( + "The tracking URL. %ID% will be replaced by the tracking number entered in the order" + ) + ], + ] + ) + ->add( + "method", + ChoiceType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(['value' => 0]) + ], + "choices" => [ + $this->trans("Price and weight") => CustomDelivery::METHOD_PRICE_WEIGHT, + $this->trans("Price") => CustomDelivery::METHOD_PRICE, + $this->trans("Weight") =>CustomDelivery::METHOD_WEIGHT + ], + 'data' => $config['method'], + 'label' => $this->trans("Method"), + 'label_attr' => [ + 'for' => "method", + 'help' => $this->trans( + "The method used to select the right slice." + ) + ], + ] + ) + ->add( + "tax", + TaxRuleIdType::class, + [ + "constraints" => [ + new Callback( + [$this, 'checkTaxRuleId'] + ), + ], + 'required' => false, + 'data' => $config['tax'], + 'label' => $this->trans("Tax rule"), + 'label_attr' => [ + 'for' => "method", + 'help' => $this->trans( + "The tax rule used to calculate postage taxes." + ) + ], + ] + ); + } + + protected function trans($id, array $parameters = []) + { + return $this->translator->trans($id, $parameters, CustomDelivery::MESSAGE_DOMAIN); + } +} diff --git a/domokits/local/modules/CustomDelivery/Form/SliceForm.php b/domokits/local/modules/CustomDelivery/Form/SliceForm.php new file mode 100644 index 0000000..06c40c5 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Form/SliceForm.php @@ -0,0 +1,92 @@ + + */ +class SliceForm extends BaseForm +{ + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return "customdelivery-configuration-form"; + } + + protected function buildForm() + { + $form = $this->formBuilder; + + $form + ->add( + "id", + NumberType::class, + [ + 'constraints' => [ + new NotBlank() + ], + 'label' => $this->trans("Id") + ] + ) + ->add( + "area", + AreaIdType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(['value' => 0]) + ], + 'label' => $this->trans("Area"), + ] + ) + ->add( + "priceMax", + FloatType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(['value' => 0]) + ], + 'label' => $this->trans("Area"), + ] + ) + ->add( + "weightMax", + FloatType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(['value' => 0]) + ], + 'label' => $this->trans("Area"), + ] + ); + } + + protected function trans($id, array $parameters = []) + { + return $this->translator->trans($id, $parameters, CustomDelivery::MESSAGE_DOMAIN); + } +} diff --git a/domokits/local/modules/CustomDelivery/Hook/HookManager.php b/domokits/local/modules/CustomDelivery/Hook/HookManager.php new file mode 100644 index 0000000..e82655a --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Hook/HookManager.php @@ -0,0 +1,67 @@ + + */ +class HookManager extends BaseHook +{ + + public function onAccountOrderAfterProducts(HookRenderEvent $event) + { + $orderId = $event->getArgument('order'); + + if (null !== $orderId) { + $render = $this->render( + 'account-order-after-products.html', + [ + "order_id" => $orderId + ] + ); + $event->add($render); + } + + $event->stopPropagation(); + } + + public function onModuleConfiguration(HookRenderEvent $event) + { + $moduleId = $this->getModule()->getModuleId(); + $config = CustomDelivery::getConfig(); + + $event->add( + $this->render( + "module-configuration.html", + [ + 'module_id' => $moduleId, + 'method' => $config['method'] + ] + ) + ); + } + + public function onModuleConfigJs(HookRenderEvent $event) + { + $event->add( + $this->render("module-config-js.html") + ); + } +} diff --git a/domokits/local/modules/CustomDelivery/I18n/backOffice/default/en_US.php b/domokits/local/modules/CustomDelivery/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..4c34c00 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/backOffice/default/en_US.php @@ -0,0 +1,19 @@ + 'Actions', + 'Add this price slice' => 'Add this price slice', + 'Area : ' => 'Area : ', + 'Configuration.' => 'Configuration.', + 'Delete this price slice' => 'Delete this price slice', + 'Message' => 'Message', + 'No taxes' => 'No taxes', + 'Price (%symbol)' => 'Price (%symbol)', + 'Save' => 'Save', + 'Save this price slice' => 'Save this price slice', + 'Slices.' => 'Slices.', + 'Untaxed Price up to ... %symbol' => 'Untaxed Price up to ... %symbol', + 'Weight up to ... kg' => 'Weight up to ... kg', + 'You should first attribute shipping zones to the modules: ' => 'You should first attribute shipping zones to the module: ', + 'manage shipping zones' => 'manage shipping zones', +); diff --git a/domokits/local/modules/CustomDelivery/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/CustomDelivery/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..6b6e2ef --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,19 @@ + 'Actions', + 'Add this price slice' => 'Ajouter cette tranche', + 'Area : ' => 'Zone :', + 'Configuration.' => 'Configuration.', + 'Delete this price slice' => 'Supprimer cette tranche', + 'Message' => 'Message', + 'No taxes' => 'Pas de taxe', + 'Price (%symbol)' => 'Prix (%symbol)', + 'Save' => 'Enregistrer', + 'Save this price slice' => 'Enregistrer cette tranche', + 'Slices.' => 'Tranches.', + 'Untaxed Price up to ... %symbol' => 'Prix HT jusqu\'à ... %symbol', + 'Weight up to ... kg' => 'Poids jusqu\'à ... kg', + 'You should first attribute shipping zones to the modules: ' => 'Vous devez d\'abord attribuer des zones de livraisons au module :', + 'manage shipping zones' => 'gèrer les zones de livraisons', +); diff --git a/domokits/local/modules/CustomDelivery/I18n/email/default/en_US.php b/domokits/local/modules/CustomDelivery/I18n/email/default/en_US.php new file mode 100644 index 0000000..865088d --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/email/default/en_US.php @@ -0,0 +1,11 @@ + 'Best Regards.', + 'Dear' => 'Dear', + 'Feel free to contact us for any further information' => 'Feel free to contact us for any further information', + 'Please check this URL to track your parcel : %tracking_url' => 'Please check this URL to track your parcel : %tracking_url', + 'Thank you for your order on our online store %store_name' => 'Thank you for your order on our online store %store_name', + 'The tracking number for this delivery is: %package' => 'The tracking number for this delivery is: %package', + 'Your order %order_ref dated %order_date has been shipped on %update_date' => 'Your order %order_ref dated %order_date has been shipped on %update_date', +); diff --git a/domokits/local/modules/CustomDelivery/I18n/email/default/fr_FR.php b/domokits/local/modules/CustomDelivery/I18n/email/default/fr_FR.php new file mode 100644 index 0000000..f86e3cd --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/email/default/fr_FR.php @@ -0,0 +1,11 @@ + 'Cordialement.', + 'Dear' => 'Chère', + 'Feel free to contact us for any further information' => 'Vous pouvez nous contacter pour toutes informations complémentaires', + 'Please check this URL to track your parcel : %tracking_url' => 'Vous pouvez suivre votre colis en ligne à cette adresse : %tracking_url', + 'Thank you for your order on our online store %store_name' => 'Merci pour votre commande sur notre boutique en ligne %store_name', + 'The tracking number for this delivery is: %package' => 'Le numéro de suivi pour cette commande est: %package', + 'Your order %order_ref dated %order_date has been shipped on %update_date' => 'Votre commande %order_ref datée du %order_date a été expédié le %update_date', +); diff --git a/domokits/local/modules/CustomDelivery/I18n/en_US.php b/domokits/local/modules/CustomDelivery/I18n/en_US.php new file mode 100644 index 0000000..79bfd28 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/en_US.php @@ -0,0 +1,24 @@ + 'Area', + 'Custom delivery shipping message' => 'Custom delivery shipping message', + 'Id' => 'Id', + 'Method' => 'Method', + 'Price' => 'Price', + 'Price and weight' => 'Price and weight', + 'Tax rule' => 'Tax rule', + 'The Tax Rule id \'%id\' doesn\'t exist' => 'The Tax Rule id \'%id\' doesn\'t exist', + 'The area is not valid' => 'The area is not valid', + 'The method used to select the right slice.' => 'The method used to select the right slice.', + 'The price max value is not valid' => 'The price max value is not valid', + 'The price value is not valid' => 'The price value is not valid', + 'The slice has not been deleted' => 'The slice has not been deleted', + 'The tax rule used to calculate postage taxes.' => 'The tax rule used to calculate postage taxes.', + 'The tracking URL. %ID% will be replaced by the tracking number entered in the order' => 'The tracking URL. %ID% will be replaced by the tracking number entered in the order', + 'The weight max value is not valid' => 'The weight max value is not valid', + 'Tracking URL' => 'Tracking URL', + 'Weight' => 'Weight', + 'Your order {$order_ref} has been shipped' => 'Your order {$order_ref} has been shipped', + 'Your slice has been saved' => 'Your slice has been saved', +); diff --git a/domokits/local/modules/CustomDelivery/I18n/fr_FR.php b/domokits/local/modules/CustomDelivery/I18n/fr_FR.php new file mode 100644 index 0000000..5273164 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/I18n/fr_FR.php @@ -0,0 +1,24 @@ + 'Zone', + 'Custom delivery shipping message' => 'Message d\'envoi pour la livraison personnalisée', + 'Id' => 'Id', + 'Method' => 'Méthode', + 'Price' => 'Prix', + 'Price and weight' => 'Prix et poids', + 'Tax rule' => 'Règle de taxe', + 'The Tax Rule id \'%id\' doesn\'t exist' => 'La règle de taxe id \'%id\' n\'existe pas', + 'The area is not valid' => 'La zone n\'est pas valide', + 'The method used to select the right slice.' => 'La méthode utilisée pour sélectionner la bonne tranche.', + 'The price max value is not valid' => 'La valeur du prix max n\'est pas valide', + 'The price value is not valid' => 'La valeur du prix n\'est pas valide', + 'The slice has not been deleted' => 'Votre tranche n\'a pas été supprimé', + 'The tax rule used to calculate postage taxes.' => 'La règle de taxe utilisée pour calculer les taxes associés à la livraison.', + 'The tracking URL. %ID% will be replaced by the tracking number entered in the order' => 'L\'URL de suivi. %ID% sera remplacé par le numéro de suivi saisi dans la commande', + 'The weight max value is not valid' => 'La valeur du poids max n\'est pas valide', + 'Tracking URL' => 'URL de suivi', + 'Weight' => 'Poids', + 'Your order {$order_ref} has been shipped' => 'Votre commande {$order_ref} vient d\'être expédiée', + 'Your slice has been saved' => 'Votre tranche a été sauvegardé', +); diff --git a/domokits/local/modules/CustomDelivery/LICENSE b/domokits/local/modules/CustomDelivery/LICENSE new file mode 100644 index 0000000..fb6d90b --- /dev/null +++ b/domokits/local/modules/CustomDelivery/LICENSE @@ -0,0 +1,166 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/domokits/local/modules/CustomDelivery/Loop/CustomDeliverySliceLoop.php b/domokits/local/modules/CustomDelivery/Loop/CustomDeliverySliceLoop.php new file mode 100644 index 0000000..ff26d64 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Loop/CustomDeliverySliceLoop.php @@ -0,0 +1,168 @@ + + */ +class CustomDeliverySliceLoop extends BaseLoop implements PropelSearchLoopInterface +{ + protected $timestampable = false; + + protected $versionable = false; + + /** + * @param LoopResult $loopResult + * + * @return LoopResult + */ + public function parseResults(LoopResult $loopResult) + { + /** @var CustomDeliverySlice $slice */ + foreach ($loopResult->getResultDataCollection() as $slice) { + + $loopResultRow = new LoopResultRow($slice); + + $loopResultRow + ->set("ID", $slice->getId()) + ->set("AREA_ID", $slice->getAreaId()) + ->set("PRICE_MAX", $slice->getPriceMax()) + ->set("WEIGHT_MAX", $slice->getWeightMax()) + ->set("PRICE", $slice->getPrice()); + + $this->addOutputFields($loopResultRow, $slice); + + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } + + /** + * this method returns a Propel ModelCriteria + * + * @return \Propel\Runtime\ActiveQuery\ModelCriteria + */ + public function buildModelCriteria() + { + $query = CustomDeliverySliceQuery::create(); + + $id = $this->getArgValue('id'); + if (null !== $id) { + $query->filterById($id, Criteria::IN); + } + + $id = $this->getArgValue('area_id'); + if (null !== $id) { + $query->filterByAreaId($id, Criteria::IN); + } + + $orders = $this->getArgValue('order'); + + foreach ($orders as $order) { + switch ($order) { + case "id": + $query->orderById(Criteria::ASC); + break; + case "id_reverse": + $query->orderById(Criteria::DESC); + break; + case "weight_max": + $query->orderByWeightMax(Criteria::ASC); + break; + case "weight_max_reverse": + $query->orderByWeightMax(Criteria::DESC); + break; + case "price_max": + $query->orderByPriceMax(Criteria::ASC); + break; + case "price_max_reverse": + $query->orderByPriceMax(Criteria::DESC); + break; + case "price": + $query->orderByPrice(Criteria::ASC); + break; + case "price_reverse": + $query->orderByPrice(Criteria::DESC); + break; + } + } + + return $query; + } + + /** + * Definition of loop arguments + * + * example : + * + * public function getArgDefinitions() + * { + * return new ArgumentCollection( + * + * Argument::createIntListTypeArgument('id'), + * new Argument( + * 'ref', + * new TypeCollection( + * new Type\AlphaNumStringListType() + * ) + * ), + * Argument::createIntListTypeArgument('category'), + * Argument::createBooleanTypeArgument('new'), + * ... + * ); + * } + * + * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntListTypeArgument('id'), + Argument::createIntListTypeArgument('area_id'), + new Argument( + 'order', + new TypeCollection( + new EnumListType( + [ + 'id', + 'id_reverse', + 'weight_max', + 'weight_max_reverse', + 'price_max', + 'price_max_reverse', + 'price', + 'price_reverse', + ] + ) + ), + 'id' + ) + ); + } +} diff --git a/domokits/local/modules/CustomDelivery/Model/CustomDeliverySlice.php b/domokits/local/modules/CustomDelivery/Model/CustomDeliverySlice.php new file mode 100644 index 0000000..aa4d36f --- /dev/null +++ b/domokits/local/modules/CustomDelivery/Model/CustomDeliverySlice.php @@ -0,0 +1,10 @@ +/local/modules/``` directory and be sure that the name of the module is CustomDelivery. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/custom-delivery-module:~1.0 +``` + +## Usage + +Just enter the price you want for each area in the configuration page of the module. +You can create as many slices you want. These slices are based on the amount price and/or the weight of an order. You +can associate an optional taxe rule to the module to include taxes for the shipment. + + +# customization + +You can customize the mails sent by the module in the **Mailing templates** configuration page in the back-office. The + template used is called `mail_custom_delivery`. diff --git a/domokits/local/modules/CustomDelivery/composer.json b/domokits/local/modules/CustomDelivery/composer.json new file mode 100644 index 0000000..277e415 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/custom-delivery-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "CustomDelivery" + } +} \ No newline at end of file diff --git a/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-config-js.html b/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-config-js.html new file mode 100644 index 0000000..f064982 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-config-js.html @@ -0,0 +1,127 @@ + +{javascripts file='assets/js/libs/underscore-min.js'} + +{/javascripts} + + \ No newline at end of file diff --git a/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-configuration.html b/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-configuration.html new file mode 100644 index 0000000..1909641 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/templates/backOffice/default/module-configuration.html @@ -0,0 +1,195 @@ + +
+
+ +
+ {intl d='customdelivery.bo.default' l='Configuration.'} +
+ +
+
+ + {form name="customdelivery.configuration.form"} + + + {if $form_error_message}
{$form_error_message}
{/if} + + {form_hidden_fields form=$form} + + {render_form_field form=$form field="url"} + {render_form_field form=$form field="method"} + + {form_field form=$form field="tax"} +
+ + + +
+ {/form_field} + + + + + {/form} + +
+ +
+ +
+
+ + +{* default currency *} +{loop type="currency" name="default_currency" default_only="1"} + {$currencySymbol=$SYMBOL} +{/loop} + + +
+
+ +
+ {intl d='customdelivery.bo.default' l='Slices.'} +
+ +
+ + {loop type="area" name="area" module_id=$module_id backend_context=true} + {$area_id=$ID} +
+
+ + + + + {if $method != 2}{/if} + {if $method != 1}{/if} + + + + + + {loop type="custom-delivery-slice" name="custom-delivery-slice" area_id=$area_id order="weight_max,price_max" } + + {if $method != 2} + + {/if} + {if $method != 1} + + {/if} + + + + {/loop} + + {* New slice *} + {loop type="auth" name="can_change" role="ADMIN" module="customdelivery" access="CREATE"} + + {if $method != 2} + + {/if} + {if $method != 1} + + {/if} + + + + {/loop} + +
+ {intl d='customdelivery.bo.default' l="Area : "} {$NAME} +
{intl d='customdelivery.bo.default' l="Untaxed Price up to ... %symbol" symbol=$currencySymbol}{intl d='customdelivery.bo.default' l="Weight up to ... kg"}{intl d='customdelivery.bo.default' l="Price (%symbol)" symbol=$currencySymbol}{intl d='customdelivery.bo.default' l="Actions"}
+ + + + + + +
+ {loop type="auth" name="can_change" role="ADMIN" module="customdelivery" access="UPDATE"} + + + + {/loop} + {loop type="auth" name="can_change" role="ADMIN" module="customdelivery" access="DELETE"} + + + + {/loop} +
+
+ + + + + + + + + +
+
+
+ + {/loop} + {elseloop rel="area"} +
+
+ {intl d='customdelivery.bo.default' l="You should first attribute shipping zones to the modules: "} + + {intl d='customdelivery.bo.default' l="manage shipping zones"} + +
+
+ {/elseloop} +
+ +
+
+ +{include + file = "includes/generic-warning-dialog.html" + + dialog_id = "custom_delivery_dialog" + dialog_title = {intl d='customdelivery.bo.default' l="Message"} + dialog_body = "" +} + +{* JS Templates *} + diff --git a/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.html b/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.html new file mode 100644 index 0000000..0b1137e --- /dev/null +++ b/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.html @@ -0,0 +1,17 @@ +{default_translation_domain domain="customdelivery.email.default"} + +{loop type="customer" name="customer.order" current="false" id="$customer_id" backend_context="1"} +

{intl l="Dear" } {$LASTNAME} {$FIRSTNAME},

+{/loop} + +

{intl l="Thank you for your order on our online store %store_name" store_name={config key="store_name"}}

+

{intl l="Your order %order_ref dated %order_date has been shipped on %update_date" order_ref={$order_ref} order_date={format_date date=$order_date} update_date={format_date date=$update_date}}

+{if $package} +

{intl l="The tracking number for this delivery is: %package" package={$package}}

+{if $tracking_url} +

{intl l="Please check this URL to track your parcel : %tracking_url" tracking_url={$tracking_url}}

+{/if} +{/if} +

{intl l="Feel free to contact us for any further information"}

+ +

{intl l="Best Regards."}

\ No newline at end of file diff --git a/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.txt b/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.txt new file mode 100644 index 0000000..04f5026 --- /dev/null +++ b/domokits/local/modules/CustomDelivery/templates/email/default/custom-delivery-shipping.txt @@ -0,0 +1,18 @@ +{default_translation_domain domain="customdelivery.email.default"} + +{loop type="customer" name="customer.order" current="false" id="$customer_id" backend_context="1"} + {intl l="Dear" } {$LASTNAME} {$FIRSTNAME}, +{/loop} + +{intl l="Thank you for your order on our online store %store_name" store_name={config key="store_name"}} + +{intl l="Your order %order_ref dated %order_date has been shipped on %update_date" order_ref={$order_ref} order_date={format_date date=$order_date} update_date={format_date date=$update_date}} +{if $package} +{intl l="The tracking number for this delivery is: %package" package={$package}} +{if $tracking_url} +{intl l="Please check this URL to track your parcel : %tracking_url" tracking_url={$tracking_url}} +{/if} +{/if} +{intl l="Feel free to contact us for any further information"} + +{intl l="Best Regards."} \ No newline at end of file diff --git a/domokits/local/modules/FreeOrder/Config/config.xml b/domokits/local/modules/FreeOrder/Config/config.xml new file mode 100644 index 0000000..42d3733 --- /dev/null +++ b/domokits/local/modules/FreeOrder/Config/config.xml @@ -0,0 +1,6 @@ + + + + diff --git a/domokits/local/modules/FreeOrder/Config/module.xml b/domokits/local/modules/FreeOrder/Config/module.xml new file mode 100644 index 0000000..955d422 --- /dev/null +++ b/domokits/local/modules/FreeOrder/Config/module.xml @@ -0,0 +1,27 @@ + + + FreeOrder\FreeOrder + + There's nothing to pay for this order + This is a pseudo-payment module for free orders. + + + Vous n'avez rien à payer pour cette commande + Un pseudo-module de paiement pour les commandes de montant nul + + + en_US + fr_FR + + 2.5.4 + + Franck Allimant + CQFDev + franck@cqfdev.fr + + payment + 2.5.4 + alpha + diff --git a/domokits/local/modules/FreeOrder/FreeOrder.php b/domokits/local/modules/FreeOrder/FreeOrder.php new file mode 100644 index 0000000..099ccb3 --- /dev/null +++ b/domokits/local/modules/FreeOrder/FreeOrder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FreeOrder; + +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\Order; +use Thelia\Model\OrderStatusQuery; +use Thelia\Module\AbstractPaymentModule; + +class FreeOrder extends AbstractPaymentModule +{ + /** + * @return bool + */ + public function isValidPayment() + { + return round($this->getCurrentOrderTotalAmount(), 4) == 0; + } + + public function pay(Order $order): void + { + $event = new OrderEvent($order); + $event->setStatus(OrderStatusQuery::getPaidStatus()->getId()); + $this->getDispatcher()->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + } + + /** + * @return bool + */ + public function manageStockOnCreation() + { + return false; + } +} diff --git a/domokits/local/modules/FreeOrder/LICENSE.txt b/domokits/local/modules/FreeOrder/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/FreeOrder/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/FreeOrder/Readme.md b/domokits/local/modules/FreeOrder/Readme.md new file mode 100644 index 0000000..6333346 --- /dev/null +++ b/domokits/local/modules/FreeOrder/Readme.md @@ -0,0 +1,25 @@ +# Free Order + +This module is used to terminate the order process when the order amount is 0,00. In this case, none of the traditional +payment modules applies. + +## Installation + +This module is bundled with Thelia standard distribution. + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is FreeOrder. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/free-order-module:~1.0 +``` + +## Usage + +The module is displayed as needed in the payment modules list of the order-invoice page. \ No newline at end of file diff --git a/domokits/local/modules/FreeOrder/composer.json b/domokits/local/modules/FreeOrder/composer.json new file mode 100644 index 0000000..f32437e --- /dev/null +++ b/domokits/local/modules/FreeOrder/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/free-order-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "FreeOrder" + } +} \ No newline at end of file diff --git a/domokits/local/modules/Front/Config/config.xml b/domokits/local/modules/Front/Config/config.xml new file mode 100644 index 0000000..4e04106 --- /dev/null +++ b/domokits/local/modules/Front/Config/config.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + Front/Config/front.xml + + %kernel.cache_dir% + %kernel.debug% + + + + + + diff --git a/domokits/local/modules/Front/Config/front.xml b/domokits/local/modules/Front/Config/front.xml new file mode 100644 index 0000000..20bea5d --- /dev/null +++ b/domokits/local/modules/Front/Config/front.xml @@ -0,0 +1,276 @@ + + + + + + Thelia\Controller\Front\DefaultController::noAction + includes/mini-cart + + + + Thelia\Controller\Front\DefaultController::noAction + includes/addedToCart + + + + + Front\Controller\CustomerController::viewRegisterAction + + + + Front\Controller\CustomerController::createAction + register + + + + + Front\Controller\CustomerController::viewLoginAction + + + + Front\Controller\CustomerController::loginAction + login + + + + + Front\Controller\CustomerController::newPasswordAction + password + + + + Front\Controller\CustomerController::newPasswordSentAction + password + + + + + Front\Controller\CustomerController::logoutAction + + + + + Front\Controller\CustomerController::confirmCustomerAction + + + + + + Thelia\Controller\Front\DefaultController::noAction + account + + + + Front\Controller\CustomerController::viewAction + account-update + + + + Front\Controller\CustomerController::updateAction + account-update + + + + + Front\Controller\CustomerController::updatePasswordAction + account-password + + + + Thelia\Controller\Front\DefaultController::noAction + account-password + + + + Front\Controller\OrderController::viewAction + \d+ + + + + Front\Controller\OrderController::generateDeliveryPdf + \d+ + + + + Front\Controller\OrderController::generateInvoicePdf + \d+ + + + + Front\Controller\OrderController::downloadVirtualProduct + \d+ + + + + + + Thelia\Controller\Front\DefaultController::noAction + address + + + + Front\Controller\AddressController::createAction + address + + + + Front\Controller\AddressController::updateViewAction + address-update + + + + Front\Controller\AddressController::processUpdateAction + address-update + + + + Front\Controller\AddressController::deleteAction + account + + + + Front\Controller\AddressController::generateModalAction + modal-address + \d+ + + + + Front:Address:makeAddressDefault + \d+ + + + + + + + Thelia\Controller\Front\DefaultController::noAction + cart + + + + Front\Controller\CartController::addItem + + + + Front\Controller\CartController::deleteItem + cart + + + + Front\Controller\CartController::changeItem + cart + + + + Front\Controller\CartController::changeCountry + cart + + + + + + Front\Controller\OrderController::deliver + order-delivery + + + + Front\Controller\OrderController::deliverView + order-delivery + + + + Front\Controller\OrderController::getDeliveryModuleListAjaxAction + + + + Front\Controller\OrderController::invoice + order-invoice + + + + Thelia\Controller\Front\DefaultController::noAction + order-invoice + + + + Front\Controller\CouponController::consumeAction + order-invoice + + + + Front\Controller\CouponController::clearAllCouponsAction + order-invoice + + + + Front\Controller\OrderController::pay + + + + Front\Controller\OrderController::orderPlaced + order-placed + + + + Front\Controller\OrderController::orderFailed + order-failed + + + + + + Front\Controller\ContactController::sendAction + contact + + + + Thelia\Controller\Front\DefaultController::noAction + contact-success + + + + + + Front\Controller\NewsletterController::subscribeAction + newsletter + + + + Front\Controller\NewsletterController::unsubscribeAction + newsletter-unsubscribe + + + + + + + Front\Controller\SitemapController::generateAction + + + Front\Controller\SitemapController::generateAction + + + + + + Front\Controller\FeedController::generateAction + catalog + + + + + + + + Thelia\Controller\Front\DefaultController::emptyRoute + + + + + Thelia\Controller\Front\DefaultController::noAction + index + ^(?!admin|api)[^/]+ + + diff --git a/domokits/local/modules/Front/Config/module.xml b/domokits/local/modules/Front/Config/module.xml new file mode 100644 index 0000000..1d4876f --- /dev/null +++ b/domokits/local/modules/Front/Config/module.xml @@ -0,0 +1,29 @@ + + + Front\Front + + Front integration + + + + Front office module + + + + en_US + fr_FR + + 2.5.4 + + + Thelia team + info@thelia.net + + + classic + 2.5.4 + alpha + 1 + diff --git a/domokits/local/modules/Front/Controller/AddressController.php b/domokits/local/modules/Front/Controller/AddressController.php new file mode 100644 index 0000000..81426a0 --- /dev/null +++ b/domokits/local/modules/Front/Controller/AddressController.php @@ -0,0 +1,257 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Symfony\Component\Form\Form; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Address\AddressCreateOrUpdateEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\AddressQuery; +use Thelia\Model\Customer; +use Thelia\Model\Event\AddressEvent; + +/** + * Class AddressController. + * + * @author Manuel Raynaud + */ +class AddressController extends BaseFrontController +{ + /** + * Controller for generate modal containing update form + * Check if request is a XmlHttpRequest and address owner is the current customer. + */ + public function generateModalAction($address_id): void + { + $this->checkAuth(); + $this->checkXmlHttpRequest(); + } + + /** + * Create controller. + * Check if customer is logged in. + * + * Dispatch TheliaEvents::ADDRESS_CREATE event + */ + public function createAction(EventDispatcherInterface $eventDispatcher) + { + $this->checkAuth(); + + $addressCreate = $this->createForm(FrontForm::ADDRESS_CREATE); + + try { + /** @var Customer $customer */ + $customer = $this->getSecurityContext()->getCustomerUser(); + + $form = $this->validateForm($addressCreate, 'post'); + $event = $this->createAddressEvent($form); + $event->setCustomer($customer); + + $eventDispatcher->dispatch($event, TheliaEvents::ADDRESS_CREATE); + + return $this->generateSuccessRedirect($addressCreate); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans('Please check your input: %s', ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans('Sorry, an error occured: %s', ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN); + } + + Tlog::getInstance()->error(sprintf('Error during address creation process : %s', $message)); + + $addressCreate->setErrorMessage($message); + + $this->getParserContext() + ->addForm($addressCreate) + ->setGeneralError($message) + ; + + // Redirect to error URL if defined + if ($addressCreate->hasErrorUrl()) { + return $this->generateErrorRedirect($addressCreate); + } + } + + protected function createAddressEvent(Form $form) + { + return new AddressCreateOrUpdateEvent( + $form->get('label')->getData(), + $form->get('title')->getData(), + $form->get('firstname')->getData(), + $form->get('lastname')->getData(), + $form->get('address1')->getData(), + $form->get('address2')->getData(), + $form->get('address3')->getData(), + $form->get('zipcode')->getData(), + $form->get('city')->getData(), + $form->get('country')->getData(), + $form->get('cellphone')->getData(), + $form->get('phone')->getData(), + $form->get('company')->getData(), + $form->get('is_default')->getData(), + $form->get('state')->getData() + ); + } + + public function updateViewAction($address_id) + { + $this->checkAuth(); + + $customer = $this->getSecurityContext()->getCustomerUser(); + $address = AddressQuery::create()->findPk($address_id); + + if (!$address || $customer->getId() != $address->getCustomerId()) { + return $this->generateRedirectFromRoute('default'); + } + + $this->getParserContext()->set('address_id', $address_id); + } + + public function processUpdateAction($address_id, EventDispatcherInterface $eventDispatcher) + { + $this->checkAuth(); + + $addressUpdate = $this->createForm(FrontForm::ADDRESS_UPDATE); + + try { + $customer = $this->getSecurityContext()->getCustomerUser(); + + $form = $this->validateForm($addressUpdate); + + $address = AddressQuery::create()->findPk($address_id); + + if (null === $address) { + return $this->generateRedirectFromRoute('default'); + } + + if ($address->getCustomer()->getId() != $customer->getId()) { + return $this->generateRedirectFromRoute('default'); + } + + $event = $this->createAddressEvent($form); + $event->setAddress($address); + + $eventDispatcher->dispatch($event, TheliaEvents::ADDRESS_UPDATE); + + return $this->generateSuccessRedirect($addressUpdate); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans('Please check your input: %s', ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans('Sorry, an error occured: %s', ['%s' => $e->getMessage()], Front::MESSAGE_DOMAIN); + } + + $this->getParserContext()->set('address_id', $address_id); + + Tlog::getInstance()->error(sprintf('Error during address creation process : %s', $message)); + + $addressUpdate->setErrorMessage($message); + + $this->getParserContext() + ->addForm($addressUpdate) + ->setGeneralError($message) + ; + + if ($addressUpdate->hasErrorUrl()) { + return $this->generateErrorRedirect($addressUpdate); + } + } + + public function deleteAction(EventDispatcherInterface $eventDispatcher, $address_id) + { + $this->checkAuth(); + $error_message = false; + + $customer = $this->getSecurityContext()->getCustomerUser(); + $address = AddressQuery::create()->findPk($address_id); + + if (!$address || $customer->getId() != $address->getCustomerId()) { + // If Ajax Request + if ($this->getRequest()->isXmlHttpRequest()) { + return $this->jsonResponse( + json_encode( + [ + 'success' => false, + 'message' => $this->getTranslator()->trans( + 'Error during address deletion process', + [], + Front::MESSAGE_DOMAIN + ), + ] + ) + ); + } + + return $this->generateRedirectFromRoute('default'); + } + + try { + $eventDispatcher->dispatch(new AddressEvent($address), TheliaEvents::ADDRESS_DELETE); + } catch (\Exception $e) { + $error_message = $e->getMessage(); + } + + Tlog::getInstance()->error(sprintf('Error during address deletion : %s', $error_message)); + + // If Ajax Request + if ($this->getRequest()->isXmlHttpRequest()) { + if ($error_message) { + $response = $this->jsonResponse(json_encode([ + 'success' => false, + 'message' => $error_message, + ])); + } else { + $response = $this->jsonResponse( + json_encode([ + 'success' => true, + 'message' => '', + ]) + ); + } + + return $response; + } + + return $this->generateRedirectFromRoute('default', ['view' => 'account']); + } + + public function makeAddressDefaultAction(EventDispatcherInterface $eventDispatcher, $addressId) + { + $this->checkAuth(); + + $address = AddressQuery::create() + ->filterByCustomerId($this->getSecurityContext()->getCustomerUser()->getId()) + ->findPk($addressId) + ; + + if (null === $address) { + $this->pageNotFound(); + } + + try { + $event = new AddressEvent($address); + $eventDispatcher->dispatch($event, TheliaEvents::ADDRESS_DEFAULT); + } catch (\Exception $e) { + $this->getParserContext() + ->setGeneralError($e->getMessage()) + ; + + return $this->render('account'); + } + + return $this->generateRedirectFromRoute('default', ['view' => 'account']); + } +} diff --git a/domokits/local/modules/Front/Controller/CartController.php b/domokits/local/modules/Front/Controller/CartController.php new file mode 100644 index 0000000..edc022b --- /dev/null +++ b/domokits/local/modules/Front/Controller/CartController.php @@ -0,0 +1,241 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Propel\Runtime\Exception\PropelException; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Cart\CartEvent; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Form\CartAdd; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\AddressQuery; +use Thelia\Model\ConfigQuery; +use Thelia\Tools\URL; + +class CartController extends BaseFrontController +{ + public function addItem(EventDispatcherInterface $eventDispatcher) + { + $request = $this->getRequest(); + + $cartAdd = $this->getAddCartForm($request); + $message = null; + + try { + $form = $this->validateForm($cartAdd); + + $cartEvent = $this->getCartEvent($eventDispatcher); + + $cartEvent->bindForm($form); + + $eventDispatcher->dispatch($cartEvent, TheliaEvents::CART_ADDITEM); + + $this->afterModifyCart($eventDispatcher); + + if (!$this->changeViewForAjax()) { + if (null !== $response = $this->generateSuccessRedirect($cartAdd)) { + return $response; + } + } + } catch (PropelException $e) { + Tlog::getInstance()->error(sprintf('Failed to add item to cart with message : %s', $e->getMessage())); + $message = $this->getTranslator()->trans( + 'Failed to add this article to your cart, please try again', + [], + Front::MESSAGE_DOMAIN + ); + } catch (FormValidationException $e) { + $message = $e->getMessage(); + } + + if ($message) { + $cartAdd->setErrorMessage($message); + $this->getParserContext()->addForm($cartAdd); + } + } + + public function changeItem(EventDispatcherInterface $eventDispatcher) + { + $cartEvent = $this->getCartEvent($eventDispatcher); + $cartEvent->setCartItemId($this->getRequest()->get('cart_item')); + $cartEvent->setQuantity($this->getRequest()->get('quantity')); + + try { + $this->getTokenProvider()->checkToken( + $this->getRequest()->query->get('_token') + ); + + $eventDispatcher->dispatch($cartEvent, TheliaEvents::CART_UPDATEITEM); + + $this->afterModifyCart($eventDispatcher); + + if (!$this->changeViewForAjax()) { + if (null !== $successUrl = $this->getRequest()->get('success_url')) { + return $this->generateRedirect(URL::getInstance()->absoluteUrl($successUrl)); + } + } + } catch (\Exception $e) { + Tlog::getInstance()->error(sprintf('Failed to change cart item quantity: %s', $e->getMessage())); + + $this->getParserContext()->setGeneralError($e->getMessage()); + } + } + + public function deleteItem(EventDispatcherInterface $eventDispatcher) + { + $cartEvent = $this->getCartEvent($eventDispatcher); + $cartEvent->setCartItemId($this->getRequest()->get('cart_item')); + + try { + $this->getTokenProvider()->checkToken( + $this->getRequest()->query->get('_token') + ); + + $eventDispatcher->dispatch($cartEvent, TheliaEvents::CART_DELETEITEM); + + $this->afterModifyCart($eventDispatcher); + } catch (\Exception $e) { + Tlog::getInstance()->error(sprintf('error during deleting cartItem with message : %s', $e->getMessage())); + $this->getParserContext()->setGeneralError($e->getMessage()); + } + + if (!$this->changeViewForAjax()) { + if (null !== $successUrl = $this->getRequest()->get('success_url')) { + return $this->generateRedirect(URL::getInstance()->absoluteUrl($successUrl)); + } + } + } + + protected function changeViewForAjax() + { + // If this is an ajax request, and if the template allow us to return an ajax result + if ($this->getRequest()->isXmlHttpRequest() && (0 === (int) $this->getRequest()->get('no_ajax_check', 0))) { + $request = $this->getRequest(); + + $view = $request->get('ajax-view', 'includes/mini-cart'); + + $request->attributes->set('_view', $view); + + return true; + } + + return false; + } + + public function changeCountry() + { + $redirectUrl = URL::getInstance()->absoluteUrl('/cart'); + $deliveryId = $this->getRequest()->get('country'); + $cookieName = ConfigQuery::read('front_cart_country_cookie_name', 'fcccn'); + $cookieExpires = ConfigQuery::read('front_cart_country_cookie_expires', 2592000); + $cookieExpires = (int) $cookieExpires ?: 2592000; + + $cookie = new Cookie($cookieName, $deliveryId, time() + $cookieExpires, '/'); + + $response = $this->generateRedirect($redirectUrl); + $response->headers->setCookie($cookie); + + return $response; + } + + /** + * @return \Thelia\Core\Event\Cart\CartEvent + */ + protected function getCartEvent(EventDispatcherInterface $eventDispatcher) + { + $cart = $this->getSession()->getSessionCart($eventDispatcher); + + return new CartEvent($cart); + } + + /** + * Find the good way to construct the cart form. + * + * @return CartAdd + */ + private function getAddCartForm(Request $request) + { + /* @var CartAdd $cartAdd */ + if ($request->isMethod('post')) { + $cartAdd = $this->createForm(FrontForm::CART_ADD); + } else { + $cartAdd = $this->createForm( + FrontForm::CART_ADD, + FormType::class, + [], + [ + 'csrf_protection' => false, + ] + ); + } + + return $cartAdd; + } + + /** + * @throws PropelException + */ + protected function afterModifyCart(EventDispatcherInterface $eventDispatcher): void + { + /* recalculate postage amount */ + $order = $this->getSession()->getOrder(); + if (null !== $order) { + $deliveryModule = $order->getModuleRelatedByDeliveryModuleId(); + $deliveryAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress()); + + if (null !== $deliveryModule && null !== $deliveryAddress) { + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + + $orderEvent = new OrderEvent($order); + + try { + $deliveryPostageEvent = new DeliveryPostageEvent( + $moduleInstance, + $this->getSession()->getSessionCart($eventDispatcher), + $deliveryAddress + ); + + $eventDispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + ); + + $postage = $deliveryPostageEvent->getPostage(); + + if (null !== $postage) { + $orderEvent->setPostage($postage->getAmount()); + $orderEvent->setPostageTax($postage->getAmountTax()); + $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); + } + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + } catch (\Exception $ex) { + // The postage has been chosen, but changes in the cart causes an exception. + // Reset the postage data in the order + $orderEvent->setDeliveryModule(0); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + } + } + } + } +} diff --git a/domokits/local/modules/Front/Controller/ContactController.php b/domokits/local/modules/Front/Controller/ContactController.php new file mode 100644 index 0000000..1717f21 --- /dev/null +++ b/domokits/local/modules/Front/Controller/ContactController.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Contact\ContactEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Template\ParserContext; +use Thelia\Core\Translation\Translator; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Mailer\MailerFactory; +use Thelia\Model\ConfigQuery; + +/** + * Class ContactController. + * + * @author Manuel Raynaud + * @author Loïc Mo + */ +class ContactController extends BaseFrontController +{ + /** + * Send contact message. + */ + public function sendAction(EventDispatcherInterface $eventDispatcher, MailerFactory $mailer, ParserContext $parserContext) + { + $translator = Translator::getInstance(); + $contactForm = $this->createForm(FrontForm::CONTACT); + + try { + $form = $this->validateForm($contactForm); + $event = new ContactEvent($form); + $eventDispatcher->dispatch($event, TheliaEvents::CONTACT_SUBMIT); + + $name = $translator?->trans('Sender name: %name%', ['%name%' => $event->getName()]); + $email = $translator?->trans('Sender\'s e-mail address: %email%', ['%email%' => $event->getEmail()]); + $message = $translator?->trans('Message content: %message%', ['%message%' => $event->getMessage()]); + + $messageContent = + "

$name

\n". + "

$email

\n". + "

$message

"; + + $mailer->sendSimpleEmailMessage( + [ConfigQuery::getStoreEmail() => $event->getName()], + [ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName()], + $event->getSubject(), + $messageContent, + strip_tags($messageContent), + [], + [], + [$event->getEmail() => $event->getName()] + ); + + if ($contactForm->hasSuccessUrl()) { + return $this->generateSuccessRedirect($contactForm); + } + + return $this->generateRedirectFromRoute('contact.success'); + } catch (FormValidationException $e) { + $error_message = $e->getMessage(); + } + + Tlog::getInstance()->error(sprintf('Error during sending contact mail : %s', $error_message)); + + $contactForm->setErrorMessage($error_message); + + $parserContext + ->addForm($contactForm) + ->setGeneralError($error_message) + ; + + // Redirect to error URL if defined + if ($contactForm->hasErrorUrl()) { + return $this->generateErrorRedirect($contactForm); + } + } +} diff --git a/domokits/local/modules/Front/Controller/CouponController.php b/domokits/local/modules/Front/Controller/CouponController.php new file mode 100644 index 0000000..3ddb749 --- /dev/null +++ b/domokits/local/modules/Front/Controller/CouponController.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Propel\Runtime\Exception\PropelException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Coupon\CouponConsumeEvent; +use Thelia\Core\Event\DefaultActionEvent; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Exception\UnmatchableConditionException; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\AddressQuery; + +/** + * Class CouponController. + * + * @author Guillaume MOREL + */ +class CouponController extends BaseFrontController +{ + /** + * Clear all coupons. + */ + public function clearAllCouponsAction(EventDispatcherInterface $eventDispatcher): void + { + // Dispatch Event to the Action + $eventDispatcher->dispatch(new DefaultActionEvent(), TheliaEvents::COUPON_CLEAR_ALL); + } + + /** + * Coupon consuming. + */ + public function consumeAction(EventDispatcherInterface $eventDispatcher) + { + $this->checkCartNotEmpty($eventDispatcher); + + $message = false; + $couponCodeForm = $this->createForm(FrontForm::COUPON_CONSUME); + + try { + $form = $this->validateForm($couponCodeForm, 'post'); + + $couponCode = $form->get('coupon-code')->getData(); + + if (null === $couponCode || empty($couponCode)) { + $message = true; + throw new \Exception( + $this->getTranslator()->trans( + 'Coupon code can\'t be empty', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + + $couponConsumeEvent = new CouponConsumeEvent($couponCode); + + // Dispatch Event to the Action + $eventDispatcher->dispatch($couponConsumeEvent, TheliaEvents::COUPON_CONSUME); + + /* recalculate postage amount */ + $order = $this->getSession()->getOrder(); + + if (null !== $order) { + $deliveryModule = $order->getModuleRelatedByDeliveryModuleId(); + $deliveryAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress()); + + if (null !== $deliveryModule && null !== $deliveryAddress) { + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + + $orderEvent = new OrderEvent($order); + + try { + $deliveryPostageEvent = new DeliveryPostageEvent( + $moduleInstance, + $this->getSession()->getSessionCart($eventDispatcher), + $deliveryAddress + ); + + $eventDispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + $postage = $deliveryPostageEvent->getPostage(); + + $orderEvent->setPostage($postage->getAmount()); + $orderEvent->setPostageTax($postage->getAmountTax()); + $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + } catch (\Exception $ex) { + // The postage has been chosen, but changes dues to coupon causes an exception. + // Reset the postage data in the order + $orderEvent->setDeliveryModule(0); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + } + } + } + + return $this->generateSuccessRedirect($couponCodeForm); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your coupon code: %message', + ['%message' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } catch (UnmatchableConditionException $e) { + $message = $this->getTranslator()->trans( + 'You should sign in or register to use this coupon', + [ + '%sign' => $this->retrieveUrlFromRouteId('customer.login.view'), + '%register' => $this->retrieveUrlFromRouteId('customer.create.view'), + ], + Front::MESSAGE_DOMAIN + ); + } catch (PropelException $e) { + $this->getParserContext()->setGeneralError($e->getMessage()); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occurred: %message', + ['%message' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } + + if ($message !== false) { + Tlog::getInstance()->error( + sprintf('Error during order delivery process : %s. Exception was %s', $message, $e->getMessage()) + ); + + $couponCodeForm->setErrorMessage($message); + + $this->getParserContext() + ->addForm($couponCodeForm) + ->setGeneralError($message); + } + + return $this->generateErrorRedirect($couponCodeForm); + } +} diff --git a/domokits/local/modules/Front/Controller/CustomerController.php b/domokits/local/modules/Front/Controller/CustomerController.php new file mode 100644 index 0000000..e64a8f5 --- /dev/null +++ b/domokits/local/modules/Front/Controller/CustomerController.php @@ -0,0 +1,595 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent; +use Thelia\Core\Event\Customer\CustomerLoginEvent; +use Thelia\Core\Event\DefaultActionEvent; +use Thelia\Core\Event\LostPasswordEvent; +use Thelia\Core\Event\Newsletter\NewsletterEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Security\Authentication\CustomerUsernamePasswordFormAuthenticator; +use Thelia\Core\Security\Exception\AuthenticationException; +use Thelia\Core\Security\Exception\CustomerNotConfirmedException; +use Thelia\Core\Security\Exception\UsernameNotFoundException; +use Thelia\Core\Security\Exception\WrongPasswordException; +use Thelia\Form\CustomerLogin; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\ConfigQuery; +use Thelia\Model\Customer; +use Thelia\Model\CustomerQuery; +use Thelia\Model\Event\CustomerEvent; +use Thelia\Model\Newsletter; +use Thelia\Model\NewsletterQuery; +use Thelia\Tools\RememberMeTrait; +use Thelia\Tools\URL; + +/** + * Class CustomerController. + * + * @author Manuel Raynaud + */ +class CustomerController extends BaseFrontController +{ + use RememberMeTrait; + + /** + * Display the register template if no customer logged. + */ + public function viewLoginAction() + { + if ($this->getSecurityContext()->hasCustomerUser()) { + // Redirect to home page + return $this->generateRedirect(URL::getInstance()->getIndexPage()); + } + + return $this->render('login'); + } + + /** + * Display the register template if no customer logged. + */ + public function viewRegisterAction() + { + if ($this->getSecurityContext()->hasCustomerUser()) { + // Redirect to home page + return $this->generateRedirect(URL::getInstance()->getIndexPage()); + } + + return $this->render('register'); + } + + public function newPasswordAction(EventDispatcherInterface $eventDispatcher) + { + $passwordLost = $this->createForm(FrontForm::CUSTOMER_LOST_PASSWORD); + + if (!$this->getSecurityContext()->hasCustomerUser()) { + try { + $form = $this->validateForm($passwordLost); + + $event = new LostPasswordEvent($form->get('email')->getData()); + + $eventDispatcher->dispatch($event, TheliaEvents::LOST_PASSWORD); + + return $this->generateSuccessRedirect($passwordLost); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occurred: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } + + if ($message !== false) { + Tlog::getInstance()->error( + sprintf( + 'Error during customer creation process : %s. Exception was %s', + $message, + $e->getMessage() + ) + ); + } + } else { + $message = $this->getTranslator()->trans( + "You're currently logged in. Please log out before requesting a new password.", + [], + Front::MESSAGE_DOMAIN + ); + } + + $passwordLost->setErrorMessage($message); + + $this->getParserContext() + ->addForm($passwordLost) + ->setGeneralError($message) + ; + + // Redirect to error URL if defined + if ($passwordLost->hasErrorUrl()) { + return $this->generateErrorRedirect($passwordLost); + } + } + + public function newPasswordSentAction(): void + { + $this->getParser()->assign('password_sent', true); + } + + /** + * Create a new customer. + * On success, redirect to success_url if exists, otherwise, display the same view again. + */ + public function createAction(EventDispatcherInterface $eventDispatcher) + { + if (!$this->getSecurityContext()->hasCustomerUser()) { + $customerCreation = $this->createForm(FrontForm::CUSTOMER_CREATE); + + try { + $form = $this->validateForm($customerCreation, 'post'); + + $customerCreateEvent = $this->createEventInstance($form->getData()); + + $eventDispatcher->dispatch($customerCreateEvent, TheliaEvents::CUSTOMER_CREATEACCOUNT); + + $newCustomer = $customerCreateEvent->getCustomer(); + + // Newsletter + if (true === $form->get('newsletter')->getData()) { + $newsletterEmail = $newCustomer->getEmail(); + $nlEvent = new NewsletterEvent( + $newsletterEmail, + $this->getRequest()->getSession()->getLang()->getLocale() + ); + $nlEvent->setFirstname($newCustomer->getFirstname()); + $nlEvent->setLastname($newCustomer->getLastname()); + + // Security : Check if this new Email address already exist + if (null !== $newsletter = NewsletterQuery::create()->findOneByEmail($newsletterEmail)) { + $nlEvent->setId($newsletter->getId()); + $eventDispatcher->dispatch($nlEvent, TheliaEvents::NEWSLETTER_UPDATE); + } else { + $eventDispatcher->dispatch($nlEvent, TheliaEvents::NEWSLETTER_SUBSCRIBE); + } + } + + if (ConfigQuery::isCustomerEmailConfirmationEnable() && !$newCustomer->getEnable()) { + $response = $this->generateRedirectFromRoute('customer.login.view'); + } else { + $this->processLogin($eventDispatcher, $customerCreateEvent->getCustomer()); + + $cart = $this->getSession()->getSessionCart($eventDispatcher); + if ($cart->getCartItems()->count() > 0) { + $response = $this->generateRedirectFromRoute('cart.view'); + } else { + $response = $this->generateSuccessRedirect($customerCreation); + } + } + + return $response; + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } + + Tlog::getInstance()->error( + sprintf( + 'Error during customer creation process : %s. Exception was %s', + $message, + $e->getMessage() + ) + ); + + $customerCreation->setErrorMessage($message); + + $this->getParserContext() + ->addForm($customerCreation) + ->setGeneralError($message) + ; + + // Redirect to error URL if defined + if ($customerCreation->hasErrorUrl()) { + return $this->generateErrorRedirect($customerCreation); + } + } + } + + /** + * Prepare customer data update. + */ + public function viewAction(): void + { + $this->checkAuth(); + + /** @var Customer $customer */ + $customer = $this->getSecurityContext()->getCustomerUser(); + $newsletter = NewsletterQuery::create()->findOneByEmail($customer->getEmail()); + $data = [ + 'id' => $customer->getId(), + 'title' => $customer->getTitleId(), + 'firstname' => $customer->getFirstName(), + 'lastname' => $customer->getLastName(), + 'email' => $customer->getEmail(), + 'email_confirm' => $customer->getEmail(), + 'lang_id' => $customer->getLangId(), + 'newsletter' => $newsletter instanceof Newsletter ? !$newsletter->getUnsubscribed() : false, + ]; + + $customerProfileUpdateForm = $this->createForm(FrontForm::CUSTOMER_PROFILE_UPDATE, FormType::class, $data); + + // Pass it to the parser + $this->getParserContext()->addForm($customerProfileUpdateForm); + } + + public function updatePasswordAction(EventDispatcherInterface $eventDispatcher) + { + if ($this->getSecurityContext()->hasCustomerUser()) { + $customerPasswordUpdateForm = $this->createForm(FrontForm::CUSTOMER_PASSWORD_UPDATE); + + try { + /** @var Customer $customer */ + $customer = $this->getSecurityContext()->getCustomerUser(); + + $form = $this->validateForm($customerPasswordUpdateForm, 'post'); + + $customerChangeEvent = $this->createEventInstance($form->getData()); + $customerChangeEvent->setCustomer($customer); + $eventDispatcher->dispatch($customerChangeEvent, TheliaEvents::CUSTOMER_UPDATEPROFILE); + + return $this->generateSuccessRedirect($customerPasswordUpdateForm); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } + + Tlog::getInstance()->error( + sprintf( + 'Error during customer password modification process : %s.', + $message + ) + ); + + $customerPasswordUpdateForm->setErrorMessage($message); + + $this->getParserContext() + ->addForm($customerPasswordUpdateForm) + ->setGeneralError($message) + ; + + // Redirect to error URL if defined + if ($customerPasswordUpdateForm->hasErrorUrl()) { + return $this->generateErrorRedirect($customerPasswordUpdateForm); + } + } + } + + public function updateAction(EventDispatcherInterface $eventDispatcher) + { + if ($this->getSecurityContext()->hasCustomerUser()) { + $customerProfileUpdateForm = $this->createForm(FrontForm::CUSTOMER_PROFILE_UPDATE); + + try { + /** @var Customer $customer */ + $customer = $this->getSecurityContext()->getCustomerUser(); + $newsletterOldEmail = $customer->getEmail(); + + $form = $this->validateForm($customerProfileUpdateForm, 'post'); + + $customerChangeEvent = $this->createEventInstance($form->getData()); + $customerChangeEvent->setCustomer($customer); + + $customerChangeEvent->setEmailUpdateAllowed( + ((int) ConfigQuery::read('customer_change_email', 0)) ? true : false + ); + + $eventDispatcher->dispatch($customerChangeEvent, TheliaEvents::CUSTOMER_UPDATEPROFILE); + + $updatedCustomer = $customerChangeEvent->getCustomer(); + + // Newsletter + if (true === $form->get('newsletter')->getData()) { + $nlEvent = new NewsletterEvent( + $updatedCustomer->getEmail(), + $this->getRequest()->getSession()->getLang()->getLocale() + ); + $nlEvent->setFirstname($updatedCustomer->getFirstname()); + $nlEvent->setLastname($updatedCustomer->getLastname()); + + if (null !== $newsletter = NewsletterQuery::create()->findOneByEmail($newsletterOldEmail)) { + $nlEvent->setId($newsletter->getId()); + $eventDispatcher->dispatch($nlEvent, TheliaEvents::NEWSLETTER_UPDATE); + } else { + $eventDispatcher->dispatch($nlEvent, TheliaEvents::NEWSLETTER_SUBSCRIBE); + } + } else { + if (null !== $newsletter = NewsletterQuery::create()->findOneByEmail($newsletterOldEmail)) { + $nlEvent = new NewsletterEvent( + $updatedCustomer->getEmail(), + $this->getRequest()->getSession()->getLang()->getLocale() + ); + $nlEvent->setId($newsletter->getId()); + $eventDispatcher->dispatch($nlEvent, TheliaEvents::NEWSLETTER_UNSUBSCRIBE); + } + } + + $this->processLogin($eventDispatcher, $updatedCustomer); + + return $this->generateSuccessRedirect($customerProfileUpdateForm); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + [ + '%s' => $e->getMessage(), + ], + Front::MESSAGE_DOMAIN + ); + } + + Tlog::getInstance()->error(sprintf('Error during customer modification process : %s.', $message)); + + $customerProfileUpdateForm->setErrorMessage($message); + + $this->getParserContext() + ->addForm($customerProfileUpdateForm) + ->setGeneralError($message) + ; + + // Redirect to error URL if defined + if ($customerProfileUpdateForm->hasErrorUrl()) { + return $this->generateErrorRedirect($customerProfileUpdateForm); + } + } + } + + /** + * Perform user login. On a successful login, the user is redirected to the URL + * found in the success_url form parameter, or / if none was found. + * + * If login is not successfull, the same view is displayed again. + */ + public function loginAction(EventDispatcherInterface $eventDispatcher) + { + if (!$this->getSecurityContext()->hasCustomerUser()) { + $request = $this->getRequest(); + $customerLoginForm = $this->createForm(CustomerLogin::class); + + try { + $form = $this->validateForm($customerLoginForm, 'post'); + + // If User is a new customer + if ($form->get('account')->getData() == 0 && $form->get('email')->getErrors()->count() == 0) { + return $this->generateRedirectFromRoute( + 'customer.create.process', + ['email' => $form->get('email')->getData()] + ); + } + try { + $authenticator = new CustomerUsernamePasswordFormAuthenticator($request, $customerLoginForm); + + /** @var Customer $customer */ + $customer = $authenticator->getAuthentifiedUser(); + + $this->processLogin($eventDispatcher, $customer); + + if ((int) $form->get('remember_me')->getData() > 0) { + // If a remember me field if present and set in the form, create + // the cookie thant store "remember me" information + $this->createRememberMeCookie( + $customer, + $this->getRememberMeCookieName(), + $this->getRememberMeCookieExpiration() + ); + } + + return $this->generateSuccessRedirect($customerLoginForm); + } catch (UsernameNotFoundException $e) { + $message = $this->getTranslator()->trans( + 'Wrong email or password. Please try again', + [], + Front::MESSAGE_DOMAIN + ); + } catch (WrongPasswordException $e) { + $message = $this->getTranslator()->trans( + 'Wrong email or password. Please try again', + [], + Front::MESSAGE_DOMAIN + ); + } catch (CustomerNotConfirmedException $e) { + if ($e->getUser() !== null) { + // Send the confirmation email again + $eventDispatcher->dispatch( + new CustomerEvent($e->getUser()), + TheliaEvents::SEND_ACCOUNT_CONFIRMATION_EMAIL + ); + } + $message = $this->getTranslator()->trans( + 'Your account is not yet confirmed. A confirmation email has been sent to your email address, please check your mailbox', + [], + Front::MESSAGE_DOMAIN + ); + } catch (AuthenticationException $e) { + $message = $this->getTranslator()->trans( + 'Wrong email or password. Please try again', + [], + Front::MESSAGE_DOMAIN + ); + } + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } + + Tlog::getInstance()->error( + sprintf( + 'Error during customer login process : %s. Exception was %s', + $message, + $e->getMessage() + ) + ); + + $customerLoginForm->setErrorMessage($message); + + $this->getParserContext()->addForm($customerLoginForm); + + if ($customerLoginForm->hasErrorUrl()) { + return $this->generateErrorRedirect($customerLoginForm); + } + } + } + + /** + * Perform customer logout. + */ + public function logoutAction(EventDispatcherInterface $eventDispatcher) + { + if ($this->getSecurityContext()->hasCustomerUser()) { + $eventDispatcher->dispatch(new DefaultActionEvent(), TheliaEvents::CUSTOMER_LOGOUT); + } + + $this->clearRememberMeCookie($this->getRememberMeCookieName()); + + // Redirect to home page + return $this->generateRedirect(URL::getInstance()->getIndexPage()); + } + + /** + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function confirmCustomerAction($token) + { + /** @var Customer $customer */ + if (null === $customer = CustomerQuery::create()->findOneByConfirmationToken($token)) { + throw new NotFoundHttpException(); + } + + $customer + ->setEnable(true) + ->save() + ; + + // Clear form error context + + return $this->generateRedirectFromRoute('customer.login.view', ['validation_done' => 1]); + } + + /** + * Dispatch event for customer login action. + */ + protected function processLogin(EventDispatcherInterface $eventDispatcher, Customer $customer): void + { + $eventDispatcher->dispatch(new CustomerLoginEvent($customer), TheliaEvents::CUSTOMER_LOGIN); + } + + /** + * @return \Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent + */ + private function createEventInstance($data) + { + $customerCreateEvent = new CustomerCreateOrUpdateEvent( + $data['title'] ?? null, + $data['firstname'] ?? null, + $data['lastname'] ?? null, + $data['address1'] ?? null, + $data['address2'] ?? null, + $data['address3'] ?? null, + $data['phone'] ?? null, + $data['cellphone'] ?? null, + $data['zipcode'] ?? null, + $data['city'] ?? null, + $data['country'] ?? null, + $data['email'] ?? null, + $data['password'] ?? null, + $data['lang_id'] ?? $this->getSession()->getLang()->getId(), + $data['reseller'] ?? null, + $data['sponsor'] ?? null, + $data['discount'] ?? null, + $data['company'] ?? null, + null, + $data['state'] ?? null + ); + + return $customerCreateEvent; + } + + protected function getRememberMeCookieName() + { + return ConfigQuery::read('customer_remember_me_cookie_name', 'crmcn'); + } + + protected function getRememberMeCookieExpiration() + { + return ConfigQuery::read('customer_remember_me_cookie_expiration', 2592000 /* 1 month */); + } +} diff --git a/domokits/local/modules/Front/Controller/FeedController.php b/domokits/local/modules/Front/Controller/FeedController.php new file mode 100644 index 0000000..86e48b2 --- /dev/null +++ b/domokits/local/modules/Front/Controller/FeedController.php @@ -0,0 +1,196 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Response; +use Thelia\Model\BrandQuery; +use Thelia\Model\CategoryQuery; +use Thelia\Model\ConfigQuery; +use Thelia\Model\FolderQuery; +use Thelia\Model\Lang; +use Thelia\Model\LangQuery; + +/** + * Controller uses to generate RSS Feeds. + * + * A default cache of 2 hours is used to avoid attack. You can flush cache if you have `ADMIN` role and pass flush=1 in + * query string parameter. + * + * @author Julien Chanséaume + */ +class FeedController extends BaseFrontController +{ + /** + * Folder name for feeds cache. + */ + public const FEED_CACHE_DIR = 'feeds'; + + /** + * Key prefix for feed cache. + */ + public const FEED_CACHE_KEY = 'feed'; + + /** + * render the RSS feed. + * + * @param $context string The context of the feed : catalog, content. default: catalog + * @param $lang string The lang of the feed : fr_FR, en_US, ... default: default language of the site + * @param $id string The id of the parent element. The id of the main parent category for catalog context. + * The id of the content folder for content context + * + * @throws \RuntimeException + * + * @return Response + */ + public function generateAction($context, $lang, $id) + { + /** @var Request $request */ + $request = $this->getRequest(); + + // context + if ('' === $context) { + $context = 'catalog'; + } elseif (!\in_array($context, ['catalog', 'content', 'brand'])) { + $this->pageNotFound(); + } + + // the locale : fr_FR, en_US, + if ('' !== $lang) { + if (!$this->checkLang($lang)) { + $this->pageNotFound(); + } + } else { + try { + $lang = Lang::getDefaultLanguage(); + $lang = $lang->getLocale(); + } catch (\RuntimeException $ex) { + // @todo generate error page + throw new \RuntimeException('No default language is defined. Please define one.'); + } + } + if (null === $lang = LangQuery::create()->findOneByLocale($lang)) { + $this->pageNotFound(); + } + $lang = $lang->getId(); + + // check if element exists and is visible + if ('' !== $id) { + if (false === $this->checkId($context, $id)) { + $this->pageNotFound(); + } + } + + $flush = $request->query->get('flush', ''); + + /** @var AdapterInterface $cacheAdapter */ + $cacheAdapter = $this->container->get('thelia.cache'); + + $cacheKey = self::FEED_CACHE_KEY.$lang.$context; + + $cacheItem = $cacheAdapter->getItem($cacheKey); + + if (!$cacheItem->isHit() || $flush) { + $cacheExpire = (int) (ConfigQuery::read('feed_ttl', '7200')) ?: 7200; + + // render the view + $cacheContent = $this->renderRaw( + 'feed', + [ + '_context_' => $context, + '_lang_' => $lang, + '_id_' => $id, + ] + ); + + $cacheItem->expiresAfter($cacheExpire); + $cacheItem->set($cacheContent); + $cacheAdapter->save($cacheItem); + } + + $response = new Response(); + $response->setContent($cacheItem->get()); + $response->headers->set('Content-Type', 'application/rss+xml'); + + return $response; + } + + /** + * get the cache directory for feeds. + * + * @return mixed|string + */ + protected function getCacheDir() + { + $cacheDir = $this->container->getParameter('kernel.cache_dir'); + $cacheDir = rtrim($cacheDir, '/'); + $cacheDir .= '/'.self::FEED_CACHE_DIR.'/'; + + return $cacheDir; + } + + /** + * Check if current user has ADMIN role. + * + * @return bool + */ + protected function checkAdmin() + { + return $this->getSecurityContext()->hasAdminUser(); + } + + /** + * Check if a lang is used. + * + * @param $lang string The lang code. e.g.: fr + * + * @return bool true if the language is used, otherwise false + */ + private function checkLang($lang) + { + // load locals + $lang = LangQuery::create() + ->findOneByLocale($lang); + + return null !== $lang; + } + + /** + * Check if the element exists and is visible. + * + * @param $context string catalog or content + * @param $id string id of the element + * + * @return bool + */ + private function checkId($context, $id) + { + $ret = false; + if (is_numeric($id)) { + if ('catalog' === $context) { + $cat = CategoryQuery::create()->findPk($id); + $ret = (null !== $cat && $cat->getVisible()); + } elseif ('brand' === $context) { + $brand = BrandQuery::create()->findPk($id); + $ret = (null !== $brand && $brand->getVisible()); + } else { + $folder = FolderQuery::create()->findPk($id); + $ret = (null !== $folder && $folder->getVisible()); + } + } + + return $ret; + } +} diff --git a/domokits/local/modules/Front/Controller/NewsletterController.php b/domokits/local/modules/Front/Controller/NewsletterController.php new file mode 100644 index 0000000..1d998e8 --- /dev/null +++ b/domokits/local/modules/Front/Controller/NewsletterController.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Newsletter\NewsletterEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Form\Definition\FrontForm; +use Thelia\Log\Tlog; +use Thelia\Model\Customer; +use Thelia\Model\NewsletterQuery; + +/** + * Class NewsletterController. + * + * @author Manuel Raynaud , Franck Allimant + */ +class NewsletterController extends BaseFrontController +{ + /** + * @since 2.3.0-alpha2 + */ + public function unsubscribeAction(EventDispatcherInterface $eventDispatcher) + { + $errorMessage = false; + + $newsletterForm = $this->createForm(FrontForm::NEWSLETTER_UNSUBSCRIBE); + + try { + $form = $this->validateForm($newsletterForm); + + $email = $form->get('email')->getData(); + + if (null !== $newsletter = NewsletterQuery::create()->findOneByEmail($email)) { + $event = new NewsletterEvent( + $email, + $this->getRequest()->getSession()->getLang()->getLocale() + ); + + $event->setId($newsletter->getId()); + + $eventDispatcher->dispatch($event, TheliaEvents::NEWSLETTER_UNSUBSCRIBE); + + // If a success URL is defined in the form, redirect to it, otherwise use the defaut view + if ($newsletterForm->hasSuccessUrl() && !$this->getRequest()->isXmlHttpRequest()) { + return $this->generateSuccessRedirect($newsletterForm); + } + } + } catch (\Exception $e) { + $errorMessage = $e->getMessage(); + + Tlog::getInstance()->error(sprintf('Error during newsletter unsubscription : %s', $errorMessage)); + + $newsletterForm->setErrorMessage($errorMessage); + } + + // If Ajax Request + if ($this->getRequest()->isXmlHttpRequest()) { + return new JsonResponse([ + 'success' => ($errorMessage) ? false : true, + 'message' => ($errorMessage) ? $errorMessage : $this->getTranslator()->trans( + 'Your subscription to our newsletter has been canceled.', + [], + Front::MESSAGE_DOMAIN + ), + ], ($errorMessage) ? 500 : 200); + } + + $this->getParserContext() + ->setGeneralError($errorMessage) + ->addForm($newsletterForm); + + // If an error URL is defined in the form, redirect to it, otherwise use the defaut view + if ($errorMessage && $newsletterForm->hasErrorUrl()) { + return $this->generateErrorRedirect($newsletterForm); + } + } + + public function subscribeAction(EventDispatcherInterface $eventDispatcher) + { + $errorMessage = false; + + $newsletterForm = $this->createForm(FrontForm::NEWSLETTER); + + try { + $form = $this->validateForm($newsletterForm); + + $event = new NewsletterEvent( + $form->get('email')->getData(), + $this->getRequest()->getSession()->getLang()->getLocale() + ); + + /** @var Customer $customer */ + if (null !== $customer = $this->getSecurityContext()->getCustomerUser()) { + $event + ->setFirstname($customer->getFirstname()) + ->setLastname($customer->getLastname()) + ; + } else { + $event + ->setFirstname($form->get('firstname')->getData()) + ->setLastname($form->get('lastname')->getData()) + ; + } + + $eventDispatcher->dispatch($event, TheliaEvents::NEWSLETTER_SUBSCRIBE); + + // If a success URL is defined in the form, redirect to it, otherwise use the defaut view + if ($newsletterForm->hasSuccessUrl() && !$this->getRequest()->isXmlHttpRequest()) { + return $this->generateSuccessRedirect($newsletterForm); + } + } catch (\Exception $e) { + $errorMessage = $e->getMessage(); + + Tlog::getInstance()->error(sprintf('Error during newsletter subscription : %s', $errorMessage)); + + $newsletterForm->setErrorMessage($errorMessage); + } + + // If Ajax Request + if ($this->getRequest()->isXmlHttpRequest()) { + return new JsonResponse([ + 'success' => ($errorMessage) ? false : true, + 'message' => ($errorMessage) ? $errorMessage : $this->getTranslator()->trans( + "Thanks for signing up! We'll keep you posted whenever we have any new updates.", + [], + Front::MESSAGE_DOMAIN + ), + ], ($errorMessage) ? 500 : 200); + } + + $this->getParserContext() + ->setGeneralError($errorMessage) + ->addForm($newsletterForm); + + // If an error URL is defined in the form, redirect to it, otherwise use the defaut view + if ($errorMessage && $newsletterForm->hasErrorUrl()) { + return $this->generateErrorRedirect($newsletterForm); + } + } +} diff --git a/domokits/local/modules/Front/Controller/OrderController.php b/domokits/local/modules/Front/Controller/OrderController.php new file mode 100644 index 0000000..35967bd --- /dev/null +++ b/domokits/local/modules/Front/Controller/OrderController.php @@ -0,0 +1,591 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Front\Front; +use Propel\Runtime\ActiveQuery\Criteria; +use Propel\Runtime\Exception\PropelException; +use Symfony\Component\HttpFoundation\Response as BaseResponse; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\Product\VirtualProductOrderDownloadResponseEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Exception\TheliaProcessException; +use Thelia\Form\Definition\FrontForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\Address; +use Thelia\Model\AddressQuery; +use Thelia\Model\AreaDeliveryModuleQuery; +use Thelia\Model\ConfigQuery; +use Thelia\Model\ModuleQuery; +use Thelia\Model\Order; +use Thelia\Model\OrderProductQuery; +use Thelia\Model\OrderQuery; +use Thelia\Module\AbstractDeliveryModule; +use Thelia\Module\Exception\DeliveryException; + +/** + * Class OrderController. + * + * @author Etienne Roudeix + */ +class OrderController extends BaseFrontController +{ + /** + * Check if the cart contains only virtual products. + */ + public function deliverView(EventDispatcherInterface $eventDispatcher) + { + $this->checkAuth(); + $this->checkCartNotEmpty($eventDispatcher); + + // check if the cart contains only virtual products + $cart = $this->getSession()->getSessionCart($eventDispatcher); + + $deliveryAddress = $this->getCustomerAddress(); + + if ($cart->isVirtual()) { + if (null !== $deliveryAddress) { + $deliveryModule = ModuleQuery::create()->retrieveVirtualProductDelivery($this->container); + + if (false === $deliveryModule) { + Tlog::getInstance()->error( + $this->getTranslator()->trans( + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated', + [], + Front::MESSAGE_DOMAIN + ) + ); + } elseif (\count($deliveryModule) == 1) { + return $this->registerVirtualProductDelivery($eventDispatcher, $deliveryModule[0], $deliveryAddress); + } + } + } + + return $this->render( + 'order-delivery', + [ + 'delivery_address_id' => (null !== $deliveryAddress) ? $deliveryAddress->getId() : null, + ] + ); + } + + /** + * @param AbstractDeliveryModule $moduleInstance + * @param Address $deliveryAddress + * + * @return \Symfony\Component\HttpFoundation\Response + */ + private function registerVirtualProductDelivery(EventDispatcherInterface $eventDispatcher, $moduleInstance, $deliveryAddress) + { + /* get postage amount */ + $deliveryModule = $moduleInstance->getModuleModel(); + $cart = $this->getSession()->getSessionCart($eventDispatcher); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $eventDispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + $postage = $deliveryPostageEvent->getPostage(); + + $orderEvent = $this->getOrderEvent(); + $orderEvent->setDeliveryAddress($deliveryAddress->getId()); + $orderEvent->setDeliveryModule($deliveryModule->getId()); + $orderEvent->setPostage($postage->getAmount()); + $orderEvent->setPostageTax($postage->getAmountTax()); + $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_ADDRESS); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + + return $this->generateRedirectFromRoute('order.invoice'); + } + + /** + * set delivery address + * set delivery module. + */ + public function deliver(EventDispatcherInterface $eventDispatcher) + { + $this->checkAuth(); + $this->checkCartNotEmpty($eventDispatcher); + + $message = false; + + $orderDelivery = $this->createForm(FrontForm::ORDER_DELIVER); + + try { + $form = $this->validateForm($orderDelivery, 'post'); + + $deliveryAddressId = $form->get('delivery-address')->getData(); + $deliveryModuleId = $form->get('delivery-module')->getData(); + $deliveryAddress = AddressQuery::create()->findPk($deliveryAddressId); + $deliveryModule = ModuleQuery::create()->findPk($deliveryModuleId); + + /* check that the delivery address belongs to the current customer */ + if ($deliveryAddress->getCustomerId() !== $this->getSecurityContext()->getCustomerUser()->getId()) { + throw new \Exception( + $this->getTranslator()->trans( + 'Delivery address does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + + /* check that the delivery module fetches the delivery address area */ + if (null === AreaDeliveryModuleQuery::create()->findByCountryAndModule( + $deliveryAddress->getCountry(), + $deliveryModule, + $deliveryAddress->getState() + )) { + throw new \Exception( + $this->getTranslator()->trans( + 'Delivery module cannot be use with selected delivery address', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + + /* get postage amount */ + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + + $cart = $this->getSession()->getSessionCart($eventDispatcher); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $eventDispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + if (!$deliveryPostageEvent->isValidModule() || null === $deliveryPostageEvent->getPostage()) { + throw new DeliveryException( + $this->getTranslator()->trans('The delivery module is not valid.', [], Front::MESSAGE_DOMAIN) + ); + } + + $postage = $deliveryPostageEvent->getPostage(); + + $orderEvent = $this->getOrderEvent(); + $orderEvent->setDeliveryAddress($deliveryAddressId); + $orderEvent->setDeliveryModule($deliveryModuleId); + $orderEvent->setPostage($postage->getAmount()); + $orderEvent->setPostageTax($postage->getAmountTax()); + $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_ADDRESS); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + + return $this->generateRedirectFromRoute('order.invoice'); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } catch (PropelException $e) { + $this->getParserContext()->setGeneralError($e->getMessage()); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } + + if ($message !== false) { + Tlog::getInstance()->error( + sprintf('Error during order delivery process : %s. Exception was %s', $message, $e->getMessage()) + ); + + $orderDelivery->setErrorMessage($message); + + $this->getParserContext() + ->addForm($orderDelivery) + ->setGeneralError($message) + ; + } + } + + /** + * set invoice address + * set payment module. + */ + public function invoice(EventDispatcherInterface $eventDispatcher) + { + $this->checkAuth(); + $this->checkCartNotEmpty($eventDispatcher); + $this->checkValidDelivery(); + + $message = false; + + $orderPayment = $this->createForm(FrontForm::ORDER_PAYMENT); + + try { + $form = $this->validateForm($orderPayment, 'post'); + + $invoiceAddressId = $form->get('invoice-address')->getData(); + $paymentModuleId = $form->get('payment-module')->getData(); + + /* check that the invoice address belongs to the current customer */ + $invoiceAddress = AddressQuery::create()->findPk($invoiceAddressId); + if ($invoiceAddress->getCustomerId() !== $this->getSecurityContext()->getCustomerUser()->getId()) { + throw new \Exception( + $this->getTranslator()->trans( + 'Invoice address does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + + $orderEvent = $this->getOrderEvent(); + $orderEvent->setInvoiceAddress($invoiceAddressId); + $orderEvent->setPaymentModule($paymentModuleId); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_INVOICE_ADDRESS); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_PAYMENT_MODULE); + + return $this->generateRedirectFromRoute('order.payment.process'); + } catch (FormValidationException $e) { + $message = $this->getTranslator()->trans( + 'Please check your input: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } catch (PropelException $e) { + $this->getParserContext()->setGeneralError($e->getMessage()); + } catch (\Exception $e) { + $message = $this->getTranslator()->trans( + 'Sorry, an error occured: %s', + ['%s' => $e->getMessage()], + Front::MESSAGE_DOMAIN + ); + } + + if ($message !== false) { + Tlog::getInstance()->error( + sprintf('Error during order payment process : %s. Exception was %s', $message, $e->getMessage()) + ); + + $orderPayment->setErrorMessage($message); + + $this->getParserContext() + ->addForm($orderPayment) + ->setGeneralError($message) + ; + } + + return $this->generateErrorRedirect($orderPayment); + } + + public function pay(EventDispatcherInterface $eventDispatcher) + { + /* check customer */ + $this->checkAuth(); + + /* check cart count */ + $this->checkCartNotEmpty($eventDispatcher); + + /* check stock not empty */ + if (true === ConfigQuery::checkAvailableStock()) { + if (null !== $response = $this->checkStockNotEmpty($eventDispatcher)) { + return $response; + } + } + + /* check delivery address and module */ + $this->checkValidDelivery(); + + /* check invoice address and payment module */ + $this->checkValidInvoice(); + + $orderEvent = $this->getOrderEvent(); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_PAY); + + $placedOrder = $orderEvent->getPlacedOrder(); + + if (null !== $placedOrder && null !== $placedOrder->getId()) { + /* order has been placed */ + if ($orderEvent->hasResponse()) { + return $orderEvent->getResponse(); + } + + return $this->generateRedirectFromRoute( + 'order.placed', + [], + ['order_id' => $orderEvent->getPlacedOrder()->getId()] + ); + } + + /* order has not been placed */ + return $this->generateRedirectFromRoute('cart.view'); + } + + public function orderPlaced(EventDispatcherInterface $eventDispatcher, $order_id): void + { + /* check if the placed order matched the customer */ + $placedOrder = OrderQuery::create()->findPk( + $this->getRequest()->attributes->get('order_id') + ); + + if (null === $placedOrder) { + throw new TheliaProcessException( + $this->getTranslator()->trans( + 'No placed order', + [], + Front::MESSAGE_DOMAIN + ), + TheliaProcessException::NO_PLACED_ORDER, + $placedOrder + ); + } + + $customer = $this->getSecurityContext()->getCustomerUser(); + + if (null === $customer || $placedOrder->getCustomerId() !== $customer->getId()) { + throw new TheliaProcessException( + $this->getTranslator()->trans( + 'Received placed order id does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ), + TheliaProcessException::PLACED_ORDER_ID_BAD_CURRENT_CUSTOMER, + $placedOrder + ); + } + + $eventDispatcher->dispatch($this->getOrderEvent(), TheliaEvents::ORDER_CART_CLEAR); + + $this->getParserContext()->set('placed_order_id', $placedOrder->getId()); + } + + public function orderFailed($order_id, $message): void + { + if (empty($order_id)) { + // Fallback to request parameter if the method parameter is empty. + $order_id = $this->getRequest()->get('order_id'); + } + + $failedOrder = OrderQuery::create()->findPk($order_id); + + if (null !== $failedOrder) { + $customer = $this->getSecurityContext()->getCustomerUser(); + + if (null === $customer || $failedOrder->getCustomerId() !== $customer->getId()) { + throw new TheliaProcessException( + $this->getTranslator()->trans( + 'Received failed order id does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ), + TheliaProcessException::PLACED_ORDER_ID_BAD_CURRENT_CUSTOMER, + $failedOrder + ); + } + } else { + Tlog::getInstance()->warning("Failed order ID '$order_id' not found."); + } + + $this->getParserContext() + ->set('failed_order_id', $order_id) + ->set('failed_order_message', $message) + ; + } + + protected function getOrderEvent() + { + $order = $this->getOrder($this->getRequest()); + + return new OrderEvent($order); + } + + public function getOrder(Request $request) + { + $session = $request->getSession(); + + if (null !== $order = $session->getOrder()) { + return $order; + } + + $order = new Order(); + + $session->setOrder($order); + + return $order; + } + + public function viewAction($order_id) + { + $this->checkOrderCustomer($order_id); + + return $this->render('account-order', ['order_id' => $order_id]); + } + + public function generateInvoicePdf(EventDispatcherInterface $eventDispatcher, $order_id) + { + $this->checkOrderCustomer($order_id); + + return $this->generateOrderPdf($eventDispatcher, $order_id, ConfigQuery::read('pdf_invoice_file', 'invoice')); + } + + public function generateDeliveryPdf(EventDispatcherInterface $eventDispatcher, $order_id) + { + $this->checkOrderCustomer($order_id); + + return $this->generateOrderPdf($eventDispatcher, $order_id, ConfigQuery::read('pdf_delivery_file', 'delivery')); + } + + public function downloadVirtualProduct(EventDispatcherInterface $eventDispatcher, $order_product_id) + { + if (null !== $orderProduct = OrderProductQuery::create()->findPk($order_product_id)) { + $order = $orderProduct->getOrder(); + + if ($order->isPaid(false)) { + // check customer + $this->checkOrderCustomer($order->getId()); + + $virtualProductEvent = new VirtualProductOrderDownloadResponseEvent($orderProduct); + $eventDispatcher->dispatch( + $virtualProductEvent, + TheliaEvents::VIRTUAL_PRODUCT_ORDER_DOWNLOAD_RESPONSE + ); + + $response = $virtualProductEvent->getResponse(); + + if (!$response instanceof BaseResponse) { + throw new \RuntimeException('A Response must be added in the event TheliaEvents::VIRTUAL_PRODUCT_ORDER_DOWNLOAD_RESPONSE'); + } + + return $response; + } + } + + throw new AccessDeniedHttpException(); + } + + private function checkOrderCustomer($order_id): void + { + $this->checkAuth(); + + $order = OrderQuery::create()->findPk($order_id); + $valid = true; + if ($order) { + $customerOrder = $order->getCustomer(); + $customer = $this->getSecurityContext()->getCustomerUser(); + + if ($customerOrder->getId() != $customer->getId()) { + $valid = false; + } + } else { + $valid = false; + } + + if (false === $valid) { + throw new AccessDeniedHttpException(); + } + } + + public function getDeliveryModuleListAjaxAction() + { + $this->checkXmlHttpRequest(); + + // Change the delivery address if customer has changed it + $address = null; + $session = $this->getSession(); + $addressId = $this->getRequest()->get('address_id', null); + if (null !== $addressId && $addressId !== $session->getOrder()->getChoosenDeliveryAddress()) { + $address = AddressQuery::create()->findPk($addressId); + if (null !== $address && $address->getCustomerId() === $session->getCustomerUser()->getId()) { + $session->getOrder()->setChoosenDeliveryAddress($addressId); + } + } + + $address = AddressQuery::create()->findPk($session->getOrder()->getChoosenDeliveryAddress()); + + $countryId = $address->getCountryId(); + $stateId = $address->getStateId(); + + $args = [ + 'country' => $countryId, + 'state' => $stateId, + 'address' => $session->getOrder()->getChoosenDeliveryAddress(), + ]; + + return $this->render('ajax/order-delivery-module-list', $args); + } + + /** + * Redirect to cart view if at least one non product is out of stock. + * + * @return BaseResponse|null + */ + private function checkStockNotEmpty(EventDispatcherInterface $eventDispatcher) + { + $cart = $this->getSession()->getSessionCart($eventDispatcher); + + $cartItems = $cart->getCartItems(); + + foreach ($cartItems as $cartItem) { + $pse = $cartItem->getProductSaleElements(); + + $product = $cartItem->getProduct(); + + if ($pse->getQuantity() <= 0 && $product->getVirtual() !== 1) { + return $this->generateRedirectFromRoute('cart.view'); + } + } + + return null; + } + + /** + * Retrieve the chosen delivery address for a cart or the default customer address if not exists. + * + * @return Address|null + */ + protected function getCustomerAddress() + { + $deliveryAddress = null; + $addressId = $this->getSession()->getOrder()->getChoosenDeliveryAddress(); + if (null === $addressId) { + $customer = $this->getSecurityContext()->getCustomerUser(); + + $deliveryAddress = AddressQuery::create() + ->filterByCustomerId($customer->getId()) + ->orderByIsDefault(Criteria::DESC) + ->findOne(); + + if (null !== $deliveryAddress) { + $this->getSession()->getOrder()->setChoosenDeliveryAddress( + $deliveryAddress->getId() + ); + } + } else { + $deliveryAddress = AddressQuery::create()->findPk($addressId); + } + + return $deliveryAddress; + } +} diff --git a/domokits/local/modules/Front/Controller/SitemapController.php b/domokits/local/modules/Front/Controller/SitemapController.php new file mode 100644 index 0000000..5c18554 --- /dev/null +++ b/domokits/local/modules/Front/Controller/SitemapController.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front\Controller; + +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Response; +use Thelia\Model\ConfigQuery; +use Thelia\Model\LangQuery; + +/** + * Controller uses to generate sitemap.xml. + * + * A default cache of 2 hours is used to avoid attack. You can flush cache if you have `ADMIN` role and pass flush=1 in + * query string parameter. + * + * You can generate sitemap according to specific language and/or specific context (catalog/content). You have to + * use ```lang``` and ```context``` query string parameters to do so. If a language is not used in website or if the + * context is not supported the page not found is displayed. + * + * {url}/sitemap?lang=fr&context=catalog will generate a sitemap for catalog (categories and products) + * for french language. + * + * @author Julien Chanséaume + */ +class SitemapController extends BaseFrontController +{ + /** + * Folder name for sitemap cache. + */ + public const SITEMAP_CACHE_DIR = 'sitemap'; + + /** + * Key prefix for sitemap cache. + */ + public const SITEMAP_CACHE_KEY = 'sitemap'; + + /** + * @return Response + */ + public function generateAction() + { + /** @var Request $request */ + $request = $this->getRequest(); + + // the locale : fr, en, + $lang = $request->query->get('lang', ''); + if ('' !== $lang) { + if (!$this->checkLang($lang)) { + $this->pageNotFound(); + } + } + + // specific content : product, category, cms + $context = $request->query->get('context', ''); + if (!\in_array($context, ['', 'catalog', 'content'])) { + $this->pageNotFound(); + } + + $flush = $request->query->get('flush', ''); + + /** @var AdapterInterface $cacheAdapter */ + $cacheAdapter = $this->container->get('thelia.cache'); + + $cacheKey = self::SITEMAP_CACHE_KEY.$lang.$context; + + $cacheItem = $cacheAdapter->getItem($cacheKey); + + if (!$cacheItem->isHit() || $flush) { + $cacheExpire = (int) (ConfigQuery::read('sitemap_ttl', '7200')) ?: 7200; + + // Render the view. Compression causes problems and is deactivated. + $cacheContent = $this->getParser(null)->render( + 'sitemap.html', + [ + '_lang_' => $lang, + '_context_' => $context, + ], + false + ); + + $cacheItem->expiresAfter($cacheExpire); + $cacheItem->set($cacheContent); + $cacheAdapter->save($cacheItem); + } + + $response = new Response(); + $response->setContent($cacheItem->get()); + $response->headers->set('Content-Type', 'application/xml'); + + return $response; + } + + /** + * get the cache directory for sitemap. + * + * @return mixed|string + */ + protected function getCacheDir() + { + $cacheDir = $this->container->getParameter('kernel.cache_dir'); + $cacheDir = rtrim($cacheDir, '/'); + $cacheDir .= '/'.self::SITEMAP_CACHE_DIR.'/'; + + return $cacheDir; + } + + /** + * Check if current user has ADMIN role. + * + * @return bool + */ + protected function checkAdmin() + { + return $this->getSecurityContext()->hasAdminUser(); + } + + /** + * Check if a lang is used. + * + * @param $lang The lang code. e.g.: fr + * + * @return bool true if the language is used, otherwise false + */ + private function checkLang($lang) + { + // load locals + $lang = LangQuery::create() + ->findOneByCode($lang); + + return null !== $lang; + } +} diff --git a/domokits/local/modules/Front/Front.php b/domokits/local/modules/Front/Front.php new file mode 100644 index 0000000..f58c4f7 --- /dev/null +++ b/domokits/local/modules/Front/Front.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Front; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; + +class Front extends BaseModule +{ + public const MESSAGE_DOMAIN = 'front'; + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/Front/I18n/de_DE.php b/domokits/local/modules/Front/I18n/de_DE.php new file mode 100644 index 0000000..d32e2b4 --- /dev/null +++ b/domokits/local/modules/Front/I18n/de_DE.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Gutschein-Code darf nicht leer sein', + 'Delivery address does not belong to the current customer' => 'Lieferadresse gehört nicht zum aktuellen Kunden', + 'Delivery module cannot be use with selected delivery address' => 'Lieferung-Modul kann nicht mit ausgewählten Lieferadresse verwendet werden', + 'Error during address deletion process' => 'Fehler beim Löschen der Adresse', + 'Failed to add this article to your cart, please try again' => 'Der Artikel konnte nicht zum Warenkorb hinzugefügt werden, bitte versuchen Sie es erneut', + 'Invoice address does not belong to the current customer' => 'Rechnungsadresse gehört nicht zum aktuellen Kunden', + 'No placed order' => 'Keine Bestellungen', + 'Please check your coupon code: %message' => 'Bitte überprüfen Sie Ihren Gutschein-Code: %message', + 'Please check your input: %s' => 'Bitte überprüfen Sie Ihre Eingabe: %s', + 'Received failed order id does not belong to the current customer' => 'Empfangene Id einer fehlgeschlagenen Bestellung gehört nicht zum aktuellen Kunden', + 'Received placed order id does not belong to the current customer' => 'Empfangene Bestellungs-Id gehört nicht zum aktuellen Kunden', + 'Sorry, an error occured: %s' => 'Leider ist ein Fehler aufgetreten: %s', + 'Sorry, an error occurred: %message' => 'Leider ist ein Fehler aufgetreten: %message', + 'Sorry, an error occurred: %s' => 'Es tut uns Leid, aber ein Fehler ist aufgetreten: %s', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Vielen Dank für Ihre Anmeldung! Wir halten Ihnen auf dem Laufenden über neuen Updates.', + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated' => 'Um das virtuelle Produkt-Feature zu aktivieren, sollte das VirtualProductDelivery-Modul aktiviert werden', + 'Wrong email or password. Please try again' => 'E-Mail oder Passwort falsch. Bitte erneut versuchen', + 'You\'re currently logged in. Please log out before requesting a new password.' => 'Sie sind derzeit angemeldet. Bitte melden Sie sich ab, bevor Sie ein neues Passwort anfordern.', +]; diff --git a/domokits/local/modules/Front/I18n/en_US.php b/domokits/local/modules/Front/I18n/en_US.php new file mode 100644 index 0000000..086864d --- /dev/null +++ b/domokits/local/modules/Front/I18n/en_US.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Coupon code can\'t be empty', + 'Delivery address does not belong to the current customer' => 'Delivery address does not belong to the current customer', + 'Delivery module cannot be use with selected delivery address' => 'Delivery module cannot be use with selected delivery address', + 'Error during address deletion process' => 'Error during address deletion process', + 'Failed to add this article to your cart, please try again' => 'Failed to add this article to your cart, please try again', + 'Invoice address does not belong to the current customer' => 'Invoice address does not belong to the current customer', + 'No placed order' => 'No placed order', + 'Please check your coupon code: %message' => 'Please check your coupon code: %message', + 'Please check your input: %s' => 'Please check your input: %s', + 'Received failed order id does not belong to the current customer' => 'Received failed order id does not belong to the current customer', + 'Received placed order id does not belong to the current customer' => 'Received placed order id does not belong to the current customer', + 'Sorry, an error occured: %s' => 'Sorry, an error occured: %s', + 'Sorry, an error occurred: %message' => 'Sorry, an error occurred: %message', + 'Sorry, an error occurred: %s' => 'Sorry, an error occurred: %s', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.', + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated' => 'To enable the virtual product feature, the VirtualProductDelivery module should be activated', + 'Wrong email or password. Please try again' => 'Wrong email or password. Please try again', + 'You should sign in or register to use this coupon' => 'You should sign in or register to use this coupon', + 'You\'re currently logged in. Please log out before requesting a new password.' => 'You\'re currently logged in. Please log out before requesting a new password.', + 'Your account is not yet confirmed check out your mailbox' => 'Your account is not yet confirmed check out your mailbox', +]; diff --git a/domokits/local/modules/Front/I18n/fr_FR.php b/domokits/local/modules/Front/I18n/fr_FR.php new file mode 100644 index 0000000..45e3faa --- /dev/null +++ b/domokits/local/modules/Front/I18n/fr_FR.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Le code promo ne peut être vide', + 'Delivery address does not belong to the current customer' => 'L\'adresse de livraison n\'appartient pas au client en cours', + 'Delivery module cannot be use with selected delivery address' => 'Le module de livraison ne peut pas être utilisé avec cette adresse de livraison', + 'Error during address deletion process' => 'Désolé. Une erreur s\'est produite lors de la suppression de l\'adresse', + 'Failed to add this article to your cart, please try again' => 'Impossible d\'ajouter cet article à votre panier. Merci de ré-essayer.', + 'Invoice address does not belong to the current customer' => 'L\'adresse de facturation n\'appartient pas au client en cours', + 'No placed order' => 'Aucune commande passée', + 'Please check your coupon code: %message' => 'Merci de vérifier votre code promo : %message', + 'Please check your input: %s' => 'Merci de vérifier les informations indiquées : %s', + 'Received failed order id does not belong to the current customer' => 'L\'id de commande refusée n\'appartient pas au client en cours', + 'Received placed order id does not belong to the current customer' => 'L\'id de commande passée n\'appartient pas au client en cours', + 'Sorry, an error occured: %s' => 'Désolé. Une erreur s\'est produite : %s', + 'Sorry, an error occurred: %message' => 'Désolé. Une erreur s\'est produite : %message', + 'Sorry, an error occurred: %s' => 'Désolé, une erreur est survenue : %s', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Merci de votre inscription ! Nous vous tiendrons informé dès qu\'il y aura des nouveautés.', + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated' => 'Pour activer les produits virtuels, le module VirtualProductDelivery doit être activé', + 'Wrong email or password. Please try again' => 'Adresse email ou mot de passe incorrect. Merci de ré-essayer.', + 'You should sign in or register to use this coupon' => 'Vous devez vous connecter ou vous inscrire pour utiliser ce coupon', + 'You\'re currently logged in. Please log out before requesting a new password.' => 'Vous être actuellement connecté au site. Vous devez vous déconnecter pour demander un nouveau mot de passe.', +]; diff --git a/domokits/local/modules/Front/I18n/it_IT.php b/domokits/local/modules/Front/I18n/it_IT.php new file mode 100644 index 0000000..56afb70 --- /dev/null +++ b/domokits/local/modules/Front/I18n/it_IT.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Il codice di sconto non può essere vuoto', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Grazie per l\'inscrizione! Ti terremo aggiornato ogni volta che abbiamo eventuali nuovi aggiornamenti.', + 'You should sign in or register to use this coupon' => 'Dovresti accedere o registrarti per utilizzare questo coupon', +]; diff --git a/domokits/local/modules/Front/I18n/ru_RU.php b/domokits/local/modules/Front/I18n/ru_RU.php new file mode 100644 index 0000000..3427a9d --- /dev/null +++ b/domokits/local/modules/Front/I18n/ru_RU.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Код купона не может быть пустым', + 'Delivery address does not belong to the current customer' => 'Адрес доставки не пренадлежит текущему клиенту', + 'Delivery module cannot be use with selected delivery address' => 'Модуль доставки не может быть использован с текущим адресом доставки', + 'Error during address deletion process' => 'Ошибка удаления адреса', + 'Failed to add this article to your cart, please try again' => 'Ошибка при добавлении статьи в вашу корзину, попробуйте еще раз', + 'Invoice address does not belong to the current customer' => 'Адрес выставления счета не пренадлежит текущему клиенту', + 'No placed order' => 'Нет размещенного заказа', + 'Please check your coupon code: %message' => 'Пожалуйста, проверьте код купона: %message', + 'Please check your input: %s' => 'Пожалуйста, проверьте ваш ввод: %s', + 'Received failed order id does not belong to the current customer' => 'Полученный ошибочный заказ не пренадлежит текущему клиенту', + 'Received placed order id does not belong to the current customer' => 'Полученный размещенный заказ не пренадлежит текущему клиенту', + 'Sorry, an error occured: %s' => 'К сожалению произшла ошибка: %s', + 'Sorry, an error occurred: %message' => 'К сожалению произошла ошибка: %message ', + 'Sorry, an error occurred: %s' => 'К сожалению произошла ошибка: %s ', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Спасибо за подписку! Мы будем держать вас в курсе обновлений.', + 'The delivery module is not valid.' => 'Некоректный модуль доставки', + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated' => 'Для включения функции виртуальных продуктов, модуль VirtualProductDelivery должен быть включен', + 'Wrong email or password. Please try again' => 'Некоректный email или пароль. Пожалуйста, попробуйте еще раз', + 'You should sign in or register to use this coupon' => 'Вы должны войти или зарегистрироваться что использовать этот купон', + 'You\'re currently logged in. Please log out before requesting a new password.' => 'Вы сейчас авторизированы. Пожалуйста выйдите перед запросом нового пароля.', + 'Your subscription to our newsletter has been canceled.' => 'Ваша подписка на рассылку была отменена', +]; diff --git a/domokits/local/modules/Front/I18n/tr_TR.php b/domokits/local/modules/Front/I18n/tr_TR.php new file mode 100644 index 0000000..a709243 --- /dev/null +++ b/domokits/local/modules/Front/I18n/tr_TR.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Coupon code can\'t be empty' => 'Kupon şifre boş olamaz', + 'Delivery address does not belong to the current customer' => 'Teslimat adresi geçerli müşteriye ait değil', + 'Delivery module cannot be use with selected delivery address' => 'Teslim modülü seçili teslimat adresi kullanılamaz', + 'Error during address deletion process' => 'Adres silme işlemi sırasında bir hata oluştu', + 'Failed to add this article to your cart, please try again' => 'Sepetinize Bu ürün eklenemedi, lütfen tekrar deneyin', + 'Invoice address does not belong to the current customer' => 'Fatura adresi geçerli müşteriye ait değil', + 'No placed order' => 'Yerleştirilen hiçbir sipariş', + 'Please check your coupon code: %message' => 'Kupon kodunuzu gözden geçirin: %message', + 'Please check your input: %s' => 'Lütfen girişinizi denetleyin: %s', + 'Received failed order id does not belong to the current customer' => 'Alınan başarısız sipariş kimliği geçerli müşteriye ait değil', + 'Received placed order id does not belong to the current customer' => 'Alınmış yerleştirilmiş sipariş kimliği geçerli müşteriye ait değil', + 'Sorry, an error occured: %s' => 'Üzgünüz, bir hata oluştu: %s', + 'Sorry, an error occurred: %message' => 'Üzgünüz, bir hata oluştu: %message', + 'Sorry, an error occurred: %s' => 'Üzgünüz, bir hata oluştu: %s', + 'Thanks for signing up! We\'ll keep you posted whenever we have any new updates.' => 'Teşekkürler. Yeni güncelleştirmeler olduğunda sizi haberdar edeceğiz.', + 'To enable the virtual product feature, the VirtualProductDelivery module should be activated' => 'Sanal ürün özelliği etkinleştirmek için VirtualProductDelivery modülü etkinleştirilmesi', + 'Wrong email or password. Please try again' => 'Email adresi veya şifre hatalı. Lütfen tekrar deneyiniz', + 'You\'re currently logged in. Please log out before requesting a new password.' => 'Şu anda logged içinde. Lütfen yeni bir parola istemeden önce çıkış.', +]; diff --git a/domokits/local/modules/Front/LICENSE.txt b/domokits/local/modules/Front/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/Front/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/Front/composer.json b/domokits/local/modules/Front/composer.json new file mode 100644 index 0000000..b916b7b --- /dev/null +++ b/domokits/local/modules/Front/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/front-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "Front" + } +} diff --git a/domokits/local/modules/HookAdminHome/Config/config.xml b/domokits/local/modules/HookAdminHome/Config/config.xml new file mode 100644 index 0000000..895247b --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Config/config.xml @@ -0,0 +1,44 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/HookAdminHome/Config/module.xml b/domokits/local/modules/HookAdminHome/Config/module.xml new file mode 100644 index 0000000..a19b9af --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Config/module.xml @@ -0,0 +1,32 @@ + + + HookAdminHome\HookAdminHome + + Displays the default blocks on the homepage of the administration + + + Affiche les blocs par défaut sur la page d'accueil de l'administration + + + en_US + fr_FR + + 2.5.4 + + + Gilles Bourgeat + gilles@thelia.net + + + Franck Allimant + CQFDev + franck@cqfdev.fr + www.cqfdev.fr + + + classic + 2.5.4 + prod + diff --git a/domokits/local/modules/HookAdminHome/Config/routing.xml b/domokits/local/modules/HookAdminHome/Config/routing.xml new file mode 100644 index 0000000..a1dd0d6 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Config/routing.xml @@ -0,0 +1,12 @@ + + + + + + HookAdminHome\Controller\HomeController::processTemplateAction + ajax/thelia_news_feed + 1 + + diff --git a/domokits/local/modules/HookAdminHome/Controller/ConfigurationController.php b/domokits/local/modules/HookAdminHome/Controller/ConfigurationController.php new file mode 100644 index 0000000..174a22d --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Controller/ConfigurationController.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome\Controller; + +use HookAdminHome\HookAdminHome; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Tools\URL; + +class ConfigurationController extends BaseAdminController +{ + /** + * @Route("/admin/module/HookAdminHome/configure", name="admin.home.config", methods={"POST"}) + */ + public function editConfiguration() + { + if (null !== $response = $this->checkAuth( + AdminResources::MODULE, + [HookAdminHome::DOMAIN_NAME], + AccessManager::UPDATE + )) { + return $response; + } + + $form = $this->createForm('hookadminhome.config.form'); + $error_message = null; + + try { + $validateForm = $this->validateForm($form); + $data = $validateForm->getData(); + + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_NEWS, 0); + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_SALES, 0); + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_INFO, 0); + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_STATS, 0); + + if ($data['enabled-news']) { + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_NEWS, 1); + } + + if ($data['enabled-sales']) { + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_SALES, 1); + } + + if ($data['enabled-info']) { + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_INFO, 1); + } + + if ($data['enabled-stats']) { + HookAdminHome::setConfigValue(HookAdminHome::ACTIVATE_STATS, 1); + } + + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/HookAdminHome')); + } catch (FormValidationException $e) { + $error_message = $this->createStandardFormValidationErrorMessage($e); + } + + if (null !== $error_message) { + $this->setupFormErrorContext( + 'configuration', + $error_message, + $form + ); + $response = $this->render('module-configure', ['module_code' => 'HookAdminHome']); + } + + return $response; + } +} diff --git a/domokits/local/modules/HookAdminHome/Controller/HomeController.php b/domokits/local/modules/HookAdminHome/Controller/HomeController.php new file mode 100644 index 0000000..abadc37 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Controller/HomeController.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome\Controller; + +use HookAdminHome\HookAdminHome; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Model\ConfigQuery; +use Thelia\Model\Currency; +use Thelia\Model\CustomerQuery; +use Thelia\Model\OrderQuery; + +/** + * Class HomeController. + * + * @author Gilles Bourgeat + */ +class HomeController extends BaseAdminController +{ + /** + * Key prefix for stats cache. + */ + public const STATS_CACHE_KEY = 'stats'; + + public const RESOURCE_CODE = 'admin.home'; + + /** + * @Route("/admin/home/stats", name="admin.home.stats") + */ + public function loadStatsAjaxAction(AdapterInterface $cacheAdapter) + { + if (null !== $response = $this->checkAuth(self::RESOURCE_CODE, [], AccessManager::VIEW)) { + return $response; + } + + $cacheExpire = ConfigQuery::getAdminCacheHomeStatsTTL(); + + $month = (int) $this->getRequest()->query->get('month', date('m')); + $year = (int) $this->getRequest()->query->get('year', date('Y')); + + $cacheKey = self::STATS_CACHE_KEY.'_'.$month.'_'.$year; + + $cacheItem = $cacheAdapter->getItem($cacheKey); + + // force flush + if ($this->getRequest()->query->get('flush', '0')) { + $cacheAdapter->deleteItem($cacheKey); + } + + if (!$cacheItem->isHit()) { + $data = $this->getStatus($month, $year); + + $cacheItem->set(json_encode($data)); + $cacheItem->expiresAfter($cacheExpire); + + if ($cacheExpire) { + $cacheAdapter->save($cacheItem); + } + } + + return $this->jsonResponse($cacheItem->get()); + } + + /** + * @Route( + * "/admin/home/month-sales-block/{month}/{year}", + * name="admin.home.month.sales.block", + * requirements={"month"="\d+", "year"="\d+"} + * ) + */ + public function blockMonthSalesStatistics($month, $year) + { + $baseDate = sprintf('%04d-%02d', $year, $month); + + $startDate = "$baseDate-01"; + $endDate = date('Y-m-t', strtotime($startDate)); + + $prevMonthStartDate = date('Y-m-01', strtotime("$baseDate -1 month")); + $prevMonthEndDate = date('Y-m-t', strtotime($prevMonthStartDate)); + + return $this->render('block-month-sales-statistics', [ + 'startDate' => $startDate, + 'endDate' => $endDate, + 'prevMonthStartDate' => $prevMonthStartDate, + 'prevMonthEndDate' => $prevMonthEndDate, + ]); + } + + /** + * @param int $month + * @param int $year + * + * @return \stdClass + */ + protected function getStatus($month, $year) + { + $data = new \stdClass(); + + $data->title = $this->getTranslator()->trans( + 'Stats on %month/%year', + ['%month' => $month, '%year' => $year], + HookAdminHome::DOMAIN_NAME + ); + + $data->series = []; + + /* sales */ + $data->series[] = $saleSeries = new \stdClass(); + $saleSeries->color = self::testHexColor('sales_color', '#adadad'); + $saleSeries->data = OrderQuery::getMonthlySaleStats($month, $year); + $saleSeries->valueFormat = '%1.2f '.Currency::getDefaultCurrency()->getSymbol(); + + /* new customers */ + $data->series[] = $newCustomerSeries = new \stdClass(); + $newCustomerSeries->color = self::testHexColor('customers_color', '#f39922'); + $newCustomerSeries->data = CustomerQuery::getMonthlyNewCustomersStats($month, $year); + $newCustomerSeries->valueFormat = '%d'; + + /* orders */ + $data->series[] = $orderSeries = new \stdClass(); + $orderSeries->color = self::testHexColor('orders_color', '#5cb85c'); + $orderSeries->data = OrderQuery::getMonthlyOrdersStats($month, $year); + $orderSeries->valueFormat = '%d'; + + /* first order */ + $data->series[] = $firstOrderSeries = new \stdClass(); + $firstOrderSeries->color = self::testHexColor('first_orders_color', '#5bc0de'); + $firstOrderSeries->data = OrderQuery::getFirstOrdersStats($month, $year); + $firstOrderSeries->valueFormat = '%d'; + + /* cancelled orders */ + $data->series[] = $cancelledOrderSeries = new \stdClass(); + $cancelledOrderSeries->color = self::testHexColor('cancelled_orders_color', '#d9534f'); + $cancelledOrderSeries->data = OrderQuery::getMonthlyOrdersStats($month, $year, [5]); + $cancelledOrderSeries->valueFormat = '%d'; + + return $data; + } + + /** + * @param string $key + * @param string $default + * + * @return string hexadecimal color or default argument + */ + protected function testHexColor($key, $default) + { + $hexColor = $this->getRequest()->query->get($key, $default); + + return preg_match('/^#[a-f0-9]{6}$/i', $hexColor) ? $hexColor : $default; + } +} diff --git a/domokits/local/modules/HookAdminHome/Form/Configuration.php b/domokits/local/modules/HookAdminHome/Form/Configuration.php new file mode 100644 index 0000000..87591ca --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Form/Configuration.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome\Form; + +use HookAdminHome\HookAdminHome; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; + +class Configuration extends BaseForm +{ + protected function buildForm(): void + { + $this->formBuilder->add( + 'enabled-news', + CheckboxType::class, + [ + 'label' => 'Enabled News', + 'label_attr' => [ + 'for' => 'enabled-news', + 'help' => Translator::getInstance()->trans( + 'Check if you want show news', + [], + HookAdminHome::DOMAIN_NAME + ), + ], + 'required' => false, + 'value' => HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_NEWS, 0), + ] + ); + + $this->formBuilder->add( + 'enabled-info', + CheckboxType::class, + [ + 'label' => 'Enabled Info', + 'label_attr' => [ + 'for' => 'enabled-info', + 'help' => Translator::getInstance()->trans( + 'Check if you want show info', + [], + HookAdminHome::DOMAIN_NAME + ), + ], + 'required' => false, + 'value' => HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_INFO, 0), + ] + ); + + $this->formBuilder->add( + 'enabled-stats', + CheckboxType::class, + [ + 'label' => 'Enabled default Home Stats', + 'label_attr' => [ + 'for' => 'enabled-stats', + 'help' => Translator::getInstance()->trans( + 'Check if you want show default Home Stats', + [], + HookAdminHome::DOMAIN_NAME + ), + ], + 'required' => false, + 'value' => HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_STATS, 0), + ] + ); + + $this->formBuilder->add( + 'enabled-sales', + CheckboxType::class, + [ + 'label' => 'Enabled Sales Statistics', + 'label_attr' => [ + 'for' => 'enabled-sales', + 'help' => Translator::getInstance()->trans( + 'Check if you want show sales stats', + [], + HookAdminHome::DOMAIN_NAME + ), + ], + 'required' => false, + 'value' => HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_SALES, 0), + ] + ); + } + + public static function getName() + { + return 'hookadminhomeconfigform'; + } +} diff --git a/domokits/local/modules/HookAdminHome/Hook/AdminHook.php b/domokits/local/modules/HookAdminHome/Hook/AdminHook.php new file mode 100644 index 0000000..c451460 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Hook/AdminHook.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome\Hook; + +use HookAdminHome\HookAdminHome; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class AdminHook. + * + * @author Gilles Bourgeat + */ +class AdminHook extends BaseHook +{ + protected $theliaCache; + + public function __construct(AdapterInterface $theliaCache = null) + { + $this->theliaCache = $theliaCache; + } + + public function blockStatistics(HookRenderEvent $event): void + { + if (1 == HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_STATS, 1)) { + $event->add($this->render('block-statistics.html')); + } + + $event->add($this->render('hook-admin-home-config.html')); + } + + public function blockStatisticsJs(HookRenderEvent $event): void + { + if (1 == HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_STATS, 1)) { + $event->add($this->render('block-statistics-js.html')); + } + } + + public function blockSalesStatistics(HookRenderBlockEvent $event): void + { + if (1 == HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_SALES, 1)) { + $content = trim($this->render('block-sales-statistics.html')); + if (!empty($content)) { + $event->add([ + 'id' => 'block-sales-statistics', + 'title' => $this->trans('Sales statistics', [], HookAdminHome::DOMAIN_NAME), + 'content' => $content, + ]); + } + } + } + + public function blockNews(HookRenderBlockEvent $event): void + { + if (1 == HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_NEWS, 1)) { + $content = trim($this->render('block-news.html')); + if (!empty($content)) { + $event->add([ + 'id' => 'block-news', + 'title' => $this->trans('Thelia Github activity', [], HookAdminHome::DOMAIN_NAME), + 'content' => $content, + ]); + } + } + } + + public function blockTheliaInformation(HookRenderBlockEvent $event): void + { + $releases = $this->getGithubReleases(); + if (1 == HookAdminHome::getConfigValue(HookAdminHome::ACTIVATE_INFO, 1)) { + $content = trim( + $this->render( + 'block-thelia-information.html', + [ + 'latestStableRelease' => $releases['latestStableRelease'], + 'latestPreRelease' => $releases['latestPreRelease'], + ] + ) + ); + if (!empty($content)) { + $event->add([ + 'id' => 'block-thelia-information', + 'title' => $this->trans('Thelia news', [], HookAdminHome::DOMAIN_NAME), + 'content' => $content, + ]); + } + } + } + + private function getGithubReleases(): array + { + $cachedReleases = $this->theliaCache->getItem('thelia_github_releases'); + if (!$cachedReleases->isHit()) { + try { + $resource = curl_init(); + + curl_setopt($resource, \CURLOPT_URL, 'https://api.github.com/repos/thelia/thelia/releases'); + curl_setopt($resource, \CURLOPT_RETURNTRANSFER, 1); + curl_setopt($resource, \CURLOPT_HTTPHEADER, ['accept: application/vnd.github.v3+json']); + curl_setopt($resource, \CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); + + $results = curl_exec($resource); + + curl_close($resource); + + $theliaReleases = json_decode($results, true); + + $publishedAtSort = function ($a, $b) {return (new \DateTime($a['published_at'])) < (new \DateTime($b['published_at'])); }; + + $stableReleases = array_filter($theliaReleases, function ($theliaRelease) { return !$theliaRelease['prerelease']; }); + usort($stableReleases, $publishedAtSort); + $latestStableRelease = $stableReleases[0] ?? null; + + $preReleases = array_filter($theliaReleases, function ($theliaRelease) { return $theliaRelease['prerelease']; }); + usort($preReleases, $publishedAtSort); + $latestPreRelease = $preReleases[0] ?? null; + + // Don't display pre-release if they are < than stable release + if (version_compare($latestPreRelease['tag_name'], $latestStableRelease['tag_name'], '<')) { + $latestPreRelease = null; + } + } catch (\Exception $exception) { + $latestPreRelease = null; + $latestStableRelease = null; + } + + $cachedReleases->expiresAfter(3600); + $cachedReleases->set( + [ + 'latestStableRelease' => $latestStableRelease, + 'latestPreRelease' => $latestPreRelease, + ] + ); + $this->theliaCache->save($cachedReleases); + } + + return $cachedReleases->get(); + } +} diff --git a/domokits/local/modules/HookAdminHome/Hook/HookAdminManager.php b/domokits/local/modules/HookAdminHome/Hook/HookAdminManager.php new file mode 100644 index 0000000..64dbfcf --- /dev/null +++ b/domokits/local/modules/HookAdminHome/Hook/HookAdminManager.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +class HookAdminManager extends BaseHook +{ + public function onModuleConfiguration(HookRenderEvent $event): void + { + $event->add( + $this->render('admin-home-config.html') + ); + } +} diff --git a/domokits/local/modules/HookAdminHome/HookAdminHome.php b/domokits/local/modules/HookAdminHome/HookAdminHome.php new file mode 100644 index 0000000..409b218 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/HookAdminHome.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAdminHome; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Core\Template\TemplateDefinition; +use Thelia\Module\BaseModule; + +class HookAdminHome extends BaseModule +{ + /** @var string */ + public const DOMAIN_NAME = 'hookadminhome'; + + /** @var string */ + public const ACTIVATE_NEWS = 'activate_home_news'; + + /** @var string */ + public const ACTIVATE_SALES = 'activate_home_sales'; + + /** @var string */ + public const ACTIVATE_INFO = 'activate_home_info'; + + /** @var string */ + public const ACTIVATE_STATS = 'activate_stats'; + + /** + * @return array + */ + public function getHooks() + { + return [ + [ + 'type' => TemplateDefinition::BACK_OFFICE, + 'code' => 'hook_home_stats', + 'title' => 'Hook Home Stats', + 'description' => 'Hook to change default stats', + ], + ]; + } + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/HookAdminHome/I18n/ar_SA.php b/domokits/local/modules/HookAdminHome/I18n/ar_SA.php new file mode 100644 index 0000000..537ee04 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/ar_SA.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Stats on %month/%year' => 'إحصائيات عن الشهر و السنة %month/%year', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ar_SA.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ar_SA.php new file mode 100644 index 0000000..a91b16c --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ar_SA.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'تم إحباط الطلبات', + 'Average cart' => 'متوسط العربة', + 'Categories' => 'الفئات', + 'Click here' => 'انقر هنا', + 'Current version' => 'النسخة الحالية', + 'Customers' => 'العملاء', + 'Dashboard' => 'لوحة المعلومات', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/cs_CZ.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/cs_CZ.php new file mode 100644 index 0000000..12aae3c --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/cs_CZ.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Aborted orders', + 'Average cart' => 'Average cart', + 'Categories' => 'Categories', + 'Click here' => 'Click here', + 'Current version' => 'Current version', + 'Customers' => 'Customers', + 'Dashboard' => 'Dashboard', + 'First orders' => 'First orders', + 'Latest version available' => 'Latest version available', + 'Lire la suite' => 'Lire la suite', + 'Loading Thelia lastest news...' => 'Loading Thelia lastest news...', + 'Loading...' => 'Loading...', + 'New customers' => 'New customers', + 'News' => 'News', + 'Offline products' => 'Offline products', + 'Online products' => 'Online products', + 'Orders' => 'Orders', + 'Overall sales' => 'Overall sales', + 'Previous month sales' => 'Previous month sales', + 'Previous year sales' => 'Previous year sales', + 'Products' => 'Products', + 'Sales' => 'Sales', + 'Sales excluding shipping' => 'Sales excluding shipping', + 'This month' => 'This month', + 'This year' => 'This year', + 'Today' => 'Today', + 'Yesterday sales' => 'Yesterday sales', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/de_DE.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..4b3fac2 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/de_DE.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Abgebrochene Bestellungen', + 'Average cart' => 'Durchschnittlichen Warenkorb', + 'Categories' => 'Kategorien', + 'Click here' => 'Hier Klicken', + 'Current version' => 'Aktuelle Version', + 'Customers' => 'Kunden', + 'Dashboard' => 'Dashboard', + 'First orders' => 'Erste Bestellungen', + 'Latest version available' => 'Neueste Version verfügbar', + 'Lire la suite' => 'Weiterlesen', + 'Loading Thelia lastest news...' => 'THELIAs neuesten Nachrichten Laden ...', + 'Loading...' => 'Laden...', + 'New customers' => 'Neue Kunde', + 'Offline products' => 'Offline Produkte', + 'Online products' => 'Online Produkte', + 'Orders' => 'Bestellungen', + 'Overall sales' => 'Gesamtverkäufe', + 'Previous month sales' => 'Vorheriger Monat Verkäufe', + 'Previous year sales' => 'Vorheriges Jahr Verkäufe', + 'Products' => 'Produkte', + 'Sales' => 'Verkäufe', + 'Sales excluding shipping' => 'Verkäufe ohne Lieferung', + 'This month' => 'Diesen Monat', + 'This year' => 'Dieses Jahr', + 'Today' => 'Heute', + 'Yesterday sales' => 'Verkäufe von Gestern', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/en_US.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..b212ca5 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/en_US.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Aborted orders', + 'An error occurred while reading from JSON file' => 'An error occurred while reading from JSON file', + 'Average cart' => 'Average cart', + 'Categories' => 'Categories', + 'Click here' => 'Click here', + 'Current version' => 'Current version', + 'Customers' => 'Customers', + 'Dashboard' => 'Dashboard', + 'First orders' => 'First orders', + 'Latest version available' => 'Latest version available', + 'Loading Thelia lastest news...' => 'Loading Thelia lastest news...', + 'Loading...' => 'Loading...', + 'New customers' => 'New customers', + 'News' => 'News', + 'Offline products' => 'Offline products', + 'Online products' => 'Online products', + 'Orders' => 'Orders', + 'Overall sales' => 'Overall sales', + 'Previous month sales' => 'Previous month sales', + 'Previous year sales' => 'Previous year sales', + 'Products' => 'Products', + 'Read more' => 'Read more', + 'Sales' => 'Sales', + 'Sales excluding shipping' => 'Sales excluding shipping', + 'This month' => 'This month', + 'This year' => 'This year', + 'Today' => 'Today', + 'YYYY-MM' => 'YYYY-MM', + 'Yesterday sales' => 'Yesterday sales', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/es_ES.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/es_ES.php new file mode 100644 index 0000000..3454efe --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/es_ES.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Pedidos abandonados', + 'Average cart' => 'Carrito medio', + 'Categories' => 'Categorías', + 'Click here' => 'Haz clic aquí', + 'Current version' => 'Versión actual', + 'Customers' => 'Clientes', + 'Dashboard' => 'Panel de Control', + 'First orders' => 'Primeros pedidos', + 'Latest version available' => 'Última versión disponible', + 'Lire la suite' => 'Leer más', + 'Loading Thelia lastest news...' => 'Carregant Thelia últimes notícies ...', + 'Loading...' => 'Carregant ...', + 'New customers' => 'Nuevos clientes', + 'News' => 'Noticias', + 'Offline products' => 'Productos fuera de línea', + 'Online products' => 'Productos en línea', + 'Orders' => 'Pedidos', + 'Overall sales' => 'Ventas totales', + 'Previous month sales' => 'Ventas del mes anterior', + 'Previous year sales' => 'Ventas del año anterior', + 'Products' => 'Productos', + 'Sales' => 'Ventas', + 'Sales excluding shipping' => 'Ventas sin el envio', + 'This month' => 'Este mes', + 'This year' => 'Este año', + 'Today' => 'Hoy', + 'Yesterday sales' => 'Ventas de ayer', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..b0693b6 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Paniers abandonnés', + 'An error occurred while reading from JSON file' => 'Désolé, une erreur s\'est produite pendant la récupération des données.', + 'Average cart' => 'Panier moyen', + 'Categories' => 'Rubriques', + 'Customers' => 'Clients', + 'Dashboard' => 'Tableau de bord', + 'First orders' => 'Premières commandes', + 'Latest pre-release' => 'Derniére pré-version', + 'Latest stable version' => 'Derniére version stable', + 'Loading Thelia lastest news...' => 'Chargement des dernières information Thelia...', + 'Loading Tweeter feed...' => 'Chargement du fil Tweeter...', + 'New customers' => 'Nouveaux clients', + 'Offline products' => 'Produits hors ligne', + 'Online products' => 'Produits en ligne', + 'Orders' => 'Commandes', + 'Overall sales' => 'Total des ventes', + 'Previous month sales' => 'Ventes du mois précédent', + 'Previous year sales' => 'Ventes de l\'année précédente', + 'Products' => 'Produits', + 'Read more' => 'Lire la suite', + 'Sales' => 'Ventes', + 'Sales excluding shipping' => 'Ventes hors frais de port', + 'This month' => 'Ce mois', + 'This year' => 'Cette année', + 'Today' => 'Aujourd\'hui', + 'YYYY-MM' => 'MM/YYYY', + 'Yesterday sales' => 'Ventes de la veille', + 'Your version' => 'Votre version', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/it_IT.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/it_IT.php new file mode 100644 index 0000000..a8d73b8 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/it_IT.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Ordini annullati', + 'Average cart' => 'Carrello medio', + 'Categories' => 'Categorie', + 'Click here' => 'Clicca qui', + 'Current version' => 'Versione attuale', + 'Customers' => 'Clienti', + 'Dashboard' => 'Dashboard', + 'First orders' => 'Primi ordini', + 'Latest version available' => 'Ultima versione disponibile', + 'Lire la suite' => 'Per saperne di più', + 'Loading Thelia lastest news...' => 'Caricamento delle ultime notizie su Thelia...', + 'Loading...' => 'Caricamento...', + 'New customers' => 'Nuovi clienti', + 'News' => 'Notizie', + 'Offline products' => 'Prodotti non in linea', + 'Online products' => 'Prodotti online', + 'Orders' => 'Ordini', + 'Overall sales' => 'Vendite complessive', + 'Previous month sales' => 'Vendite del mese precedente', + 'Previous year sales' => 'Vendite dell\'anno precedente', + 'Products' => 'Prodotti', + 'Read more' => 'Per saperne di più', + 'Sales' => 'Vendite', + 'Sales excluding shipping' => 'Vendite escluse spese di spedizione', + 'This month' => 'Questo mese', + 'This year' => 'Quest\'anno', + 'Today' => 'Oggi', + 'Yesterday sales' => 'Vendite di ieri', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/pt_BR.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/pt_BR.php new file mode 100644 index 0000000..7bd02a1 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/pt_BR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Ordens abortadas', + 'Click here' => 'Clique aqui', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ru_RU.php new file mode 100644 index 0000000..6e05f0f --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'Отмененные заказы', + 'Average cart' => 'Средняя корзина', + 'Categories' => 'Категории', + 'Click here' => 'Нажмите здесь', + 'Current version' => 'Текущая версия', + 'Customers' => 'Клиенты', + 'Dashboard' => 'Приборная панель', + 'First orders' => 'Первые заказы', + 'Latest version available' => 'Последняя доступная версия', + 'Loading Thelia lastest news...' => 'Загрузка последних новостей Thelia...', + 'Loading...' => 'Загрузка...', + 'New customers' => 'Новые клиенты', + 'News' => 'Новости', + 'Offline products' => 'Товары выкл.', + 'Online products' => 'Товары вкл.', + 'Orders' => 'Заказы', + 'Overall sales' => 'Всего продаж', + 'Previous month sales' => 'Продажи в предыдущем месяце', + 'Previous year sales' => 'Продажи в предыдущем году', + 'Products' => 'Товары', + 'Read more' => 'Читать далее', + 'Sales' => 'Продажи', + 'Sales excluding shipping' => 'Продаж без доставки', + 'This month' => 'В этом месяце', + 'This year' => 'В этом году', + 'Today' => 'Сегодня', + 'Yesterday sales' => 'Вчерашние продажи', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..9de1b15 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Aborted orders' => 'İptal edilen siparişler', + 'Average cart' => 'Sepet Ortalaması', + 'Categories' => 'Katogoriler', + 'Click here' => 'Buraya tıklayın', + 'Current version' => 'Güncel Sürüm', + 'Customers' => 'müşteriler', + 'Dashboard' => 'Kontrol paneli', + 'First orders' => 'İlk emir', + 'Latest version available' => 'En son yorum elde edilebilir', + 'Lire la suite' => 'Devamını okuyun', + 'Loading Thelia lastest news...' => 'Thelia yükleme son haberler...', + 'Loading...' => 'Yükleneniyor…...', + 'New customers' => 'Yeni Müşteriler', + 'News' => 'Yeni Haberler', + 'Offline products' => 'Çevrimdışı ürünler', + 'Online products' => 'Online Ürünler', + 'Orders' => 'siparişler', + 'Overall sales' => 'Genel satış', + 'Previous month sales' => 'Önceki ay satış', + 'Previous year sales' => 'Önceki yılın satış', + 'Products' => 'ürün', + 'Sales' => 'Satış', + 'Sales excluding shipping' => 'Nakliye hariç satış', + 'This month' => 'Bu Ay', + 'This year' => 'Bu yıl', + 'Today' => 'bugün', + 'Yesterday sales' => 'Dün satış', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/cs_CZ.php b/domokits/local/modules/HookAdminHome/I18n/cs_CZ.php new file mode 100644 index 0000000..ada6cbb --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/cs_CZ.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Sales statistics', + 'Stats on %month/%year' => 'Stats on %month/%year', + 'Thelia informations' => 'Thelia information', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/de_DE.php b/domokits/local/modules/HookAdminHome/I18n/de_DE.php new file mode 100644 index 0000000..3f14186 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/de_DE.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Verkaufsstatistiken', + 'Stats on %month/%year' => 'Statistiken für %month/%year', + 'Thelia informations' => 'Thelias Informationen', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/en_US.php b/domokits/local/modules/HookAdminHome/I18n/en_US.php new file mode 100644 index 0000000..aa42b6d --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/en_US.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Stats on %month/%year' => 'Stats on %month/%year', + 'Thelia informations' => 'Thelia information', + 'Sales statistics' => 'Sales statistics', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/es_ES.php b/domokits/local/modules/HookAdminHome/I18n/es_ES.php new file mode 100644 index 0000000..588ad89 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/es_ES.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Estadísticas de ventas', + 'Thelia informations' => 'información sobre Thelia', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/fr_FR.php b/domokits/local/modules/HookAdminHome/I18n/fr_FR.php new file mode 100644 index 0000000..880bd48 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Statistiques de vente', + 'Stats on %month/%year' => 'Statistiques pour %month/%year', + 'Thelia Github activity' => 'Thelia sur Github', + 'Thelia news' => 'Actualité Thelia', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/id_ID.php b/domokits/local/modules/HookAdminHome/I18n/id_ID.php new file mode 100644 index 0000000..daa0f18 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/id_ID.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Stats on %month/%year' => 'Stats on %month/%year', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/it_IT.php b/domokits/local/modules/HookAdminHome/I18n/it_IT.php new file mode 100644 index 0000000..c02246c --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/it_IT.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Statistiche di vendita', + 'Thelia informations' => 'Thelia informazioni', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/ru_RU.php b/domokits/local/modules/HookAdminHome/I18n/ru_RU.php new file mode 100644 index 0000000..5d5de3f --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/ru_RU.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Статистика продаж', + 'Stats on %month/%year' => 'Статистика за %month/%year', + 'Thelia informations' => 'Информация о Thelia', +]; diff --git a/domokits/local/modules/HookAdminHome/I18n/tr_TR.php b/domokits/local/modules/HookAdminHome/I18n/tr_TR.php new file mode 100644 index 0000000..0c5b6b7 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/I18n/tr_TR.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Sales statistics' => 'Satış istatistikleri', + 'Stats on %month/%year' => '%month/%year istatistikleri', + 'Thelia informations' => 'Thelia bilgi', +]; diff --git a/domokits/local/modules/HookAdminHome/LICENSE.txt b/domokits/local/modules/HookAdminHome/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookAdminHome/composer.json b/domokits/local/modules/HookAdminHome/composer.json new file mode 100644 index 0000000..d5921a2 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-admin-home-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookAdminHome" + } +} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/admin-home-config.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/admin-home-config.html new file mode 100644 index 0000000..7517623 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/admin-home-config.html @@ -0,0 +1,87 @@ +
+
+
+ {intl l="Hook Admin Home config"} +
+
+
+
+
+ + {form name="hookadminhome.config.form"} + + + {form_hidden_fields} + + {form_field form=$form field="enabled-stats"} +
+ + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="enabled-news"} +
+ + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="enabled-sales"} +
+ + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="enabled-info"} +
+ + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + + + {/form} +
+
+
+ + diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/ajax/thelia_news_feed.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/ajax/thelia_news_feed.html new file mode 100644 index 0000000..f5c1aa7 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/ajax/thelia_news_feed.html @@ -0,0 +1,29 @@ +{* this template is loaded via Ajax in the login page, to prevent login page slowdown *} + +{* Set the default translation domain, that will be used by intl when the 'd' parameter is not set *} +{default_translation_domain domain='hookadminhome.bo.default'} + +
+ {loop type="feed" name="thelia_feeds" url="https://github.com/thelia/thelia/commits/main.atom" limit="6" timeout=30} + +
+ +
+
+ {* we use unescape:"htmlall" to unescape var before truncate, to prevent a cut in the middel of an HTML entity, eg &ea... *} +

{$DESCRIPTION|strip_tags|unescape:"htmlall"|truncate:250:"...":true nofilter}

+
+ +
+
+ + {/loop} +
diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/css/home.css b/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/css/home.css new file mode 100644 index 0000000..611f622 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/css/home.css @@ -0,0 +1 @@ +#block-information a{color:#8A8A8A}.stats{border-right:1px solid #f0f0f0;text-align:center}.stats:last-child{border-right:none}.stats h2{margin-top:0;margin-bottom:5px;font-size:30px}.stats p{margin-top:0;text-transform:uppercase;font-size:12px}@media (max-width:991px){.stats{margin-bottom:10px}.stats:nth-child(3){border-right:none}}.homepage #date-picker{text-align:center;} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/less/home.less b/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/less/home.less new file mode 100644 index 0000000..a87eaab --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/assets/less/home.less @@ -0,0 +1,45 @@ +@import "../../../../../../../../templates/backOffice/default/assets/less/bootstrap/variables.less"; +@import "../../../../../../../../templates/backOffice/default/assets/less/thelia/variables.less"; + +#block-information { + a { + color: #8A8A8A; + } +} + +.stats { + border-right: 1px solid @table-border-color; + text-align: center; + + &:last-child { + border-right: none; + } + + h2 { + margin-top: 0; + margin-bottom: 5px; + font-size: 30px; + } + + p { + margin-top: 0; + text-transform: uppercase; + font-size: @font-size-base - 1; // 12px + } +} + +@media (max-width: @screen-sm-max) { + .stats { + margin-bottom: 10px; + + &:nth-child(3) { + border-right: none; + } + } +} + +.homepage { + #date-picker { + text-align: center; + } +} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-information.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-information.html new file mode 100644 index 0000000..25f0926 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-information.html @@ -0,0 +1,59 @@ +{* Do not display shop information block if user none of the required authorizations *} + +{capture name="shop_information_block_content"} + {loop type="auth" name="can_view" role="ADMIN" resource="admin.customer" access="VIEW"} + + {/loop} + + {loop type="auth" name="can_view" role="ADMIN" resource="admin.category" access="VIEW"} + + {/loop} + + {loop type="auth" name="can_view" role="ADMIN" resource="admin.product" access="VIEW"} + + + + {/loop} + + {loop type="auth" name="can_view" role="ADMIN" resource="admin.order" access="VIEW"} + + {/loop} +{/capture} + +{if trim($smarty.capture.shop_information_block_content) ne ""} +
+
+ {$smarty.capture.shop_information_block_content nofilter} +
+
+{/if} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-month-sales-statistics.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-month-sales-statistics.html new file mode 100644 index 0000000..b4ae789 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-month-sales-statistics.html @@ -0,0 +1,48 @@ +{loop type="currency" name="default-currency" default_only="1"} +{$defaultCurrency = $SYMBOL} +{/loop} + +{if empty($startDate)}{$startDate = 'this_month'}{/if} +{if empty($startDate)}{$startDate = 'this_month'}{/if} + +{if empty($prevMonthStartDate)}{$prevMonthStartDate = 'last_month'}{/if} +{if empty($prevMonthEndDate)}{$prevMonthEndDate = 'last_month'}{/if} + +
+ + + + + + + + + + + + + + + + + + + + + + + +
{intl l="Overall sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate=$startDate endDate=$endDate|default:null} symbol=$defaultCurrency|default:'€'}
{intl l="Sales excluding shipping" d='hookadminhome.bo.default'} + {$salesNoShipping = {stats key="sales" startDate=$startDate endDate=$endDate|default:null includeShipping="false"}} + {format_money number=$salesNoShipping symbol=$defaultCurrency|default:'€'} +
{intl l="Previous month sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate=$prevMonthStartDate endDate=$prevMonthEndDate|default:null} symbol=$defaultCurrency|default:'€'}
{intl l="Orders" d='hookadminhome.bo.default'} + {$orderCount = {stats key="orders" startDate=$startDate endDate=$endDate|default:null}} + {$orderCount} +
{intl l="Average cart" d='hookadminhome.bo.default'} + {if $orderCount == 0} + {format_money number=0 symbol=$defaultCurrency|default:'€'} + {else} + {format_money number={($salesNoShipping/$orderCount)|round:"2"} symbol=$defaultCurrency|default:'€'} + {/if} +
+
diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news-js.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news-js.html new file mode 100644 index 0000000..d18e1f9 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news-js.html @@ -0,0 +1,7 @@ +{loop type="auth" name="can_view" role="ADMIN" module="HookAdminHome" access="VIEW"} + +{/loop} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news.html new file mode 100644 index 0000000..97bd6f9 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-news.html @@ -0,0 +1,5 @@ +{loop type="auth" name="can_view" role="ADMIN" module="HookAdminHome" access="VIEW"} +
+
{intl l="Loading Thelia lastest news..." d='hookadminhome.bo.default'}
+
+{/loop} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-sales-statistics.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-sales-statistics.html new file mode 100644 index 0000000..5ee04b6 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-sales-statistics.html @@ -0,0 +1,100 @@ +{loop type="auth" name="can_view" role="ADMIN" resource="admin.order" access="VIEW"} + +{loop type="currency" name="default-currency" default_only="1"} +{$defaultCurrency = $SYMBOL} +{/loop} +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
{intl l="Overall sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate="today" endDate="today"} symbol=$defaultCurrency|default:'€'}
{intl l="Sales excluding shipping" d='hookadminhome.bo.default'} + {$salesNoShipping = {stats key="sales" startDate="today" endDate="today" includeShipping="false"}} + {format_money number=$salesNoShipping symbol=$defaultCurrency|default:'€'} +
{intl l="Yesterday sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate="yesterday" endDate="yesterday"} symbol=$defaultCurrency|default:'€'}
{intl l="Orders" d='hookadminhome.bo.default'} + {$orderCount = {stats key="orders" startDate="today" endDate="today"}} + {$orderCount} +
{intl l="Average cart" d='hookadminhome.bo.default'} + {if $orderCount == 0} + {format_money number=0 symbol=$defaultCurrency|default:'€'} + {else} + {format_money number={($salesNoShipping/$orderCount)|round:"2"} symbol=$defaultCurrency|default:'€'} + {/if} +
+
+
+ +
+ {include file="block-month-sales-statistics.html"} +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
{intl l="Overall sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate="this_year" endDate="this_year"} symbol=$defaultCurrency|default:'€'}
{intl l="Sales excluding shipping" d='hookadminhome.bo.default'} + {$salesNoShipping = {stats key="sales" startDate="this_year" endDate="this_year" includeShipping="false"}} + {format_money number=$salesNoShipping symbol=$defaultCurrency|default:'€'} +
{intl l="Previous year sales" d='hookadminhome.bo.default'}{format_money number={stats key="sales" startDate="last_year" endDate="last_year"} symbol=$defaultCurrency|default:'€'}
{intl l="Orders" d='hookadminhome.bo.default'} + {$orderCount = {stats key="orders" startDate="this_year" endDate="this_year"}} + {$orderCount} +
{intl l="Average cart" d='hookadminhome.bo.default'} + {if $orderCount == 0} + {format_money number=0 symbol=$defaultCurrency|default:'€'} + {else} + {format_money number={($salesNoShipping/$orderCount)|round:"2"} symbol=$defaultCurrency|default:'€'} + {/if} +
+
+
+
+{/loop} diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics-js.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics-js.html new file mode 100644 index 0000000..b346c47 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics-js.html @@ -0,0 +1,207 @@ + + + + + + + \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics.html new file mode 100644 index 0000000..e29e713 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-statistics.html @@ -0,0 +1,34 @@ +{loop type="auth" name="can_view" role="ADMIN" resource="admin.order" access="VIEW"} +
+ +
+ {intl l='Dashboard' d='hookadminhome.bo.default'} +
+ + + + + + + +
+
+ +
+
+ + + + + +
+
+ +
+ +
+
+
+ +
+{/loop} \ No newline at end of file diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-thelia-information.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-thelia-information.html new file mode 100644 index 0000000..f4823d2 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/block-thelia-information.html @@ -0,0 +1,24 @@ +{loop type="auth" name="can_view" role="ADMIN" module="HookAdminHome" access="VIEW"} +
+ + + + + + + {if $latestStableRelease} + + + + + {/if} + {if $latestPreRelease} + + + + + {/if} + +
{intl l="Your version" d='hookadminhome.bo.default'}{$THELIA_VERSION}
{intl l="Latest stable version" d='hookadminhome.bo.default'}{$latestStableRelease['tag_name']}
{intl l="Latest pre-release" d='hookadminhome.bo.default'}{$latestPreRelease['tag_name']}
+
+{/loop} diff --git a/domokits/local/modules/HookAdminHome/templates/backOffice/default/hook-admin-home-config.html b/domokits/local/modules/HookAdminHome/templates/backOffice/default/hook-admin-home-config.html new file mode 100644 index 0000000..2ce7e24 --- /dev/null +++ b/domokits/local/modules/HookAdminHome/templates/backOffice/default/hook-admin-home-config.html @@ -0,0 +1 @@ +{hook name="hook_home_stats" location="hook_home_stats"} \ No newline at end of file diff --git a/domokits/local/modules/HookAnalytics/Config/config.xml b/domokits/local/modules/HookAnalytics/Config/config.xml new file mode 100644 index 0000000..57a6cb0 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Config/config.xml @@ -0,0 +1,21 @@ + + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/domokits/local/modules/HookAnalytics/Config/module.xml b/domokits/local/modules/HookAnalytics/Config/module.xml new file mode 100644 index 0000000..99d80c1 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Config/module.xml @@ -0,0 +1,24 @@ + + + HookAnalytics\HookAnalytics + + Analytics (Google) + + + Statistiques (Google) + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookAnalytics/Config/routing.xml b/domokits/local/modules/HookAnalytics/Config/routing.xml new file mode 100644 index 0000000..269697d --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Config/routing.xml @@ -0,0 +1,10 @@ + + + + + HookAnalytics\Controller\Configuration::saveAction + + + diff --git a/domokits/local/modules/HookAnalytics/Controller/Configuration.php b/domokits/local/modules/HookAnalytics/Controller/Configuration.php new file mode 100644 index 0000000..ef62762 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Controller/Configuration.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAnalytics\Controller; + +use HookAnalytics\HookAnalytics; +use Symfony\Component\HttpFoundation\JsonResponse; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; + +/** + * Class Configuration. + * + * @author Julien Chanséaume + */ +class Configuration extends BaseAdminController +{ + public function saveAction() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], ['hookanalytics'], AccessManager::UPDATE)) { + return $response; + } + + $form = $this->createForm(\HookAnalytics\Form\Configuration::class); + $resp = [ + 'error' => 0, + 'message' => '', + ]; + $response = null; + + $lang = $this->getSession()->get('thelia.admin.edition.lang'); + try { + $vform = $this->validateForm($form); + $data = $vform->getData(); + + HookAnalytics::setConfigValue('hookanalytics_trackingcode', $data['trackingcode'], $lang->getLocale(), true); + } catch (\Exception $e) { + $resp['error'] = 1; + $resp['message'] = $e->getMessage(); + } + + return new JsonResponse($resp); + } +} diff --git a/domokits/local/modules/HookAnalytics/Form/Configuration.php b/domokits/local/modules/HookAnalytics/Form/Configuration.php new file mode 100644 index 0000000..595f409 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Form/Configuration.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAnalytics\Form; + +use HookAnalytics\HookAnalytics; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; +use Thelia\Model\LangQuery; + +/** + * Class Configuration. + * + * @author Julien Chanséaume + */ +class Configuration extends BaseForm +{ + protected function buildForm(): void + { + $form = $this->formBuilder; + + $lang = $this->getRequest()->getSession()->get('thelia.admin.edition.lang'); + if (!$lang) { + $lang = LangQuery::create()->filterByByDefault(1)->findOne(); + } + + $value = HookAnalytics::getConfigValue('hookanalytics_trackingcode', '', $lang->getLocale()); + $form->add( + 'trackingcode', + TextType::class, + [ + 'data' => $value, + 'label' => Translator::getInstance()->trans('Tracking Code'), + 'label_attr' => [ + 'for' => 'trackingcode', + ], + ] + ); + } + + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return 'hookanalytics'; + } +} diff --git a/domokits/local/modules/HookAnalytics/Hook/FrontHook.php b/domokits/local/modules/HookAnalytics/Hook/FrontHook.php new file mode 100644 index 0000000..9d20dd7 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/Hook/FrontHook.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAnalytics\Hook; + +use HookAnalytics\HookAnalytics; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume + */ +class FrontHook extends BaseHook +{ + public function onMainHeadBottom(HookRenderEvent $event): void + { + $lang = $this->getRequest()->getSession()->get('thelia.current.lang'); + if (null !== $lang) { + $value = trim(HookAnalytics::getConfigValue('hookanalytics_trackingcode', '', $lang->getLocale())); + if ('' != $value) { + $event->add($value); + } + } + } +} diff --git a/domokits/local/modules/HookAnalytics/HookAnalytics.php b/domokits/local/modules/HookAnalytics/HookAnalytics.php new file mode 100644 index 0000000..276a3cf --- /dev/null +++ b/domokits/local/modules/HookAnalytics/HookAnalytics.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookAnalytics; + +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\ConfigQuery; +use Thelia\Model\LangQuery; +use Thelia\Module\BaseModule; + +class HookAnalytics extends BaseModule +{ + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + if (($config = ConfigQuery::read('hookanalytics_trackingcode', '')) + && version_compare($newVersion, '2.4.4', '>=') + && version_compare($currentVersion, '2.4.4', '<')) { + $langs = LangQuery::create()->filterByActive()->find(); + if ($config) { + foreach ($langs as $lang) { + self::setConfigValue('hookanalytics_trackingcode', $config, $lang->getLocale()); + } + } + } + } +} diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/de_DE.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..f9954c0 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/de_DE.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Ein Fehler ist aufgetreten', + 'Edit your analytics configuration.' => 'Analytics-Konfiguration bearbeiten.', + 'Save' => 'Speichern', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/en_US.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/en_US.php new file mode 100755 index 0000000..ff7e107 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/en_US.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'An error occured', + 'Edit your analytics configuration.' => 'Edit your analytics configuration.', + 'Save' => 'Save', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..0dec381 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Une erreur est survenue', + 'Edit your analytics configuration.' => 'Modifier la configuration des statistiques', + 'Save' => ' Enregistrer', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/it_IT.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/it_IT.php new file mode 100644 index 0000000..672ee79 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Save' => 'Salvare', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/ru_RU.php new file mode 100755 index 0000000..34e6d98 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Произошла ошибка', + 'Edit your analytics configuration.' => 'Редактировать вашу конфигурацию аналитики', + 'Save' => 'Сохранить', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..e370995 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Bir hata meydana geldi', + 'Edit your analytics configuration.' => 'Analytics yapılandırmanızı düzenleyin.', + 'Save' => 'kaydet', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/de_DE.php b/domokits/local/modules/HookAnalytics/I18n/de_DE.php new file mode 100644 index 0000000..81886cd --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'Tracking-Code', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/en_US.php b/domokits/local/modules/HookAnalytics/I18n/en_US.php new file mode 100755 index 0000000..c4078df --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'Tracking Code', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/fr_FR.php b/domokits/local/modules/HookAnalytics/I18n/fr_FR.php new file mode 100755 index 0000000..77c7d34 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'Code de suivi', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..12b828e --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS-Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'YouTube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..7ca6666 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/en_US.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..74465e0 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'Flux RSS', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..b089829 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google +', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..b3b977a --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS-канал', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..351bff5 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google +', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Beslemesi', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/it_IT.php b/domokits/local/modules/HookAnalytics/I18n/it_IT.php new file mode 100644 index 0000000..0a31bcd --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'Codice di monitoraggio', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/ru_RU.php b/domokits/local/modules/HookAnalytics/I18n/ru_RU.php new file mode 100755 index 0000000..ece2499 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'Код отслеживания', +]; diff --git a/domokits/local/modules/HookAnalytics/I18n/tr_TR.php b/domokits/local/modules/HookAnalytics/I18n/tr_TR.php new file mode 100644 index 0000000..4111611 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/I18n/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Tracking Code' => 'İzleme Kodu', +]; diff --git a/domokits/local/modules/HookAnalytics/LICENSE.txt b/domokits/local/modules/HookAnalytics/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookAnalytics/composer.json b/domokits/local/modules/HookAnalytics/composer.json new file mode 100644 index 0000000..efe5231 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-analytics-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookAnalytics" + } +} diff --git a/domokits/local/modules/HookAnalytics/templates/backOffice/default/assets/js/module-configuration.js b/domokits/local/modules/HookAnalytics/templates/backOffice/default/assets/js/module-configuration.js new file mode 100644 index 0000000..fe180bb --- /dev/null +++ b/domokits/local/modules/HookAnalytics/templates/backOffice/default/assets/js/module-configuration.js @@ -0,0 +1,29 @@ +$(document).ready(function() { + $("#hookanalytics-form").on("submit", function(e, data){ + e.preventDefault(); + var form = $(this); + + $('body').append(''); + + $.ajax({ + url: form.attr('action'), + type: form.attr('method'), + data: form.serialize() + }).done(function(){ + $("#loading-event").remove(); + }) + .success(function(data) { + if (data.error != 0) { + $("#loading-event").remove(); + $('#hookanalytics-failed-body').html(data.message); + $("#hookanalytics-failed").modal("show"); + } + }) + .fail(function(jqXHR, textStatus, errorThrown){ + $("#loading-event").remove(); + $('#hookanalytics-failed-body').html(jqXHR.responseJSON.message); + $("#hookanalytics-failed").modal("show"); + }); + + }); +}); \ No newline at end of file diff --git a/domokits/local/modules/HookAnalytics/templates/backOffice/default/module_configuration.html b/domokits/local/modules/HookAnalytics/templates/backOffice/default/module_configuration.html new file mode 100755 index 0000000..758fb54 --- /dev/null +++ b/domokits/local/modules/HookAnalytics/templates/backOffice/default/module_configuration.html @@ -0,0 +1,62 @@ + + + +
+
+ +
+ {intl l='Edit your analytics configuration.'} +
+ +
+
+ + {form name="hookanalytics.configuration.form"} + + + {form_hidden_fields} + +
+
+ {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = true + page_url = {url path=$smarty.server.REQUEST_URI} + } +
+
+ + {form_field field='trackingcode'} +
+ + +
+ {/form_field} + + + + {/form} + +
+ +
+ +
+
+ + + + diff --git a/domokits/local/modules/HookCart/Config/config.xml b/domokits/local/modules/HookCart/Config/config.xml new file mode 100644 index 0000000..f8c3dce --- /dev/null +++ b/domokits/local/modules/HookCart/Config/config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/domokits/local/modules/HookCart/Config/module.xml b/domokits/local/modules/HookCart/Config/module.xml new file mode 100644 index 0000000..9f67fe6 --- /dev/null +++ b/domokits/local/modules/HookCart/Config/module.xml @@ -0,0 +1,24 @@ + + + HookCart\HookCart + + Block Cart + + + Bloc Panier + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookCart/HookCart.php b/domokits/local/modules/HookCart/HookCart.php new file mode 100644 index 0000000..5eb0daa --- /dev/null +++ b/domokits/local/modules/HookCart/HookCart.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookCart; + +use Thelia\Module\BaseModule; + +class HookCart extends BaseModule +{ +} diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..d59fd8b --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Warenkorb', + 'Checkout' => 'Zur Kasse', + 'Remove' => 'Entfernen', + 'View Cart' => 'Warenkorb anzeigen', + 'You have no items in your shopping cart.' => 'Sie haben keine Produkte im Warenkorb', +]; diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..c3fea29 --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/en_US.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Cart', + 'Checkout' => 'Checkout', + 'Remove' => 'Remove', + 'View Cart' => 'View Cart', + 'You have no items in your shopping cart.' => 'You have no items in your shopping cart.', +]; diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..e1b0971 --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Panier', + 'Checkout' => 'Commande', + 'Remove' => 'Supprimer', + 'View Cart' => 'Voir le panier', + 'You have no items in your shopping cart.' => 'Vous n\'avez pas de produit dans votre panier.', +]; diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..492fd63 --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Carrello', + 'Checkout' => 'Procedi all\'acquisto', + 'Remove' => 'Rimuovi', + 'View Cart' => 'Visualizza il carrello', + 'You have no items in your shopping cart.' => 'Non hai nessun prodotto nel tuo carrello.', +]; diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..312788a --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Корзина', + 'Checkout' => 'Оформить', + 'Remove' => 'Удалить', + 'View Cart' => 'Просмотр', + 'You have no items in your shopping cart.' => 'Ваша корзина пуста', +]; diff --git a/domokits/local/modules/HookCart/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookCart/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..8d40125 --- /dev/null +++ b/domokits/local/modules/HookCart/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Sepet', + 'Checkout' => 'Ödeme yap', + 'Remove' => 'Kaldır', + 'View Cart' => 'Sepeti Görüntüle', + 'You have no items in your shopping cart.' => 'Sepetinizde hiç ürün yok.', +]; diff --git a/domokits/local/modules/HookCart/LICENSE.txt b/domokits/local/modules/HookCart/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookCart/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookCart/composer.json b/domokits/local/modules/HookCart/composer.json new file mode 100644 index 0000000..f56a5cb --- /dev/null +++ b/domokits/local/modules/HookCart/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-cart-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookCart" + } +} diff --git a/domokits/local/modules/HookCart/templates/frontOffice/default/assets/css/styles.css b/domokits/local/modules/HookCart/templates/frontOffice/default/assets/css/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/domokits/local/modules/HookCart/templates/frontOffice/default/main-navbar-secondary.html b/domokits/local/modules/HookCart/templates/frontOffice/default/main-navbar-secondary.html new file mode 100644 index 0000000..a5df381 --- /dev/null +++ b/domokits/local/modules/HookCart/templates/frontOffice/default/main-navbar-secondary.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookCart/templates/frontOffice/default/mini-cart.html b/domokits/local/modules/HookCart/templates/frontOffice/default/mini-cart.html new file mode 100644 index 0000000..72be18e --- /dev/null +++ b/domokits/local/modules/HookCart/templates/frontOffice/default/mini-cart.html @@ -0,0 +1,73 @@ +{ifloop rel="cartloop"} + +{/ifloop} +{elseloop rel="cartloop"} + +{/elseloop} diff --git a/domokits/local/modules/HookContact/Config/config.xml b/domokits/local/modules/HookContact/Config/config.xml new file mode 100644 index 0000000..5c54bc9 --- /dev/null +++ b/domokits/local/modules/HookContact/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookContact/Config/module.xml b/domokits/local/modules/HookContact/Config/module.xml new file mode 100644 index 0000000..f1bd006 --- /dev/null +++ b/domokits/local/modules/HookContact/Config/module.xml @@ -0,0 +1,24 @@ + + + HookContact\HookContact + + Block Contact + + + Bloc Contact + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookContact/Hook/FrontHook.php b/domokits/local/modules/HookContact/Hook/FrontHook.php new file mode 100644 index 0000000..2bde0bf --- /dev/null +++ b/domokits/local/modules/HookContact/Hook/FrontHook.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookContact\Hook; + +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume + */ +class FrontHook extends BaseHook +{ + public function onMainFooterBody(HookRenderBlockEvent $event): void + { + $content = trim($this->render('main-footer-body.html')); + if ('' != $content) { + $event->add( + [ + 'id' => 'contact-footer-body', + 'class' => 'contact', + 'title' => $this->trans('Contact', [], 'hookcontact'), + 'content' => $content, + ] + ); + } + } +} diff --git a/domokits/local/modules/HookContact/HookContact.php b/domokits/local/modules/HookContact/HookContact.php new file mode 100644 index 0000000..1f5a4d2 --- /dev/null +++ b/domokits/local/modules/HookContact/HookContact.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookContact; + +use Thelia\Module\BaseModule; + +class HookContact extends BaseModule +{ +} diff --git a/domokits/local/modules/HookContact/I18n/de_DE.php b/domokits/local/modules/HookContact/I18n/de_DE.php new file mode 100644 index 0000000..8134ca2 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'Kontakt', +]; diff --git a/domokits/local/modules/HookContact/I18n/en_US.php b/domokits/local/modules/HookContact/I18n/en_US.php new file mode 100644 index 0000000..6890337 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'Contact', +]; diff --git a/domokits/local/modules/HookContact/I18n/fr_FR.php b/domokits/local/modules/HookContact/I18n/fr_FR.php new file mode 100644 index 0000000..6890337 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'Contact', +]; diff --git a/domokits/local/modules/HookContact/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookContact/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..ec233a8 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Find us, Contact us' => 'Nous trouver, Nous contacter', +]; diff --git a/domokits/local/modules/HookContact/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookContact/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..3b01cd9 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Find us, Contact us' => 'Найти нас, Связаться с нами', +]; diff --git a/domokits/local/modules/HookContact/I18n/it_IT.php b/domokits/local/modules/HookContact/I18n/it_IT.php new file mode 100644 index 0000000..71e5dd4 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'Contatta', +]; diff --git a/domokits/local/modules/HookContact/I18n/ru_RU.php b/domokits/local/modules/HookContact/I18n/ru_RU.php new file mode 100644 index 0000000..fdfc258 --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'Контакты', +]; diff --git a/domokits/local/modules/HookContact/I18n/tr_TR.php b/domokits/local/modules/HookContact/I18n/tr_TR.php new file mode 100644 index 0000000..c60f40d --- /dev/null +++ b/domokits/local/modules/HookContact/I18n/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Contact' => 'İletişim', +]; diff --git a/domokits/local/modules/HookContact/LICENSE.txt b/domokits/local/modules/HookContact/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookContact/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookContact/composer.json b/domokits/local/modules/HookContact/composer.json new file mode 100644 index 0000000..2ecdb22 --- /dev/null +++ b/domokits/local/modules/HookContact/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-contact-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookContact" + } +} diff --git a/domokits/local/modules/HookContact/templates/frontOffice/default/main-footer-body.html b/domokits/local/modules/HookContact/templates/frontOffice/default/main-footer-body.html new file mode 100644 index 0000000..9eea38b --- /dev/null +++ b/domokits/local/modules/HookContact/templates/frontOffice/default/main-footer-body.html @@ -0,0 +1,25 @@ +
+ +
    +
  • +
    + {config key="store_address1"} {config key="store_address2"} {config key="store_address3"}
    + {config key="store_zipcode"} + + {config key="store_city"} + {if {config key="store_country"} } + {loop type="country" name="address.country.title" id={config key="store_country"}}, {$TITLE}{/loop} + {/if} + +
    +
  • + {if {config key="store_phone"} } +
  • + {config key="store_phone"} +
  • + {/if} +
  • + {intl l="Find us, Contact us" d="hookcontact.fo.default"} +
  • +
+
diff --git a/domokits/local/modules/HookCurrency/Config/config.xml b/domokits/local/modules/HookCurrency/Config/config.xml new file mode 100644 index 0000000..1b5deb7 --- /dev/null +++ b/domokits/local/modules/HookCurrency/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookCurrency/Config/module.xml b/domokits/local/modules/HookCurrency/Config/module.xml new file mode 100644 index 0000000..e15a292 --- /dev/null +++ b/domokits/local/modules/HookCurrency/Config/module.xml @@ -0,0 +1,24 @@ + + + HookCurrency\HookCurrency + + Block Currency + + + Bloc Devise + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookCurrency/HookCurrency.php b/domokits/local/modules/HookCurrency/HookCurrency.php new file mode 100644 index 0000000..d321ca3 --- /dev/null +++ b/domokits/local/modules/HookCurrency/HookCurrency.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookCurrency; + +use Thelia\Module\BaseModule; + +class HookCurrency extends BaseModule +{ +} diff --git a/domokits/local/modules/HookCurrency/LICENSE.txt b/domokits/local/modules/HookCurrency/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookCurrency/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookCurrency/composer.json b/domokits/local/modules/HookCurrency/composer.json new file mode 100644 index 0000000..5876794 --- /dev/null +++ b/domokits/local/modules/HookCurrency/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-currency-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookCurrency" + } +} diff --git a/domokits/local/modules/HookCurrency/templates/frontOffice/default/main-navbar-secondary.html b/domokits/local/modules/HookCurrency/templates/frontOffice/default/main-navbar-secondary.html new file mode 100644 index 0000000..0a8faad --- /dev/null +++ b/domokits/local/modules/HookCurrency/templates/frontOffice/default/main-navbar-secondary.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookCustomer/Config/config.xml b/domokits/local/modules/HookCustomer/Config/config.xml new file mode 100644 index 0000000..63a29ce --- /dev/null +++ b/domokits/local/modules/HookCustomer/Config/config.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/domokits/local/modules/HookCustomer/Config/module.xml b/domokits/local/modules/HookCustomer/Config/module.xml new file mode 100644 index 0000000..9d442cd --- /dev/null +++ b/domokits/local/modules/HookCustomer/Config/module.xml @@ -0,0 +1,24 @@ + + + HookCustomer\HookCustomer + + Block Customer + + + Bloc Client + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookCustomer/HookCustomer.php b/domokits/local/modules/HookCustomer/HookCustomer.php new file mode 100644 index 0000000..0f7f8c4 --- /dev/null +++ b/domokits/local/modules/HookCustomer/HookCustomer.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookCustomer; + +use Thelia\Module\BaseModule; + +class HookCustomer extends BaseModule +{ +} diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..91ab712 --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'E-mail Adresse', + 'Forgot your Password?' => 'Haben sir Ihr Passwort vergessen ?', + 'Log In!' => 'Log In!', + 'Log out!' => 'Log out!', + 'My Account' => 'Mein Kundenkonto', + 'Password' => 'Passwort', + 'Register' => 'Registrieren', + 'Register!' => 'Registrieren!', + 'Sign In' => 'Registrieren', +]; diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..bf1b235 --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/en_US.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Email address', + 'Forgot your Password?' => 'Forgot your Password?', + 'Log In!' => 'Log In!', + 'Log out!' => 'Log out!', + 'My Account' => 'My Account', + 'Password' => 'Password', + 'Register' => 'Register', + 'Register!' => 'Register!', + 'Sign In' => 'Sign In', +]; diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..ae76cbe --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Adresse e-mail', + 'Forgot your Password?' => "Mot de passe oublié\u{a0}?", + 'Log In!' => 'Se connecter', + 'Log out!' => 'Se déconnecter', + 'My Account' => 'Mon compte', + 'Password' => 'Mot de passe', + 'Register' => 'S\'inscrire', + 'Register!' => 'Enregistrez-vous !', + 'Sign In' => 'Se connecter', +]; diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..05f1353 --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Indirizzo email', + 'Forgot your Password?' => 'Hai dimenticato la password?', + 'Log In!' => 'Accedi!', + 'Log out!' => 'Esci!', + 'My Account' => 'Mio account', + 'Password' => 'Password', + 'Register' => 'Registrati', + 'Register!' => 'Registrati!', + 'Sign In' => 'Accedi', +]; diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..741d6ea --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Адрес email', + 'Forgot your Password?' => 'Забыли пароль?', + 'Log In!' => 'Вход', + 'Log out!' => 'Выход', + 'My Account' => 'Мой аккаунт', + 'Password' => 'Пароль', + 'Register' => 'Регистрация', + 'Register!' => 'Регистрация', + 'Sign In' => 'Войти', +]; diff --git a/domokits/local/modules/HookCustomer/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..791ffc1 --- /dev/null +++ b/domokits/local/modules/HookCustomer/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Eposta adresi', + 'Forgot your Password?' => 'Parolanızı mı unuttunuz?', + 'Log In!' => 'Oturum aç!', + 'Log out!' => 'Çıkış Yap!', + 'My Account' => 'Hesabım', + 'Password' => 'Parola', + 'Register' => 'Kaydol', + 'Register!' => 'Kayıt ol!', + 'Sign In' => 'Oturum Aç', +]; diff --git a/domokits/local/modules/HookCustomer/LICENSE.txt b/domokits/local/modules/HookCustomer/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookCustomer/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookCustomer/composer.json b/domokits/local/modules/HookCustomer/composer.json new file mode 100644 index 0000000..d081b40 --- /dev/null +++ b/domokits/local/modules/HookCustomer/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-customer-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookCustomer" + } +} diff --git a/domokits/local/modules/HookCustomer/templates/frontOffice/default/assets/css/styles.css b/domokits/local/modules/HookCustomer/templates/frontOffice/default/assets/css/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/domokits/local/modules/HookCustomer/templates/frontOffice/default/main-navbar-secondary.html b/domokits/local/modules/HookCustomer/templates/frontOffice/default/main-navbar-secondary.html new file mode 100644 index 0000000..23884cb --- /dev/null +++ b/domokits/local/modules/HookCustomer/templates/frontOffice/default/main-navbar-secondary.html @@ -0,0 +1,43 @@ + diff --git a/domokits/local/modules/HookLang/Config/config.xml b/domokits/local/modules/HookLang/Config/config.xml new file mode 100644 index 0000000..d30cb54 --- /dev/null +++ b/domokits/local/modules/HookLang/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookLang/Config/module.xml b/domokits/local/modules/HookLang/Config/module.xml new file mode 100644 index 0000000..dec1ec4 --- /dev/null +++ b/domokits/local/modules/HookLang/Config/module.xml @@ -0,0 +1,24 @@ + + + HookLang\HookLang + + Block Languages + + + Bloc langages + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookLang/HookLang.php b/domokits/local/modules/HookLang/HookLang.php new file mode 100644 index 0000000..942251a --- /dev/null +++ b/domokits/local/modules/HookLang/HookLang.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookLang; + +use Thelia\Module\BaseModule; + +class HookLang extends BaseModule +{ +} diff --git a/domokits/local/modules/HookLang/LICENSE.txt b/domokits/local/modules/HookLang/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookLang/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookLang/composer.json b/domokits/local/modules/HookLang/composer.json new file mode 100644 index 0000000..c533864 --- /dev/null +++ b/domokits/local/modules/HookLang/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-lang-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookLang" + } +} diff --git a/domokits/local/modules/HookLang/templates/frontOffice/default/main-navbar-secondary.html b/domokits/local/modules/HookLang/templates/frontOffice/default/main-navbar-secondary.html new file mode 100644 index 0000000..a61a7a1 --- /dev/null +++ b/domokits/local/modules/HookLang/templates/frontOffice/default/main-navbar-secondary.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookLinks/Config/config.xml b/domokits/local/modules/HookLinks/Config/config.xml new file mode 100644 index 0000000..6036b5d --- /dev/null +++ b/domokits/local/modules/HookLinks/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookLinks/Config/module.xml b/domokits/local/modules/HookLinks/Config/module.xml new file mode 100644 index 0000000..1432106 --- /dev/null +++ b/domokits/local/modules/HookLinks/Config/module.xml @@ -0,0 +1,24 @@ + + + HookLinks\HookLinks + + Block Useful links + + + Bloc Liens utiles + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookLinks/Hook/FrontHook.php b/domokits/local/modules/HookLinks/Hook/FrontHook.php new file mode 100644 index 0000000..ae69771 --- /dev/null +++ b/domokits/local/modules/HookLinks/Hook/FrontHook.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookLinks\Hook; + +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume + */ +class FrontHook extends BaseHook +{ + public function onMainFooterBody(HookRenderBlockEvent $event): void + { + $content = trim($this->render('main-footer-body.html')); + if ('' != $content) { + $event->add([ + 'id' => 'links-footer-body', + 'class' => 'default', + 'title' => $this->trans('Useful links', [], 'hooklinks'), + 'content' => $content, + ]); + } + } +} diff --git a/domokits/local/modules/HookLinks/HookLinks.php b/domokits/local/modules/HookLinks/HookLinks.php new file mode 100644 index 0000000..31677b5 --- /dev/null +++ b/domokits/local/modules/HookLinks/HookLinks.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookLinks; + +use Thelia\Module\BaseModule; + +class HookLinks extends BaseModule +{ +} diff --git a/domokits/local/modules/HookLinks/I18n/de_DE.php b/domokits/local/modules/HookLinks/I18n/de_DE.php new file mode 100644 index 0000000..5f92cfe --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Nützliche Links', +]; diff --git a/domokits/local/modules/HookLinks/I18n/en_US.php b/domokits/local/modules/HookLinks/I18n/en_US.php new file mode 100644 index 0000000..cbbd670 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Useful links', +]; diff --git a/domokits/local/modules/HookLinks/I18n/fr_FR.php b/domokits/local/modules/HookLinks/I18n/fr_FR.php new file mode 100644 index 0000000..2495350 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Liens utiles', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..6291da6 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Warenkorb', + 'Checkout' => 'Zur Kasse', + 'Log out!' => 'Log out!', + 'Login' => 'Anmeldung', + 'My Account' => 'Mein Kundenkonto', + 'Register' => 'Registrieren', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..08ef935 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/en_US.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Cart', + 'Checkout' => 'Checkout', + 'Log out!' => 'Log out!', + 'Login' => 'Login', + 'My Account' => 'My Account', + 'Register' => 'Register', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..b0a9707 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Panier', + 'Checkout' => 'Commander', + 'Log out!' => 'Se déconnecter', + 'Login' => 'Connexion', + 'My Account' => 'Mon compte', + 'Register' => 'S\'inscrire', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..0a53f32 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Carrello', + 'Checkout' => 'Procedi all\'acquisto', + 'Log out!' => 'Esci!', + 'Login' => 'Login', + 'My Account' => 'Mio account', + 'Register' => 'Registrati', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..e0a8ca7 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Корзина', + 'Checkout' => 'Оформить заказ', + 'Log out!' => 'Выход', + 'Login' => 'Вход', + 'My Account' => 'Мой аккаунт', + 'Register' => 'Регистрация', +]; diff --git a/domokits/local/modules/HookLinks/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookLinks/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..47986c4 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Cart' => 'Sepet', + 'Checkout' => 'Ödeme yap', + 'Log out!' => 'Çıkış Yap!', + 'Login' => 'Giriş yap', + 'My Account' => 'Hesabım', + 'Register' => 'Kaydol', +]; diff --git a/domokits/local/modules/HookLinks/I18n/it_IT.php b/domokits/local/modules/HookLinks/I18n/it_IT.php new file mode 100644 index 0000000..085177a --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Link utili', +]; diff --git a/domokits/local/modules/HookLinks/I18n/ru_RU.php b/domokits/local/modules/HookLinks/I18n/ru_RU.php new file mode 100644 index 0000000..ca008ad --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Полезные ссылки', +]; diff --git a/domokits/local/modules/HookLinks/I18n/tr_TR.php b/domokits/local/modules/HookLinks/I18n/tr_TR.php new file mode 100644 index 0000000..4895238 --- /dev/null +++ b/domokits/local/modules/HookLinks/I18n/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Useful links' => 'Faydalı Linkler', +]; diff --git a/domokits/local/modules/HookLinks/LICENSE.txt b/domokits/local/modules/HookLinks/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookLinks/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookLinks/composer.json b/domokits/local/modules/HookLinks/composer.json new file mode 100644 index 0000000..23abd78 --- /dev/null +++ b/domokits/local/modules/HookLinks/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-links-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookLinks" + } +} diff --git a/domokits/local/modules/HookLinks/templates/frontOffice/default/main-footer-body.html b/domokits/local/modules/HookLinks/templates/frontOffice/default/main-footer-body.html new file mode 100644 index 0000000..08607f0 --- /dev/null +++ b/domokits/local/modules/HookLinks/templates/frontOffice/default/main-footer-body.html @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookNavigation/Config/config.xml b/domokits/local/modules/HookNavigation/Config/config.xml new file mode 100644 index 0000000..1da4b2b --- /dev/null +++ b/domokits/local/modules/HookNavigation/Config/config.xml @@ -0,0 +1,17 @@ + + + + + +
+ + + + + + + + + + + diff --git a/domokits/local/modules/HookNavigation/Config/module.xml b/domokits/local/modules/HookNavigation/Config/module.xml new file mode 100644 index 0000000..a96cbc3 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Config/module.xml @@ -0,0 +1,24 @@ + + + HookNavigation\HookNavigation + + Block Navigation + + + Bloc Menu + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookNavigation/Config/routing.xml b/domokits/local/modules/HookNavigation/Config/routing.xml new file mode 100644 index 0000000..b8c3028 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Config/routing.xml @@ -0,0 +1,9 @@ + + + + HookNavigation\Controller\HookNavigationConfigController::defaultAction + + + HookNavigation\Controller\HookNavigationConfigController::saveAction + + diff --git a/domokits/local/modules/HookNavigation/Controller/HookNavigationConfigController.php b/domokits/local/modules/HookNavigation/Controller/HookNavigationConfigController.php new file mode 100644 index 0000000..a173791 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Controller/HookNavigationConfigController.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation\Controller; + +use HookNavigation\HookNavigation; +use HookNavigation\Model\Config\HookNavigationConfigValue; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Core\Template\ParserContext; +use Thelia\Core\Translation\Translator; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Tools\URL; + +/** + * Class HookNavigationConfigController. + * + * @author Etienne PERRIERE - OpenStudio + */ +class HookNavigationConfigController extends BaseAdminController +{ + public function defaultAction(Session $session) + { + $bodyConfig = HookNavigation::getConfigValue(HookNavigationConfigValue::FOOTER_BODY_FOLDER_ID); + $bottomConfig = HookNavigation::getConfigValue(HookNavigationConfigValue::FOOTER_BOTTOM_FOLDER_ID); + + $session->getFlashBag()->set('bodyConfig', $bodyConfig ?? ''); + $session->getFlashBag()->set('bottomConfig', $bottomConfig ?? ''); + + return $this->render('hooknavigation-configuration'); + } + + public function saveAction(Request $request, Translator $translator, ParserContext $parserContext) + { + $baseForm = $this->createForm('hooknavigation.configuration'); + + $errorMessage = null; + + $parserContext->set('success', true); + + try { + $form = $this->validateForm($baseForm); + $data = $form->getData(); + + HookNavigation::setConfigValue(HookNavigationConfigValue::FOOTER_BODY_FOLDER_ID, \is_bool($data['footer_body_folder_id']) ? (int) ($data['footer_body_folder_id']) : $data['footer_body_folder_id']); + HookNavigation::setConfigValue(HookNavigationConfigValue::FOOTER_BOTTOM_FOLDER_ID, \is_bool($data['footer_bottom_folder_id']) ? (int) ($data['footer_bottom_folder_id']) : $data['footer_bottom_folder_id']); + + if ($request->get('save_mode') !== 'stay') { + // Redirect to module list + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/modules')); + } + } catch (FormValidationException $ex) { + // Invalid data entered + $errorMessage = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + // Any other error + $errorMessage = $translator->trans( + 'Sorry, an error occurred: %err', + ['%err' => $ex->getMessage()], + HookNavigation::MESSAGE_DOMAIN + ); + } + + if (null !== $errorMessage) { + // Mark the form as with error + $baseForm->setErrorMessage($errorMessage); + + // Send the form and the error to the parser + $parserContext + ->addForm($baseForm) + ->setGeneralError($errorMessage) + ; + } + + return $this->defaultAction($request->getSession()); + } +} diff --git a/domokits/local/modules/HookNavigation/Form/HookNavigationConfigForm.php b/domokits/local/modules/HookNavigation/Form/HookNavigationConfigForm.php new file mode 100644 index 0000000..c955791 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Form/HookNavigationConfigForm.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation\Form; + +use HookNavigation\HookNavigation; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Thelia\Form\BaseForm; + +/** + * Class HookNavigationConfigForm. + * + * @author Etienne PERRIERE - OpenStudio + */ +class HookNavigationConfigForm extends BaseForm +{ + public static function getName() + { + return 'hooknavigation_configuration'; + } + + protected function buildForm(): void + { + $this->formBuilder + ->add( + 'footer_body_folder_id', + NumberType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Folder in footer body', [], HookNavigation::MESSAGE_DOMAIN), + ] + ) + ->add( + 'footer_bottom_folder_id', + NumberType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Folder in footer bottom', [], HookNavigation::MESSAGE_DOMAIN), + ] + ); + } +} diff --git a/domokits/local/modules/HookNavigation/Hook/FrontHook.php b/domokits/local/modules/HookNavigation/Hook/FrontHook.php new file mode 100644 index 0000000..72977d5 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Hook/FrontHook.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation\Hook; + +use HookNavigation\HookNavigation; +use HookNavigation\Model\Config\HookNavigationConfigValue; +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume , Etienne PERRIERE - OpenStudio + */ +class FrontHook extends BaseHook +{ + public function onMainFooterBody(HookRenderBlockEvent $event): void + { + $bodyConfig = HookNavigation::getConfigValue(HookNavigationConfigValue::FOOTER_BODY_FOLDER_ID); + + $content = trim($this->render('main-footer-body.html', ['bodyFolderId' => $bodyConfig])); + if ('' !== $content) { + $event->add([ + 'id' => 'navigation-footer-body', + 'class' => 'links', + 'title' => $this->trans('Latest articles', [], HookNavigation::MESSAGE_DOMAIN), + 'content' => $content, + ]); + } + } + + public function onMainFooterBottom(HookRenderEvent $event): void + { + $bottomConfig = HookNavigation::getConfigValue(HookNavigationConfigValue::FOOTER_BOTTOM_FOLDER_ID); + + $content = $this->render('main-footer-bottom.html', ['bottomFolderId' => $bottomConfig]); + $event->add($content); + } +} diff --git a/domokits/local/modules/HookNavigation/HookNavigation.php b/domokits/local/modules/HookNavigation/HookNavigation.php new file mode 100644 index 0000000..8abc3d7 --- /dev/null +++ b/domokits/local/modules/HookNavigation/HookNavigation.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; + +/** + * Class HookNavigation. + */ +class HookNavigation extends BaseModule +{ + public const MESSAGE_DOMAIN = 'hooknavigation'; + public const ROUTER = 'router.hooknavigation'; + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/de_DE.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..3c7270e --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/de_DE.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Kategorien', + 'Folder in footer body' => 'Ordner in Fußzeile', + 'Folder in footer bottom' => 'Ordner in Fußzeile', + 'Home' => 'Startseite', + 'HookNavigation configuration' => 'HookNavigation Konfiguration', + 'No articles currently' => 'Zur Zeit keine Artikel', + 'Toggle navigation' => 'Navigation umschalten', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/en_US.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..1322a48 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/en_US.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Configuration correctly saved' => 'Configuration correctly saved', + 'Configure hooknavigation' => 'Configure hooknavigation', + 'Home' => 'Home', + 'HookNavigation configuration' => 'HookNavigation configuration', + 'Modules' => 'Modules', + 'Select a folder' => 'Select a folder', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..97ecd9a --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Configuration correctly saved' => 'Configuration sauvegardée correctement', + 'Configure hooknavigation' => 'Configurer Bloc Menu', + 'Home' => 'Accueil', + 'HookNavigation configuration' => 'Configuration de Block Menu', + 'Modules' => 'Modules', + 'Select a folder' => 'Sélectionner un dossier', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/it_IT.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/it_IT.php new file mode 100644 index 0000000..477c029 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/it_IT.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Home' => 'Home', + 'Modules' => 'Moduli', + 'Select a folder' => 'Seleziona una cartella', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/ru_RU.php new file mode 100644 index 0000000..b04226e --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Configuration correctly saved' => 'Конфигурация успешно сохранена', + 'Configure hooknavigation' => 'Настройка HookNavigation', + 'Home' => 'Главная', + 'HookNavigation configuration' => 'Конфигурация HookNavigation', + 'Modules' => 'Модули', + 'Select a folder' => 'Выберите папку', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/HookNavigation/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..e39ec6c --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Katogoriler', + 'Folder in footer body' => 'Altbilgi vücut klasöründe', + 'Folder in footer bottom' => 'Altbilgi alt klasöründe', + 'Home' => 'Ana sayfa', + 'HookNavigation configuration' => 'HookNavigation yapılandırma', + 'No articles currently' => 'Hiç makale yok', + 'Toggle navigation' => 'Navigasyonu değiştir', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/en_US.php b/domokits/local/modules/HookNavigation/I18n/en_US.php new file mode 100644 index 0000000..d7ffbc2 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/en_US.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Folder in footer body' => 'Folder in footer body', + 'Folder in footer bottom' => 'Folder in footer bottom', + 'Latest articles' => 'Latest articles', + 'Sorry, an error occurred: %err' => 'Sorry, an error occurred: %err', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/fr_FR.php b/domokits/local/modules/HookNavigation/I18n/fr_FR.php new file mode 100644 index 0000000..8a1693d --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Folder in footer body' => 'Dossier du pied de page', + 'Folder in footer bottom' => 'Dossier sous le pied de page', + 'Latest articles' => 'Derniers articles', + 'Sorry, an error occurred: %err' => 'Désolé, une erreur est survenue: %err', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..199e3d2 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Latest articles' => 'Neueste Artikel', + 'No articles currently' => 'Zur Zeit keine Artikel', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..dfbcf23 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/en_US.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Categories', + 'Home' => 'Home', + 'No articles currently' => 'No articles currently', + 'Toggle navigation' => 'Toggle navigation', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..16ea044 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Rubriques', + 'Home' => 'Accueil', + 'No articles currently' => 'Aucun article pour le moment', + 'Toggle navigation' => 'Basculer la navigation', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..237c7f6 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Categorie', + 'Home' => 'Home', + 'No articles currently' => 'Attualmente non sono presenti articoli', + 'Toggle navigation' => 'Toggle navigation', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..e97a034 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Categories' => 'Категории', + 'Home' => 'Главная', + 'No articles currently' => 'Пока статей нет', + 'Toggle navigation' => 'Переключить навигацию', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..99cb89a --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Latest articles' => 'Son Makaleler', + 'No articles currently' => 'Hiç makale yok', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/it_IT.php b/domokits/local/modules/HookNavigation/I18n/it_IT.php new file mode 100644 index 0000000..dfe4d71 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Latest articles' => 'Ultimi articoli', +]; diff --git a/domokits/local/modules/HookNavigation/I18n/ru_RU.php b/domokits/local/modules/HookNavigation/I18n/ru_RU.php new file mode 100644 index 0000000..875a445 --- /dev/null +++ b/domokits/local/modules/HookNavigation/I18n/ru_RU.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Folder in footer body' => 'Папка внизу страницы', + 'Folder in footer bottom' => 'Папка в подвале страницы', + 'Latest articles' => 'Последние статьи', + 'Sorry, an error occurred: %err' => 'К сожалению произошла ошибка: %err', +]; diff --git a/domokits/local/modules/HookNavigation/LICENSE.txt b/domokits/local/modules/HookNavigation/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookNavigation/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookNavigation/Model/Config/Base/HookNavigationConfigValue.php b/domokits/local/modules/HookNavigation/Model/Config/Base/HookNavigationConfigValue.php new file mode 100644 index 0000000..bf2a659 --- /dev/null +++ b/domokits/local/modules/HookNavigation/Model/Config/Base/HookNavigationConfigValue.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation\Model\Config\Base; + +/** + * Class HookNavigationConfigValue. + */ +class HookNavigationConfigValue +{ + public const FOOTER_BODY_FOLDER_ID = 'footer_body_folder_id'; + public const FOOTER_BOTTOM_FOLDER_ID = 'footer_bottom_folder_id'; +} diff --git a/domokits/local/modules/HookNavigation/Model/Config/HookNavigationConfigValue.php b/domokits/local/modules/HookNavigation/Model/Config/HookNavigationConfigValue.php new file mode 100644 index 0000000..74db14a --- /dev/null +++ b/domokits/local/modules/HookNavigation/Model/Config/HookNavigationConfigValue.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNavigation\Model\Config; + +use HookNavigation\Model\Config\Base\HookNavigationConfigValue as BaseHookNavigationConfigValue; + +/** + * Class HookNavigationConfigValue. + */ +class HookNavigationConfigValue extends BaseHookNavigationConfigValue +{ +} diff --git a/domokits/local/modules/HookNavigation/composer.json b/domokits/local/modules/HookNavigation/composer.json new file mode 100644 index 0000000..0ccb0ca --- /dev/null +++ b/domokits/local/modules/HookNavigation/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-navigation-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookNavigation" + } +} diff --git a/domokits/local/modules/HookNavigation/templates/backOffice/default/hooknavigation-configuration.html b/domokits/local/modules/HookNavigation/templates/backOffice/default/hooknavigation-configuration.html new file mode 100644 index 0000000..871c43d --- /dev/null +++ b/domokits/local/modules/HookNavigation/templates/backOffice/default/hooknavigation-configuration.html @@ -0,0 +1,116 @@ +{extends file="admin-layout.tpl"} + +{block name="no-return-functions"} + {$admin_current_location = 'modules'} +{/block} + +{block name="page-title"}{intl d="hooknavigation.bo.default" l='HookNavigation configuration'}{/block} + +{block name="check-resource"}admin.module{/block} +{block name="check-access"}view{/block} +{block name="check-module"}HookNavigation{/block} + +{block name="main-content"} +
+ + +
+
+ {intl l="Configure hooknavigation" d="hooknavigation.bo.default"} +
+ +
+
+ {if $success|default:false} +
+ {intl l="Configuration correctly saved" d="hooknavigation.bo.default"} +
+ {/if} + + {form name="hooknavigation.configuration"} + + {include "includes/inner-form-toolbar.html" hide_flags=1 close_url={url path='/admin/modules'}} +
+ + {form_field form=$form field="success_url"} + + {/form_field} + + {form_hidden_fields form=$form} + + {flash type="bodyConfig"} + {assign var='bodyConfig' value=$MESSAGE} + {/flash} + {flash type="bottomConfig"} + {assign var='bottomConfig' value=$MESSAGE} + {/flash} + + {form_field form=$form field="footer_body_folder_id"} +
+ + + + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="footer_bottom_folder_id"} +
+ + + + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {include "includes/inner-form-toolbar.html" hide_flags=1 close_url={url path='/admin/modules'} page_bottom=1} + + {/form} +
+
+
+
+{/block} + +{block name="javascript-initialization"} +{/block} diff --git a/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-body.html b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-body.html new file mode 100644 index 0000000..4834c61 --- /dev/null +++ b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-body.html @@ -0,0 +1,17 @@ +{ifloop rel="blog.articles"} + +{/ifloop} +{elseloop rel="blog.articles"} +
    +
  • {intl l="No articles currently" d="hooknavigation.fo.default"}
  • +
+{/elseloop} \ No newline at end of file diff --git a/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-bottom.html b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-bottom.html new file mode 100644 index 0000000..05c8047 --- /dev/null +++ b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-footer-bottom.html @@ -0,0 +1,7 @@ + diff --git a/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-navbar-primary.html b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-navbar-primary.html new file mode 100644 index 0000000..6251461 --- /dev/null +++ b/domokits/local/modules/HookNavigation/templates/frontOffice/default/main-navbar-primary.html @@ -0,0 +1,56 @@ + + +{* classic navbar without dropdown + +*} \ No newline at end of file diff --git a/domokits/local/modules/HookNewsletter/Config/config.xml b/domokits/local/modules/HookNewsletter/Config/config.xml new file mode 100644 index 0000000..9d66a2f --- /dev/null +++ b/domokits/local/modules/HookNewsletter/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookNewsletter/Config/module.xml b/domokits/local/modules/HookNewsletter/Config/module.xml new file mode 100644 index 0000000..2bb1f44 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/Config/module.xml @@ -0,0 +1,24 @@ + + + HookNewsletter\HookNewsletter + + Block Newsletter + + + Bloc Newsletter + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookNewsletter/Hook/FrontHook.php b/domokits/local/modules/HookNewsletter/Hook/FrontHook.php new file mode 100644 index 0000000..47a41e6 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/Hook/FrontHook.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNewsletter\Hook; + +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume + */ +class FrontHook extends BaseHook +{ + public function onMainFooterBody(HookRenderBlockEvent $event): void + { + $content = trim($this->render('main-footer-body.html')); + if ('' != $content) { + $event->add([ + 'id' => 'newsletter-footer-body', + 'class' => 'newsletter', + 'title' => $this->trans('Newsletter', [], 'hooknewsletter'), + 'content' => $content, + ]); + } + } +} diff --git a/domokits/local/modules/HookNewsletter/HookNewsletter.php b/domokits/local/modules/HookNewsletter/HookNewsletter.php new file mode 100644 index 0000000..3bf0444 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/HookNewsletter.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookNewsletter; + +use Thelia\Module\BaseModule; + +class HookNewsletter extends BaseModule +{ +} diff --git a/domokits/local/modules/HookNewsletter/I18n/de_DE.php b/domokits/local/modules/HookNewsletter/I18n/de_DE.php new file mode 100644 index 0000000..4fbbce0 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'Newsletter', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/en_US.php b/domokits/local/modules/HookNewsletter/I18n/en_US.php new file mode 100755 index 0000000..4fbbce0 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'Newsletter', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/fr_FR.php b/domokits/local/modules/HookNewsletter/I18n/fr_FR.php new file mode 100755 index 0000000..2895c2d --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'Lettre d\'information', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..6d0e6a5 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'E-mail Adresse', + 'Sign up to receive our latest news.' => 'Abonnieren Sie unseren Newsletter.', + 'Subscribe' => 'Abonnieren', + 'Your email address' => 'Ihre E-Mail-Adresse', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..261b546 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/en_US.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Email address', + 'Sign up to receive our latest news.' => 'Sign up to receive our latest news.', + 'Subscribe' => 'Subscribe', + 'Your email address' => 'Your email address', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..cbd671c --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Adresse e-mail', + 'Sign up to receive our latest news.' => 'Enregistrez vous pour recevoir nos dernières nouvelles.', + 'Subscribe' => 'Inscription', + 'Your email address' => 'Votre adresse email', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..27f1570 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Indirizzo email', + 'Subscribe' => 'Abbonati', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..0878ec9 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'E-mail адрес', + 'Sign up to receive our latest news.' => 'Подпишитесь для получения новостей от нас', + 'Subscribe' => 'Подписаться', + 'Your email address' => 'Ваш email адрес', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..46f52f9 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Email address' => 'Eposta adresi', + 'Sign up to receive our latest news.' => 'En yeni haberleri almak için kaydolun.', + 'Subscribe' => 'Abone Ol', + 'Your email address' => 'E-posta adresiniz', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/it_IT.php b/domokits/local/modules/HookNewsletter/I18n/it_IT.php new file mode 100644 index 0000000..4fbbce0 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'Newsletter', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/ru_RU.php b/domokits/local/modules/HookNewsletter/I18n/ru_RU.php new file mode 100755 index 0000000..127244d --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'Подписка', +]; diff --git a/domokits/local/modules/HookNewsletter/I18n/tr_TR.php b/domokits/local/modules/HookNewsletter/I18n/tr_TR.php new file mode 100644 index 0000000..cd4dfce --- /dev/null +++ b/domokits/local/modules/HookNewsletter/I18n/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Newsletter' => 'E-Bülten', +]; diff --git a/domokits/local/modules/HookNewsletter/LICENSE.txt b/domokits/local/modules/HookNewsletter/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookNewsletter/composer.json b/domokits/local/modules/HookNewsletter/composer.json new file mode 100644 index 0000000..230b69d --- /dev/null +++ b/domokits/local/modules/HookNewsletter/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-newsletter-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookNewsletter" + } +} diff --git a/domokits/local/modules/HookNewsletter/templates/frontOffice/default/main-footer-body.html b/domokits/local/modules/HookNewsletter/templates/frontOffice/default/main-footer-body.html new file mode 100644 index 0000000..1249959 --- /dev/null +++ b/domokits/local/modules/HookNewsletter/templates/frontOffice/default/main-footer-body.html @@ -0,0 +1,13 @@ +

{intl l="Sign up to receive our latest news." d="hooknewsletter.fo.default"}

+{form name="thelia.front.newsletter"} +
+{form_hidden_fields} +{form_field field="email"} +
+ + +
+{/form_field} + +
+{/form} diff --git a/domokits/local/modules/HookProductsNew/Config/config.xml b/domokits/local/modules/HookProductsNew/Config/config.xml new file mode 100644 index 0000000..42df653 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookProductsNew/Config/module.xml b/domokits/local/modules/HookProductsNew/Config/module.xml new file mode 100644 index 0000000..abe77b3 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/Config/module.xml @@ -0,0 +1,24 @@ + + + HookProductsNew\HookProductsNew + + Block New Products + + + Bloc Nouveaux Produits + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookProductsNew/HookProductsNew.php b/domokits/local/modules/HookProductsNew/HookProductsNew.php new file mode 100644 index 0000000..e764f49 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/HookProductsNew.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookProductsNew; + +use Thelia\Module\BaseModule; + +class HookProductsNew extends BaseModule +{ +} diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..93af348 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Alle anzeigen', + 'Latest' => 'Neuigkeiten', +]; diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..2630a45 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/en_US.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ View All', + 'Latest' => 'Latest', +]; diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..c78e30b --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Tout voir', + 'Latest' => 'Nouveautés', +]; diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..030c627 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Mostra tutto', + 'Latest' => 'Ultimi', +]; diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..7c1bfb4 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Смотреть все', + 'Latest' => 'Новые', +]; diff --git a/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..f6e4bb6 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Hepsini gör', + 'Latest' => 'En son', +]; diff --git a/domokits/local/modules/HookProductsNew/LICENSE.txt b/domokits/local/modules/HookProductsNew/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookProductsNew/composer.json b/domokits/local/modules/HookProductsNew/composer.json new file mode 100644 index 0000000..3757392 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-products-new-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookProductsNew" + } +} diff --git a/domokits/local/modules/HookProductsNew/templates/frontOffice/default/home-body.html b/domokits/local/modules/HookProductsNew/templates/frontOffice/default/home-body.html new file mode 100644 index 0000000..11f6004 --- /dev/null +++ b/domokits/local/modules/HookProductsNew/templates/frontOffice/default/home-body.html @@ -0,0 +1,59 @@ +{ifloop rel="product_new"} +
+
+

{intl l="Latest" d="hookproductsnew.fo.default"} {intl l="+ View All" d="hookproductsnew.fo.default"}

+
+
+ +
+
+{/ifloop} diff --git a/domokits/local/modules/HookProductsOffer/Config/config.xml b/domokits/local/modules/HookProductsOffer/Config/config.xml new file mode 100644 index 0000000..00e4ebb --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/HookProductsOffer/Config/module.xml b/domokits/local/modules/HookProductsOffer/Config/module.xml new file mode 100644 index 0000000..6ee97b0 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/Config/module.xml @@ -0,0 +1,24 @@ + + + HookProductsOffer\HookProductsOffer + + Block Promo Products + + + Bloc Produits en promo + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookProductsOffer/HookProductsOffer.php b/domokits/local/modules/HookProductsOffer/HookProductsOffer.php new file mode 100644 index 0000000..85ade35 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/HookProductsOffer.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookProductsOffer; + +use Thelia\Module\BaseModule; + +class HookProductsOffer extends BaseModule +{ +} diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..5b64193 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Alle sehen', + 'Offers' => 'Angebote', +]; diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..2bea270 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/en_US.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ View All', + 'Offers' => 'Offers', +]; diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..b6ac60e --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Tout voir', + 'Offers' => 'Promotions', +]; diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..dee3d68 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Mostra tutto', + 'Offers' => 'Offerte', +]; diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..5052d1a --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Смотреть все', + 'Offers' => 'Предложения', +]; diff --git a/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..8ddc8ad --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + '+ View All' => '+ Hepsini gör', + 'Offers' => 'Teklifler', +]; diff --git a/domokits/local/modules/HookProductsOffer/LICENSE.txt b/domokits/local/modules/HookProductsOffer/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookProductsOffer/composer.json b/domokits/local/modules/HookProductsOffer/composer.json new file mode 100644 index 0000000..8329abd --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-products-offer-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookProductsOffer" + } +} diff --git a/domokits/local/modules/HookProductsOffer/templates/frontOffice/default/home-body.html b/domokits/local/modules/HookProductsOffer/templates/frontOffice/default/home-body.html new file mode 100644 index 0000000..462e775 --- /dev/null +++ b/domokits/local/modules/HookProductsOffer/templates/frontOffice/default/home-body.html @@ -0,0 +1,39 @@ +{ifloop rel="current-sales"} +
+ {loop name="current-sales" type="sale" limit="2"} +
+ + +
+
    + {loop name="products_in_sale" type="product" limit="4" sale=$ID} + {include file="includes/single-product.html" colClass="col-md-3 col-sm-4" product_id=$ID hasBtn=false hasDescription=false width="218" height="146"} + {/loop} +
+
+
+ {/loop} +
+{/ifloop} +{* Display "regular" promos, if any, only if we don't have active sales *} + +{elseloop rel="current-sales"} +{ifloop rel="product_promo"} +
+
+

{intl l="Offers" d="hookproductsoffer.fo.default"} {intl l="+ View All" d="hookproductsoffer.fo.default"}

+
+ +
+
    + {loop name="product_promo" type="product" limit="4" promo="yes"} + {include file="includes/single-product.html" colClass="col-md-3 col-sm-4" product_id=$ID hasBtn=false hasDescription=false width="218" height="146"} + {/loop} +
+
+
+{/ifloop} +{/elseloop} diff --git a/domokits/local/modules/HookSearch/Config/config.xml b/domokits/local/modules/HookSearch/Config/config.xml new file mode 100644 index 0000000..b5d60c6 --- /dev/null +++ b/domokits/local/modules/HookSearch/Config/config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/domokits/local/modules/HookSearch/Config/module.xml b/domokits/local/modules/HookSearch/Config/module.xml new file mode 100644 index 0000000..3a915ce --- /dev/null +++ b/domokits/local/modules/HookSearch/Config/module.xml @@ -0,0 +1,24 @@ + + + HookSearch\HookSearch + + Block Search + + + Bloc Recherche + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookSearch/HookSearch.php b/domokits/local/modules/HookSearch/HookSearch.php new file mode 100644 index 0000000..657cb1e --- /dev/null +++ b/domokits/local/modules/HookSearch/HookSearch.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookSearch; + +use Thelia\Module\BaseModule; + +class HookSearch extends BaseModule +{ +} diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..4a04d27 --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => 'Mindestens 2 Zeichen.', + 'Search' => 'Suchen', + 'Search a product' => 'Ein Produkt suchen', + 'Search...' => 'Suchen ...', +]; diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..cbf6af0 --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/en_US.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => 'Minimum 2 characters.', + 'Search' => 'Search', + 'Search a product' => 'Search a product', + 'Search...' => 'Search...', +]; diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..8a3c91c --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => '2 caractères minimum.', + 'Search' => 'Recherche', + 'Search a product' => 'Rechercher un produit', + 'Search...' => 'Rechercher...', +]; diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..a99d65d --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => 'Minimo 2 caratteri.', + 'Search' => 'Ricerca', + 'Search a product' => 'Ricerca un prodotto', + 'Search...' => 'Ricerca...', +]; diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/ru_RU.php new file mode 100644 index 0000000..b5d1754 --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => 'Минимум 2 символа.', + 'Search' => 'Поиск', + 'Search a product' => 'Поиск товара', + 'Search...' => 'Поиск...', +]; diff --git a/domokits/local/modules/HookSearch/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookSearch/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..ab844fd --- /dev/null +++ b/domokits/local/modules/HookSearch/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Minimum 2 characters.' => 'En az 2 karakter.', + 'Search' => 'Arama', + 'Search a product' => 'Ürün ara', + 'Search...' => 'Arama...', +]; diff --git a/domokits/local/modules/HookSearch/LICENSE.txt b/domokits/local/modules/HookSearch/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookSearch/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookSearch/composer.json b/domokits/local/modules/HookSearch/composer.json new file mode 100644 index 0000000..9dfdcaf --- /dev/null +++ b/domokits/local/modules/HookSearch/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-search-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookSearch" + } +} diff --git a/domokits/local/modules/HookSearch/templates/frontOffice/default/assets/css/styles.css b/domokits/local/modules/HookSearch/templates/frontOffice/default/assets/css/styles.css new file mode 100644 index 0000000..74b1839 --- /dev/null +++ b/domokits/local/modules/HookSearch/templates/frontOffice/default/assets/css/styles.css @@ -0,0 +1,11 @@ +.header-container .search-container label, +.header-container .search-container .btn-search>span { + position:absolute; + width:1px; + height:1px; + margin:-1px; + padding:0; + overflow:hidden; + clip:rect(0 0 0 0); + border:0 +} \ No newline at end of file diff --git a/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-primary.html b/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-primary.html new file mode 100644 index 0000000..31c6afd --- /dev/null +++ b/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-primary.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-secondary.html b/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-secondary.html new file mode 100644 index 0000000..40ba03a --- /dev/null +++ b/domokits/local/modules/HookSearch/templates/frontOffice/default/main-navbar-secondary.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/domokits/local/modules/HookSocial/Config/config.xml b/domokits/local/modules/HookSocial/Config/config.xml new file mode 100644 index 0000000..f151f07 --- /dev/null +++ b/domokits/local/modules/HookSocial/Config/config.xml @@ -0,0 +1,21 @@ + + + + + +
+ + + + + + + + + + + + + diff --git a/domokits/local/modules/HookSocial/Config/module.xml b/domokits/local/modules/HookSocial/Config/module.xml new file mode 100644 index 0000000..867247c --- /dev/null +++ b/domokits/local/modules/HookSocial/Config/module.xml @@ -0,0 +1,24 @@ + + + HookSocial\HookSocial + + Block Social + + + Bloc Social + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/HookSocial/Config/routing.xml b/domokits/local/modules/HookSocial/Config/routing.xml new file mode 100644 index 0000000..769a2c4 --- /dev/null +++ b/domokits/local/modules/HookSocial/Config/routing.xml @@ -0,0 +1,10 @@ + + + + + HookSocial\Controller\Configuration::saveAction + + + diff --git a/domokits/local/modules/HookSocial/Controller/Configuration.php b/domokits/local/modules/HookSocial/Controller/Configuration.php new file mode 100644 index 0000000..7966457 --- /dev/null +++ b/domokits/local/modules/HookSocial/Controller/Configuration.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookSocial\Controller; + +use Symfony\Component\HttpFoundation\JsonResponse; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Log\Tlog; +use Thelia\Model\ConfigQuery; + +/** + * Class Configuration. + * + * @author Julien Chanséaume + */ +class Configuration extends BaseAdminController +{ + public function saveAction() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], ['hooksocial'], AccessManager::UPDATE)) { + return $response; + } + + $form = $this->createForm(\HookSocial\Form\Configuration::class); + $resp = [ + 'error' => 0, + 'message' => '', + ]; + $response = null; + + try { + $vform = $this->validateForm($form); + $data = $vform->getData(); + + foreach ($data as $name => $value) { + if (!$form->isTemplateDefinedHiddenFieldName($name)) { + ConfigQuery::write('hooksocial_'.$name, $value, false, true); + } + + Tlog::getInstance()->debug(sprintf('%s => %s', $name, $value)); + } + } catch (\Exception $e) { + $resp['error'] = 1; + $resp['message'] = $e->getMessage(); + } + + return new JsonResponse($resp); + } +} diff --git a/domokits/local/modules/HookSocial/Form/Configuration.php b/domokits/local/modules/HookSocial/Form/Configuration.php new file mode 100644 index 0000000..65c48e5 --- /dev/null +++ b/domokits/local/modules/HookSocial/Form/Configuration.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookSocial\Form; + +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; +use Thelia\Model\ConfigQuery; + +/** + * Class Configuration. + * + * @author Julien Chanséaume + */ +class Configuration extends BaseForm +{ + protected function buildForm(): void + { + $form = $this->formBuilder; + + $definitions = [ + [ + 'id' => 'twitter', + 'label' => Translator::getInstance()->trans('Twitter username', [], 'hooksocial'), + ], + [ + 'id' => 'facebook', + 'label' => Translator::getInstance()->trans('Facebook username', [], 'hooksocial'), + ], + [ + 'id' => 'google', + 'label' => Translator::getInstance()->trans('Google + username', [], 'hooksocial'), + ], + [ + 'id' => 'instagram', + 'label' => Translator::getInstance()->trans('Instagram username', [], 'hooksocial'), + ], + [ + 'id' => 'pinterest', + 'label' => Translator::getInstance()->trans('Pinterest username', [], 'hooksocial'), + ], + [ + 'id' => 'youtube', + 'label' => Translator::getInstance()->trans('Youtube URL', [], 'hooksocial'), + ], + [ + 'id' => 'rss', + 'label' => Translator::getInstance()->trans('RSS URL', [], 'hooksocial'), + ], + ]; + + foreach ($definitions as $field) { + $value = ConfigQuery::read('hooksocial_'.$field['id'], ''); + $form->add( + $field['id'], + TextType::class, + [ + 'data' => $value, + 'label' => $field['label'], + 'label_attr' => [ + 'for' => $field['id'], + ], + ] + ); + } + } + + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return 'hooksocial'; + } +} diff --git a/domokits/local/modules/HookSocial/Hook/FrontHook.php b/domokits/local/modules/HookSocial/Hook/FrontHook.php new file mode 100644 index 0000000..c284f2c --- /dev/null +++ b/domokits/local/modules/HookSocial/Hook/FrontHook.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookSocial\Hook; + +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class FrontHook. + * + * @author Julien Chanséaume + */ +class FrontHook extends BaseHook +{ + public function onMainFooterBody(HookRenderBlockEvent $event): void + { + $content = trim($this->render('main-footer-body.html')); + if ('' != $content) { + $event->add([ + 'id' => 'social-footer-body', + 'class' => 'social', + 'title' => $this->trans('Follow us', [], 'hooksocial'), + 'content' => $content, + ]); + } + } +} diff --git a/domokits/local/modules/HookSocial/HookSocial.php b/domokits/local/modules/HookSocial/HookSocial.php new file mode 100644 index 0000000..e615459 --- /dev/null +++ b/domokits/local/modules/HookSocial/HookSocial.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace HookSocial; + +use Thelia\Module\BaseModule; + +class HookSocial extends BaseModule +{ +} diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/de_DE.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..94582e3 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/de_DE.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Ein Fehler ist aufgetreten', + 'Save' => 'Speichern', +]; diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/en_US.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/en_US.php new file mode 100755 index 0000000..0f1fc7d --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/en_US.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'An error occured', + 'Edit your social accounts.' => 'Edit your social accounts.', + 'Save' => 'Save', +]; diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..7fd0d30 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Une erreur est survenue', + 'Edit your social accounts.' => 'Modifier vos paramètres de réseaux sociaux.', + 'Save' => ' Enregistrer', +]; diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/it_IT.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/it_IT.php new file mode 100644 index 0000000..c4c1edc --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/it_IT.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Edit your social accounts.' => 'Modifica i tuoi account social.', + 'Save' => 'Salvare', +]; diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/ru_RU.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/ru_RU.php new file mode 100755 index 0000000..f2def80 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/ru_RU.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Произошла ошибка', + 'Edit your social accounts.' => 'Редактировать ваши социальные аккаунты.', + 'Save' => 'Сохранить', +]; diff --git a/domokits/local/modules/HookSocial/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/HookSocial/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..98a4654 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'An error occured' => 'Bir hata meydana geldi', + 'Edit your social accounts.' => 'Sosyal hesaplarınızı düzenleyin.', + 'Save' => 'kaydet', +]; diff --git a/domokits/local/modules/HookSocial/I18n/de_DE.php b/domokits/local/modules/HookSocial/I18n/de_DE.php new file mode 100644 index 0000000..53be417 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/de_DE.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Facebook Benutzername', + 'Follow us' => 'Folgen Sie uns', + 'Google + username' => 'Google+ Benutzername', + 'Instagram username' => 'Instagram Benutzername', + 'Pinterest username' => 'Pinterest Benutzername', + 'RSS URL' => 'RSS-URL', + 'Twitter username' => 'Twitter Benutzername', + 'Youtube URL' => 'YouTube-URL', +]; diff --git a/domokits/local/modules/HookSocial/I18n/en_US.php b/domokits/local/modules/HookSocial/I18n/en_US.php new file mode 100755 index 0000000..1752f26 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/en_US.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Facebook username', + 'Follow us' => 'Follow us', + 'Google + username' => 'Google + username', + 'Instagram username' => 'Instagram username', + 'Pinterest username' => 'Pinterest username', + 'RSS URL' => 'RSS URL', + 'Twitter username' => 'Twitter username', + 'Youtube URL' => 'Youtube URL', +]; diff --git a/domokits/local/modules/HookSocial/I18n/fr_FR.php b/domokits/local/modules/HookSocial/I18n/fr_FR.php new file mode 100755 index 0000000..dc7db56 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/fr_FR.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Nom d\'utilisateur Facebook', + 'Follow us' => 'Suivez-nous', + 'Google + username' => 'Nom d\'utilisateur Google +', + 'Instagram username' => 'Nom d\'utilisateur Instagram', + 'Pinterest username' => 'Nom d\'utilisateur Pinterest', + 'RSS URL' => 'URL du flux RSS', + 'Twitter username' => 'Nom d\'utilisateur Twitter', + 'Youtube URL' => 'URL Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..12b828e --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS-Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'YouTube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/en_US.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..7ca6666 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/en_US.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..74465e0 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'RSS' => 'Flux RSS', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..b089829 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google +', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Feed', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..defbbbe --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google+', + 'Instagram' => 'Instagram', + 'Pinterest' => 'Pinterest', + 'RSS' => 'RSS-канал', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/HookSocial/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..351bff5 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook' => 'Facebook', + 'Google+' => 'Google +', + 'Instagram' => 'Instagram', + 'RSS' => 'RSS Beslemesi', + 'Twitter' => 'Twitter', + 'Youtube' => 'Youtube', +]; diff --git a/domokits/local/modules/HookSocial/I18n/it_IT.php b/domokits/local/modules/HookSocial/I18n/it_IT.php new file mode 100644 index 0000000..c652329 --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/it_IT.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Nome utente Facebook', + 'Follow us' => 'Seguici', + 'Google + username' => 'Nome utente Google +', + 'Instagram username' => 'Nome utente Instagram', + 'Pinterest username' => 'Nome utente Pinterest', + 'RSS URL' => 'RSS URL', + 'Twitter username' => 'Nome utente Twitter', + 'Youtube URL' => 'Youtube URL', +]; diff --git a/domokits/local/modules/HookSocial/I18n/ru_RU.php b/domokits/local/modules/HookSocial/I18n/ru_RU.php new file mode 100755 index 0000000..2430ffc --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/ru_RU.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Имя пользователя Facebook', + 'Follow us' => 'Мы в соц сетях', + 'Google + username' => 'Имя пользователя Google +', + 'Instagram username' => 'Имя пользователя Instagram', + 'Pinterest username' => 'Имя пользователя Pinterest', + 'RSS URL' => 'RSS URL', + 'Twitter username' => 'Имя пользователя Twitter', + 'Youtube URL' => 'Youtube URL', +]; diff --git a/domokits/local/modules/HookSocial/I18n/tr_TR.php b/domokits/local/modules/HookSocial/I18n/tr_TR.php new file mode 100644 index 0000000..88310ac --- /dev/null +++ b/domokits/local/modules/HookSocial/I18n/tr_TR.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Facebook username' => 'Facebook kullanıcı adı', + 'Follow us' => 'Bizi takip edin', + 'Google + username' => 'Google + kullanıcı adı', + 'Instagram username' => 'Google + kullanıcı adı', + 'Pinterest username' => 'Pinterest kullanıcı adı', + 'RSS URL' => 'RSS URL', + 'Twitter username' => 'Twitter kullanıcı adı', + 'Youtube URL' => 'YouTube URL', +]; diff --git a/domokits/local/modules/HookSocial/LICENSE.txt b/domokits/local/modules/HookSocial/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/HookSocial/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/HookSocial/composer.json b/domokits/local/modules/HookSocial/composer.json new file mode 100644 index 0000000..4a18288 --- /dev/null +++ b/domokits/local/modules/HookSocial/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/hook-social-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "HookSocial" + } +} diff --git a/domokits/local/modules/HookSocial/templates/backOffice/default/assets/js/module-configuration.js b/domokits/local/modules/HookSocial/templates/backOffice/default/assets/js/module-configuration.js new file mode 100644 index 0000000..5bf3dfc --- /dev/null +++ b/domokits/local/modules/HookSocial/templates/backOffice/default/assets/js/module-configuration.js @@ -0,0 +1,28 @@ +$(document).ready(function() { + $("#hooksocial-form").on("submit", function(e, data){ + e.preventDefault(); + var form = $(this); + + $('body').append(''); + + $.ajax({ + url: form.attr('action'), + type: form.attr('method'), + data: form.serialize() + }).done(function(){ + $("#loading-event").remove(); + }) + .success(function(data) { + if (data.error != 0) { + $("#loading-event").remove(); + $('#hooksocial-failed-body').html(data.message); + $("#hooksocial-failed").modal("show"); + } + }) + .fail(function(jqXHR, textStatus, errorThrown){ + $("#loading-event").remove(); + $('#hooksocial-failed-body').html(jqXHR.responseJSON.message); + $("#hooksocial-failed").modal("show"); + }); + }); +}); \ No newline at end of file diff --git a/domokits/local/modules/HookSocial/templates/backOffice/default/module_configuration.html b/domokits/local/modules/HookSocial/templates/backOffice/default/module_configuration.html new file mode 100755 index 0000000..37f46c7 --- /dev/null +++ b/domokits/local/modules/HookSocial/templates/backOffice/default/module_configuration.html @@ -0,0 +1,94 @@ + + + +
+
+ +
+ {intl d='hooksocial.bo.default' l='Edit your social accounts.'} +
+ +
+
+ + {form name="hooksocial.configuration.form"} + + + {form_hidden_fields} + + {form_field field='twitter'} +
+ + +
+ {/form_field} + + {form_field field='facebook'} +
+ + +
+ {/form_field} + + {form_field field='google'} +
+ + +
+ {/form_field} + + {form_field field='instagram'} +
+ + +
+ {/form_field} + + {form_field field='pinterest'} +
+ + +
+ {/form_field} + + {form_field field='youtube'} +
+ + +
+ {/form_field} + + {form_field field='rss'} +
+ + +
+ {/form_field} + + + + {/form} + +
+ +
+ +
+
+ + + + diff --git a/domokits/local/modules/HookSocial/templates/frontOffice/default/assets/css/styles.css b/domokits/local/modules/HookSocial/templates/frontOffice/default/assets/css/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/domokits/local/modules/HookSocial/templates/frontOffice/default/main-footer-body.html b/domokits/local/modules/HookSocial/templates/frontOffice/default/main-footer-body.html new file mode 100644 index 0000000..095d783 --- /dev/null +++ b/domokits/local/modules/HookSocial/templates/frontOffice/default/main-footer-body.html @@ -0,0 +1,86 @@ + \ No newline at end of file diff --git a/domokits/local/modules/LocalPickup/.github/workflows/release.yml b/domokits/local/modules/LocalPickup/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/LocalPickup/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/LocalPickup/Config/config.xml b/domokits/local/modules/LocalPickup/Config/config.xml new file mode 100644 index 0000000..57def57 --- /dev/null +++ b/domokits/local/modules/LocalPickup/Config/config.xml @@ -0,0 +1,22 @@ + + + + +
+ + + + + + + + + + + + + + + diff --git a/domokits/local/modules/LocalPickup/Config/module.xml b/domokits/local/modules/LocalPickup/Config/module.xml new file mode 100644 index 0000000..8423bf6 --- /dev/null +++ b/domokits/local/modules/LocalPickup/Config/module.xml @@ -0,0 +1,18 @@ + + + LocalPickup\LocalPickup + + Local Pickup + + + Retrait sur place + + 2.0.5 + + Thelia + info@thelia.net + + delivery + 2.5.0 + alpha + diff --git a/domokits/local/modules/LocalPickup/Config/routing.xml b/domokits/local/modules/LocalPickup/Config/routing.xml new file mode 100644 index 0000000..82816fd --- /dev/null +++ b/domokits/local/modules/LocalPickup/Config/routing.xml @@ -0,0 +1,9 @@ + + + + + LocalPickup\Controller\ConfigurationController::configure + + diff --git a/domokits/local/modules/LocalPickup/Controller/ConfigurationController.php b/domokits/local/modules/LocalPickup/Controller/ConfigurationController.php new file mode 100644 index 0000000..9958e4b --- /dev/null +++ b/domokits/local/modules/LocalPickup/Controller/ConfigurationController.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* Copyright (c) OpenStudio */ +/* email : dev@thelia.net */ +/* web : http://www.thelia.net */ + +/* For the full copyright and license information, please view the LICENSE.txt */ +/* file that was distributed with this source code. */ + +namespace LocalPickup\Controller; + +use LocalPickup\Form\ConfigurationForm; +use LocalPickup\LocalPickup; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Tools\URL; + +/** + * Class ConfigurationController. + * + * @author Thelia + */ +class ConfigurationController extends BaseAdminController +{ + public function configure() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], ['LocalPickup'], AccessManager::UPDATE)) { + return $response; + } + + $form = $this->createForm(ConfigurationForm::getName()); + $errmes = $ex = null; + + try { + $vform = $this->validateForm($form); + + $price = $vform->get('price')->getData(); + $description = $vform->get('description')->getData(); + $email = $vform->get('email')->getData(); + + LocalPickup::setConfigValue(LocalPickup::PRICE_VAR_NAME, (float) $price); + LocalPickup::setConfigValue(LocalPickup::DESCRIPTION_VAR_NAME, $description, $this->getCurrentEditionLocale()); + LocalPickup::setConfigValue(LocalPickup::EMAIL_VAR_NAME, $email, $this->getCurrentEditionLocale()); + } catch (FormValidationException $ex) { + $errmes = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + $errmes = $ex->getMessage(); + } + + if (null !== $errmes && null !== $ex) { + $this->setupFormErrorContext( + 'configuration', + $errmes, + $form, + $ex + ); + } + + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/LocalPickup')); + } +} diff --git a/domokits/local/modules/LocalPickup/EventListeners/APIListener.php b/domokits/local/modules/LocalPickup/EventListeners/APIListener.php new file mode 100644 index 0000000..4e58ccc --- /dev/null +++ b/domokits/local/modules/LocalPickup/EventListeners/APIListener.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace LocalPickup\EventListeners; + +use LocalPickup\LocalPickup; +use OpenApi\Events\DeliveryModuleOptionEvent; +use OpenApi\Events\OpenApiEvents; +use OpenApi\Model\Api\DeliveryModuleOption; +use OpenApi\Model\Api\ModelFactory; +use Propel\Runtime\Exception\PropelException; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Mailer\MailerFactory; +use Thelia\Model\ModuleQuery; +use Thelia\Model\OrderStatus; + +class APIListener implements EventSubscriberInterface +{ + /** @var ModelFactory */ + protected $modelFactory; + + /** @var RequestStack */ + protected $requestStack; + + /** + * @var MailerFactory + */ + protected $mailer; + + /** + * APIListener constructor. + * + * @param ContainerInterface $container We need the container because we use a service from another module + * which is not mandatory, and using its service without it being installed will crash + */ + public function __construct(ModelFactory $modelFactory, RequestStack $requestStack, MailerFactory $mailer) + { + $this->modelFactory = $modelFactory; + $this->requestStack = $requestStack; + $this->mailer = $mailer; + } + + + public function getDeliveryModuleOptions(DeliveryModuleOptionEvent $deliveryModuleOptionEvent): void + { + $module = ModuleQuery::create()->findOneByCode(LocalPickup::getModuleCode()); + if ($deliveryModuleOptionEvent->getModule()->getId() !== $module->getId()) { + return; + } + + $isValid = true; + $locale = $this->requestStack->getCurrentRequest()->getSession()->getLang()->getLocale(); + + $postage = LocalPickup::getConfigValue(LocalPickup::PRICE_VAR_NAME, 0); + $commentary = LocalPickup::getConfigValue( + LocalPickup::DESCRIPTION_VAR_NAME, + '', + $locale + ); + + $postageTax = 0; + + $minimumDeliveryDate = ''; + $maximumDeliveryDate = ''; + + $images = $module->getModuleImages(); + $imageId = 0; + + $title = $module->setLocale($locale)->getTitle(); + + if ($images->count() > 0) { + $imageId = $images->getFirst()->getId(); + } + + /** @var DeliveryModuleOption $deliveryModuleOption */ + $deliveryModuleOption = $this->modelFactory->buildModel('DeliveryModuleOption'); + $deliveryModuleOption + ->setCode(LocalPickup::getModuleCode()) + ->setValid($isValid) + ->setTitle($title) + ->setImage($imageId) + ->setMinimumDeliveryDate($minimumDeliveryDate) + ->setMaximumDeliveryDate($maximumDeliveryDate) + ->setPostage($postage) + ->setPostageTax($postageTax) + ->setPostageUntaxed($postage - $postageTax) + ; + + // Pre-5.3.x compatibility + if (method_exists($deliveryModuleOption, 'setDescription')) { + $deliveryModuleOption->setDescription($commentary); + } + + $deliveryModuleOptionEvent->appendDeliveryModuleOptions($deliveryModuleOption); + } + + /** + * @throws PropelException + */ + public function getOrderStatus(OrderEvent $orderEvent) + { + $order = $orderEvent->getOrder(); + + if ($order->getDeliveryModuleId() !== LocalPickup::getModuleId() || $order->getOrderStatus()->getCode() !== OrderStatus::CODE_SENT) { + return; + } + + $this->mailer->sendEmailToCustomer( + LocalPickup::EMAIL_CUSTOM_LOCAL_PICKUP, + $order->getCustomer(), + [ + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef(), + 'comment' => LocalPickup::getConfigValue(LocalPickup::EMAIL_VAR_NAME, '', $order->getLang()->getLocale()), + ] + ); + } + + public static function getSubscribedEvents() + { + $listenedEvents = []; + + /* Check for old versions of Thelia where the events used by the API didn't exists */ + if (class_exists(DeliveryModuleOptionEvent::class)) { + $listenedEvents[OpenApiEvents::MODULE_DELIVERY_GET_OPTIONS] = ['getDeliveryModuleOptions', 129]; + } + + $listenedEvents[TheliaEvents::ORDER_UPDATE_STATUS] = ['getOrderStatus', 99]; + + return $listenedEvents; + } +} diff --git a/domokits/local/modules/LocalPickup/Form/ConfigurationForm.php b/domokits/local/modules/LocalPickup/Form/ConfigurationForm.php new file mode 100644 index 0000000..79f9db3 --- /dev/null +++ b/domokits/local/modules/LocalPickup/Form/ConfigurationForm.php @@ -0,0 +1,84 @@ +formBuilder + ->add( + "price", + NumberType::class, + [ + "required" => false, + "label"=>Translator::getInstance()->trans("Price", [], LocalPickup::DOMAIN_NAME), + "label_attr"=> [ + "for"=>"pricefield" + ], + "constraints"=> [ new NotBlank(), new GreaterThanOrEqual([ 'value' => 0 ]) ] + ] + ) + ->add( + "description", + TextareaType::class, + [ + "required" => false, + "label"=> Translator::getInstance()->trans("Commentary local pickup", [], LocalPickup::DOMAIN_NAME), + 'attr' => [ + 'rows' => 5, + ], + "label_attr"=> [ + "for"=>"description" + ], + ] + ) + ->add( + "email", + TextareaType::class, + [ + "required" => false, + "label"=> Translator::getInstance()->trans("Commentary email", [], LocalPickup::DOMAIN_NAME), + 'attr' => [ + 'rows' => 5, + ], + "label_attr"=> [ + "for"=>"description" + ], + ] + ) + ; + } + + /** + * @return string the name of you form. This name must be unique + */ + public static function getName() + { + return "config-localpickup"; + } + +} diff --git a/domokits/local/modules/LocalPickup/Hook/HookManager.php b/domokits/local/modules/LocalPickup/Hook/HookManager.php new file mode 100644 index 0000000..d6a185b --- /dev/null +++ b/domokits/local/modules/LocalPickup/Hook/HookManager.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* Copyright (c) OpenStudio */ +/* email : dev@thelia.net */ +/* web : http://www.thelia.net */ + +/* For the full copyright and license information, please view the LICENSE.txt */ +/* file that was distributed with this source code. */ + +namespace LocalPickup\Hook; + +use LocalPickup\LocalPickup; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class HookManager. + * + * @author Thomas Arnaud + */ +class HookManager extends BaseHook +{ + public function onModuleConfiguration(HookRenderEvent $event): void + { + $locale = $this->getSession()->getAdminEditionLang()->getLocale(); + + $event->add( + $this->render( + 'module_configuration.html', + [ + 'price' => (float) LocalPickup::getConfigValue(LocalPickup::PRICE_VAR_NAME, 0), + 'description' => LocalPickup::getConfigValue(LocalPickup::DESCRIPTION_VAR_NAME, '', $locale), + 'email' => LocalPickup::getConfigValue(LocalPickup::EMAIL_VAR_NAME, '', $locale), + ] + ) + ); + } + + public function onOrderInvoiceDeliveryAddress(HookRenderEvent $event): void + { + // Show the local delivery template if we're the current delivery module. + if ((null !== $order = $this->getSession()->getOrder()) && $order->getDeliveryModuleId() == LocalPickup::getModuleId()) { + $event->add( + $this->render('localpickup/order-invoice-delivery-address.html', [ + 'order_id' => $event->getArgument('order_id'), + ]) + ); + } + } + + public function onOrderDeliveryExtra(HookRenderEvent $event): void + { + $event->add( + $this->render( + 'localpickup/delivery-address.html', + [ + 'description' => LocalPickup::getConfigValue( + LocalPickup::DESCRIPTION_VAR_NAME, '', + $this->getSession()->getLang()->getLocale() + ), + ] + ) + ); + } +} diff --git a/domokits/local/modules/LocalPickup/I18n/backOffice/default/en_US.php b/domokits/local/modules/LocalPickup/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..b43e799 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/backOffice/default/en_US.php @@ -0,0 +1,7 @@ + 'Close', + 'Configure local pickup' => 'Configure local pickup', + 'Save changes' => 'Save changes ', +); diff --git a/domokits/local/modules/LocalPickup/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/LocalPickup/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..36cae13 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,7 @@ + 'Fermer', + 'Configure local pickup' => 'Configurer le retrait sur place', + 'Save changes' => 'Enregistrer les modifications', +); diff --git a/domokits/local/modules/LocalPickup/I18n/email/default/en_US.php b/domokits/local/modules/LocalPickup/I18n/email/default/en_US.php new file mode 100644 index 0000000..f5db2f7 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/email/default/en_US.php @@ -0,0 +1,10 @@ + 'Instructions', + 'Your order is available in store' => 'Your order is available in store', + 'Come pick up your order at the store' => 'Your order has been processed. You can collect it during store opening hours.', + 'Delivery address' => 'Delivery address', + 'Thanks' => 'Thanks', + 'The %store team.' => 'The %store team.', +); diff --git a/domokits/local/modules/LocalPickup/I18n/email/default/fr_FR.php b/domokits/local/modules/LocalPickup/I18n/email/default/fr_FR.php new file mode 100644 index 0000000..d8e51d7 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/email/default/fr_FR.php @@ -0,0 +1,10 @@ + 'Instructions', + 'Your order is available in store' => 'Votre commande est disponible en magasin', + 'Come pick up your order at the store' => "Votre commande a été traité, vous pouvez venir récupérer celle-ci en respectant les horaires d'ouverture du magasin.", + 'Delivery address' => 'Adresse de livraison', + 'Thanks' => 'Merci', + "The %store team." => "L'équipe %store." +); diff --git a/domokits/local/modules/LocalPickup/I18n/en_US.php b/domokits/local/modules/LocalPickup/I18n/en_US.php new file mode 100644 index 0000000..bd1a3c0 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/en_US.php @@ -0,0 +1,8 @@ + 'Write a comment visible for the user when selecting this delivery mode', + 'Commentary email' => 'Write a comment visible for the user in the email', + 'Price' => 'Price without taxes', + 'price must be a number !' => 'price must be a number !', +); diff --git a/domokits/local/modules/LocalPickup/I18n/fr_FR.php b/domokits/local/modules/LocalPickup/I18n/fr_FR.php new file mode 100644 index 0000000..e8e520c --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/fr_FR.php @@ -0,0 +1,8 @@ + 'Vous pouvez indiquer un commentaire qui sera affiché à vos client lors de la sélection de ce mode de livraison', + 'Commentary email' => 'Vous pouvez indiquer un commentaire qui sera affiché à vos client dans l\'email', + 'Price' => 'Prix HT', + 'price must be a number !' => 'Le prix doit être un nombre !', +); diff --git a/domokits/local/modules/LocalPickup/I18n/frontOffice/default/en_US.php b/domokits/local/modules/LocalPickup/I18n/frontOffice/default/en_US.php new file mode 100644 index 0000000..9603813 --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/frontOffice/default/en_US.php @@ -0,0 +1,8 @@ + 'In-store pick-up', + 'Instructions'=> 'Instructions', + 'Your order is available in store' => 'Votre commande est disponible en magasin', + 'Come pick up your order at the store' => "Votre commande a été traité, vous pouvez venir récupérer celle-ci en respectant les horaires d'ouverture du magasin", +); diff --git a/domokits/local/modules/LocalPickup/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/LocalPickup/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..070779c --- /dev/null +++ b/domokits/local/modules/LocalPickup/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,8 @@ + 'Retrait en magasin', + 'Instructions'=> 'Instructions', + 'Your order is available in store' => 'Votre commande est disponible en magasin', + 'Come pick up your order at the store' => "Votre commande a été traité, vous pouvez venir récupérer celle-ci en respectant les horaires d'ouverture du magasin", +); diff --git a/domokits/local/modules/LocalPickup/LICENSE.txt b/domokits/local/modules/LocalPickup/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/LocalPickup/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/LocalPickup/Listener/UpdateDeliveryAddress.php b/domokits/local/modules/LocalPickup/Listener/UpdateDeliveryAddress.php new file mode 100644 index 0000000..83ee53c --- /dev/null +++ b/domokits/local/modules/LocalPickup/Listener/UpdateDeliveryAddress.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* Copyright (c) OpenStudio */ +/* email : info@thelia.net */ +/* web : http://www.thelia.net */ + +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 3 of the License */ + +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ + +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see . */ + +namespace LocalPickup\Listener; + +use LocalPickup\LocalPickup; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Action\BaseAction; +use Thelia\Core\Event\Order\OrderAddressEvent; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\ConfigQuery; +use Thelia\Model\OrderAddressQuery; + +/** + * Class UpdateDeliveryAddress. + * + * @contributor Thomas Arnaud + */ +class UpdateDeliveryAddress extends BaseAction implements EventSubscriberInterface +{ + /** + * @throws \Exception + */ + public function updateAddress(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher): void + { + if ($event->getOrder()->getDeliveryModuleId() === LocalPickup::getModuleId()) { + $address_id = $event->getOrder()->getDeliveryOrderAddressId(); + $address = OrderAddressQuery::create()->findPk($address_id); + + if ($address !== null) { + $address1 = ConfigQuery::read('store_address1'); + $address2 = ConfigQuery::read('store_address2'); + $address3 = ConfigQuery::read('store_address3'); + $zipcode = ConfigQuery::read('store_zipcode'); + $city = ConfigQuery::read('store_city'); + $country = ConfigQuery::read('store_country'); + $name = ConfigQuery::read('store_name'); + + if ($address1 !== null && $zipcode !== null && $city !== null && $country !== null) { + $address_event = new OrderAddressEvent( + $address->getCustomerTitleId(), + $address->getFirstname(), + $address->getLastname(), + $address1, + $address2, + $address3, + $zipcode, + $city, + $country, + $address->getPhone(), + $name, + $address->getCellphone() + ); + + $address_event->setOrderAddress($address); + $address_event->setOrder($event->getOrder()); + $dispatcher->dispatch($address_event, TheliaEvents::ORDER_UPDATE_ADDRESS); + } + } else { + throw new \Exception("Error: order delivery address doesn't exists"); + } + } + } + + public function setAddress(OrderEvent $event): void + { + if ($event->getOrder()->getDeliveryModuleId() === LocalPickup::getModuleId()) { + $event->setDeliveryAddress(null); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_BEFORE_PAYMENT => ['updateAddress', 130], + TheliaEvents::ORDER_SET_DELIVERY_MODULE => ['setAddress', 128], + ]; + } +} diff --git a/domokits/local/modules/LocalPickup/LocalPickup.php b/domokits/local/modules/LocalPickup/LocalPickup.php new file mode 100644 index 0000000..933e81e --- /dev/null +++ b/domokits/local/modules/LocalPickup/LocalPickup.php @@ -0,0 +1,119 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace LocalPickup; + +use Propel\Runtime\Connection\ConnectionInterface; +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Install\Database; +use Thelia\Model\Country; +use Thelia\Model\Message; +use Thelia\Model\MessageQuery; +use Thelia\Model\State; +use Thelia\Module\AbstractDeliveryModuleWithState; + +/** + * Class LocalPickup + * @package LocalPickup + * @author Thelia + */ +class LocalPickup extends AbstractDeliveryModuleWithState +{ + const DOMAIN_NAME = 'localpickup'; + + const PRICE_VAR_NAME = 'price'; + const DESCRIPTION_VAR_NAME = 'description'; + const EMAIL_VAR_NAME = 'email'; + + const EMAIL_CUSTOM_LOCAL_PICKUP = 'email_custom_local_pickup'; + + /** + * @inheritdoc + */ + public function getPostage(Country $country, State $state = null) + { + return $this->buildOrderPostage(self::getConfigValue(self::PRICE_VAR_NAME, 0), $country, $this->getRequest()->getSession()->getLang()->getLocale()); + } + + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + if (null === MessageQuery::create()->findOneByName(self::EMAIL_CUSTOM_LOCAL_PICKUP)) { + $message = new Message(); + $message + ->setName(self::EMAIL_CUSTOM_LOCAL_PICKUP) + ->setHtmlTemplateFileName('order_shipping.html') + ->setHtmlLayoutFileName('') + ->setTextTemplateFileName('order_shipping.txt') + ->setTextLayoutFileName('') + ->setSecured(0) + ->setLocale('fr_FR') + ->setTitle('Confirmation de vote commande') + ->setSubject('Commande à récupérer en magasin') + ->setLocale('en_GB') + ->setTitle('Order confirmation') + ->setSubject('Order to pick up in store') + ->setLocale('de_DE') + ->setTitle('Bestellbestätigung') + ->setSubject('Bestellung im Geschäft abholen') + ->save() + ; + } + + if ($newVersion === '1.2') { + $db = new Database($con); + + // Migrate previous price from database to module config + try { + $statement = $db->execute("select price from local_pickup_shipping order by id desc limit 1"); + + $price = (float)$statement->fetchColumn(0); + + self::setConfigValue(self::PRICE_VAR_NAME, $price); + } catch (\Exception $ex) { + // Nothing special + } + } + } + + + /** + * @inheritdoc + */ + public function isValidDelivery(Country $country, State $state = null) + { + return true; + } + + public function getDeliveryMode() + { + return "localPickup"; + } + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/LocalPickup/Loop/LocalAddress.php b/domokits/local/modules/LocalPickup/Loop/LocalAddress.php new file mode 100644 index 0000000..7d07b8a --- /dev/null +++ b/domokits/local/modules/LocalPickup/Loop/LocalAddress.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* Copyright (c) OpenStudio */ +/* email : info@thelia.net */ +/* web : http://www.thelia.net */ + +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 3 of the License */ + +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ + +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see . */ + +namespace LocalPickup\Loop; + +use Symfony\Component\Config\Definition\Exception\Exception; +use Thelia\Core\Template\Element\ArraySearchLoopInterface; +use Thelia\Core\Template\Element\BaseLoop; +use Thelia\Core\Template\Element\LoopResult; +use Thelia\Core\Template\Element\LoopResultRow; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Model\AddressQuery; +use Thelia\Model\ConfigQuery; + +/** + * Class LocalAddress. + * + * @author Thelia + * + * @method int getId() + */ +class LocalAddress extends BaseLoop implements ArraySearchLoopInterface +{ + /** + * {@inheritdoc} + */ + public function buildArray() + { + $id = $this->getId(); + + /** @var \Thelia\Core\HttpFoundation\Session\Session $session */ + $session = $this->requestStack->getCurrentRequest()->getSession(); + + $address = AddressQuery::create() + ->filterByCustomerId($session->getCustomerUser()->getId()) + ->findPk($id); + + if ($address === null) { + throw new Exception("The requested address doesn't exist"); + } + + /** @var \Thelia\Model\Customer $customer */ + $customer = $session->getCustomerUser(); + + return [ + 'Id' => 0, + 'Label' => $address->getLabel(), + 'CustomerId' => $address->getCustomerId(), + 'TitleId' => $address->getTitleId(), + 'Company' => ConfigQuery::read('store_name'), + 'Firstname' => $customer->getFirstname(), + 'Lastname' => $customer->getLastname(), + 'Address1' => ConfigQuery::read('store_address1'), + 'Address2' => ConfigQuery::read('store_address2'), + 'Address3' => ConfigQuery::read('store_address3'), + 'Zipcode' => ConfigQuery::read('store_zipcode'), + 'City' => ConfigQuery::read('store_city'), + 'CountryId' => ConfigQuery::read('store_country'), + 'Phone' => $address->getPhone(), + 'Cellphone' => $address->getCellphone(), + 'IsDefault' => 0, + ]; + } + + /** + * {@inheritdoc} + */ + public function parseResults(LoopResult $loopResult) + { + $address = $loopResult->getResultDataCollection(); + $loopResultRow = new LoopResultRow($address); + + $loopResultRow + ->set('ID', $address['Id']) + ->set('LABEL', $address['Label']) + ->set('CUSTOMER', $address['CustomerId']) + ->set('TITLE', $address['TitleId']) + ->set('COMPANY', $address['Company']) + ->set('FIRSTNAME', $address['Firstname']) + ->set('LASTNAME', $address['Lastname']) + ->set('ADDRESS1', $address['Address1']) + ->set('ADDRESS2', $address['Address2']) + ->set('ADDRESS3', $address['Address3']) + ->set('ZIPCODE', $address['Zipcode']) + ->set('CITY', $address['City']) + ->set('COUNTRY', $address['CountryId']) + ->set('PHONE', $address['Phone']) + ->set('CELLPHONE', $address['Cellphone']) + ->set('DEFAULT', $address['IsDefault']) + ; + + $loopResult->addRow($loopResultRow); + + return $loopResult; + } + + /** + * {@inheritdoc} + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('id', null, true) + ); + } +} diff --git a/domokits/local/modules/LocalPickup/README.md b/domokits/local/modules/LocalPickup/README.md new file mode 100644 index 0000000..c01a932 --- /dev/null +++ b/domokits/local/modules/LocalPickup/README.md @@ -0,0 +1,101 @@ +LocalPickup module +================== +author: Thelia + +Summary +------- + +fr_FR: +1. Installation +2. Utilisation +3. Boucles +4. Intégration + +en_US: +1. Install notes +2. How to use +3. Loops +4. Integration + +fr_FR +----- + +### Installation + +#### Manually + +* Copiez le module dans le dossier ```/local/modules/``` et assurez-vous que le nom du module est bien LocalPickup. +* Activez le depuis votre interface d'administration Thelia. + +#### Composer + +Ajoutez le module à votre fichier composer.json principal : + +``` +composer require thelia/local-pickup-module:~1.0 +``` + +### Utilisation + +Pour utiliser le module de retrait sur place, allez dans le back-office, onglet Modules, et activez le, +puis cliquez sur "Configurer" sur la ligne du module. Renseignez le prix que vous souhaitez donner au retrait sur place +et enregistrez. + +### Boucles + +1. `address.local` + Même sorties que la boucle `address`, mais avec l'adresse du magasin au lieu de celle du client. + - Arguments: + 1. id | obligatoire | id de l'adresse du client + - Sorties: + Les mêmes variables que la boucle address, mais l'adresse donnée est celle du magasin. + - Utilisation: + ``` + {loop type="address.local" name="yourloopname" id="1"} + + {/loop}``` + +### Intégration + +L'integration utilise les hooks et ne nécessite pas de travaux particuliers. + +en_US +----- + +### Installation notes + +#### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is LocalPickup. +* Activate it in your thelia administration panel + +#### Composer + +Add it in your main thelia composer.json file: + +``` +composer require thelia/local-pickup-module:~1.0 +``` + +### Usage + +To use the module, you first need to activate it in the back-office, tab Modules, and click on "Configure" on the line +of the module. Enter the price you want for local pickup and save. + +### Loops +1. `address.local` + Same output as the `address` loop, with the store adresse instead of the customer address. + - Arguments: + 1. id | mandatory | id of the customer's address + - Output: + The same variables as address loop, but the given address is the store's address. + - Usage: + ``` + {loop type="address.local" name="yourloopname" id="1"} + + {/loop} + ``` + +### Integration + +The modules uses hooks, and does not require specific work. diff --git a/domokits/local/modules/LocalPickup/composer.json b/domokits/local/modules/LocalPickup/composer.json new file mode 100644 index 0000000..5527cbf --- /dev/null +++ b/domokits/local/modules/LocalPickup/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/local-pickup-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "LocalPickup" + } +} \ No newline at end of file diff --git a/domokits/local/modules/LocalPickup/templates/backOffice/default/module_configuration.html b/domokits/local/modules/LocalPickup/templates/backOffice/default/module_configuration.html new file mode 100644 index 0000000..d36e1f4 --- /dev/null +++ b/domokits/local/modules/LocalPickup/templates/backOffice/default/module_configuration.html @@ -0,0 +1,53 @@ +{if isset($smarty.get.errmes) and !empty($smarty.get.errmes)} +
+ {$smarty.get.errmes} +
+{/if} + +
+
+
+ {intl l='Configure local pickup' d='localpickup.bo.default'} +
+ +
+
+ + {form name="localpickup.form"} + + {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = false + + page_url = {url path="/admin/module/LocalPickup"} + close_url = {url path="/admin/modules"} + } + + {form_hidden_fields form=$form} + +
+
+ {custom_render_form_field field="price"} +
+ + + {currency attr="symbol"} + +
+ {/custom_render_form_field} +
+ +
+ {render_form_field field="description" extra_class="wysiwyg" value=$description} +
+ +
+ {render_form_field field="email" extra_class="wysiwyg" value=$email} +
+
+ {/form} + +
+
+
+
diff --git a/domokits/local/modules/LocalPickup/templates/email/default/order_shipping.html b/domokits/local/modules/LocalPickup/templates/email/default/order_shipping.html new file mode 100644 index 0000000..ff49f1b --- /dev/null +++ b/domokits/local/modules/LocalPickup/templates/email/default/order_shipping.html @@ -0,0 +1,52 @@ +{extends file="email-layout.tpl"} + +{* Do not provide a "Open in browser" link *} +{block name="browser"}{/block} +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}{intl l="Your order confirmation Nº %ref" ref={$order_ref}}{/block} + +{* Title *} +{block name="email-title"} + {default_translation_domain domain='localpickup.email.default'} + {intl l="Your order is available in store"} +{/block} + +{* Content *} +{block name="email-content"} + {default_translation_domain domain='localpickup.email.default'} + +

{intl l="Come pick up your order at the store"}

+ +
+ + {loop name="order.invoice" type="order" id=$order_id customer="*"} + + + + + +
+ {intl l="Delivery address"}:
+ {ifhook rel="email-html.order-confirmation.delivery-address"} + {* delivery module can customize the delivery address *} + {hook name="email-html.order-confirmation.delivery-address" module={$DELIVERY_MODULE} order=$order_id} + {/ifhook} + {elsehook rel="email-html.order-confirmation.delivery-address"} + {format_address order_address=$DELIVERY_ADDRESS locale=$locale} + {/elsehook} +
+ {intl l="Instructions"}:
+ {$comment nofilter} +
+ +
+
+ + {intl l="Thanks"}
+ {intl l="The %store team." store={config key="store_name"}} + {/loop} +{/block} + diff --git a/domokits/local/modules/LocalPickup/templates/email/default/order_shipping.txt b/domokits/local/modules/LocalPickup/templates/email/default/order_shipping.txt new file mode 100644 index 0000000..e69de29 diff --git a/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/delivery-address.html b/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/delivery-address.html new file mode 100644 index 0000000..d54f398 --- /dev/null +++ b/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/delivery-address.html @@ -0,0 +1,5 @@ + + + {$description nofilter} + + diff --git a/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/order-invoice-delivery-address.html b/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/order-invoice-delivery-address.html new file mode 100644 index 0000000..d78131d --- /dev/null +++ b/domokits/local/modules/LocalPickup/templates/frontOffice/default/localpickup/order-invoice-delivery-address.html @@ -0,0 +1,25 @@ +
+ {loop type="address.local" name="local-delivery-address" id={order attr="delivery_address"}} +
{intl l="Retrait en magasin" d="localpickup.fo.default"}
+
+ {loop type="title" name="customer.title.info" id=$TITLE|default:0}{$SHORT}{/loop} {$LASTNAME|upper} {$FIRSTNAME|ucwords} + {$COMPANY} +
+ {$ADDRESS1}
+ {if $ADDRESS2 != ""} + {$ADDRESS2}
+ {/if} + {if $ADDRESS3 != ""} + {$ADDRESS3}
+ {/if} + {$ZIPCODE} + {$CITY}
+ + {loop type="country" name="customer.country.info" id=$COUNTRY|default:0}{$TITLE}{/loop}{if $STATE|default:0}, + {loop type="state" name="customer.state.info" id=$STATE|default:0}{$TITLE}{/loop} + {/if} + +
+
+ {/loop} +
diff --git a/domokits/local/modules/OpenApi/Compiler/ModelPass.php b/domokits/local/modules/OpenApi/Compiler/ModelPass.php new file mode 100644 index 0000000..91a9be6 --- /dev/null +++ b/domokits/local/modules/OpenApi/Compiler/ModelPass.php @@ -0,0 +1,32 @@ +findTaggedServiceIds('open_api.model'); + + $modelServices = []; + foreach ($taggedServices as $id => $tags) { + foreach ($tags as $attributes) { + $classParts = explode('\\', $id); + $modelAlias = $attributes['alias'] ?? end($classParts); + $modelServices[$modelAlias] = $id; + } + if (property_exists($id, "serviceAliases")) { + foreach ($id::$serviceAliases as $alias) { + $modelServices[$alias] = $id; + } + } + } + + $containerBuilder->setParameter(OpenApi::OPEN_API_MODELS_PARAMETER_KEY, $modelServices); + } +} diff --git a/domokits/local/modules/OpenApi/Config/config.xml b/domokits/local/modules/OpenApi/Config/config.xml new file mode 100644 index 0000000..a5cf214 --- /dev/null +++ b/domokits/local/modules/OpenApi/Config/config.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/OpenApi/Config/module.xml b/domokits/local/modules/OpenApi/Config/module.xml new file mode 100644 index 0000000..b15480f --- /dev/null +++ b/domokits/local/modules/OpenApi/Config/module.xml @@ -0,0 +1,43 @@ + + + OpenApi\OpenApi + + Add an API to Thelia + + + + Ajoute une API a Thelia + + + + + en_US + fr_FR + + 2.1.9 + + + Vincent Lopes-Vicente + + + + classic + + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/OpenApi/Config/routing.xml b/domokits/local/modules/OpenApi/Config/routing.xml new file mode 100644 index 0000000..dad991d --- /dev/null +++ b/domokits/local/modules/OpenApi/Config/routing.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/domokits/local/modules/OpenApi/Config/schema.xml b/domokits/local/modules/OpenApi/Config/schema.xml new file mode 100644 index 0000000..353b1a4 --- /dev/null +++ b/domokits/local/modules/OpenApi/Config/schema.xml @@ -0,0 +1,29 @@ + + + + diff --git a/domokits/local/modules/OpenApi/Constraint/Length.php b/domokits/local/modules/OpenApi/Constraint/Length.php new file mode 100644 index 0000000..0433aa9 --- /dev/null +++ b/domokits/local/modules/OpenApi/Constraint/Length.php @@ -0,0 +1,29 @@ +maxMessage = $translator->trans('This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.', [], OpenApi::DOMAIN_NAME); + $this->minMessage = $translator->trans('This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.', [], OpenApi::DOMAIN_NAME); + $this->exactMessage = $translator->trans('This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.', [], OpenApi::DOMAIN_NAME); + $this->charsetMessage = $translator->trans('This value does not match the expected {{ charset }} charset.', [], OpenApi::DOMAIN_NAME); + } + + public function validatedBy() + { + return get_parent_class().'Validator'; + } +} diff --git a/domokits/local/modules/OpenApi/Constraint/NotBlank.php b/domokits/local/modules/OpenApi/Constraint/NotBlank.php new file mode 100644 index 0000000..962b7b6 --- /dev/null +++ b/domokits/local/modules/OpenApi/Constraint/NotBlank.php @@ -0,0 +1,24 @@ +message = Translator::getInstance()->trans('This value should not be blank', [], OpenApi::DOMAIN_NAME); + } + + public function validatedBy() + { + return get_parent_class().'Validator'; + } +} diff --git a/domokits/local/modules/OpenApi/Constraint/NotNull.php b/domokits/local/modules/OpenApi/Constraint/NotNull.php new file mode 100644 index 0000000..eb09ad1 --- /dev/null +++ b/domokits/local/modules/OpenApi/Constraint/NotNull.php @@ -0,0 +1,24 @@ +message = Translator::getInstance()->trans('This value should not be null', [], OpenApi::DOMAIN_NAME); + } + + public function validatedBy() + { + return get_parent_class().'Validator'; + } +} diff --git a/domokits/local/modules/OpenApi/Constraint/Zipcode.php b/domokits/local/modules/OpenApi/Constraint/Zipcode.php new file mode 100644 index 0000000..3c1a18e --- /dev/null +++ b/domokits/local/modules/OpenApi/Constraint/Zipcode.php @@ -0,0 +1,17 @@ +context->getRoot(); + $country = CountryQuery::create()->findPk($address->getCountryId()); + + if (null !== $country) { + if ($country->getNeedZipCode()) { + $zipCodeRegExp = $country->getZipCodeRE(); + if (null !== $zipCodeRegExp) { + if (!preg_match($zipCodeRegExp, $value)) { + $this->context + ->buildViolation(Translator::getInstance()->trans( + "This zip code should respect the following format : %format.", + ['%format' => $country->getZipCodeFormat()], + OpenApi::DOMAIN_NAME + )) + ->addViolation(); + } + } + } + } + + return; + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Admin/BaseAdminOpenApiController.php b/domokits/local/modules/OpenApi/Controller/Admin/BaseAdminOpenApiController.php new file mode 100644 index 0000000..1976e8d --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Admin/BaseAdminOpenApiController.php @@ -0,0 +1,16 @@ +createForm(ConfigForm::getName()); + + try { + $form = $this->validateForm($configForm); + + $data = implode(',', array_keys($form->get('enable_config')->getData())); + + OpenApi::setConfigValue('config_variables', $data); + + return $this->generateSuccessRedirect($configForm); + } catch (\Exception $exception) { + Tlog::getInstance()->error($exception->getMessage()); + + $configForm->setErrorMessage($exception->getMessage()); + + $parserContext + ->addForm($configForm) + ->setGeneralError($exception->getMessage()) + ; + + return $this->generateErrorRedirect($configForm); + } + } +} \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/Controller/Front/AddressController.php b/domokits/local/modules/OpenApi/Controller/Front/AddressController.php new file mode 100644 index 0000000..cfc69f2 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/AddressController.php @@ -0,0 +1,268 @@ +getCurrentCustomer(); + + $addresses = AddressQuery::create() + ->filterByCustomerId($currentCustomer->getId()) + ->find(); + + return OpenApiService::jsonResponse( + array_map( + function (Address $address) use ($modelFactory) { + /** @var OpenApiAddress $openApiAddress */ + $openApiAddress = $modelFactory->buildModel('Address', $address); + $openApiAddress->validate(self::GROUP_READ); + + return $openApiAddress; + }, + iterator_to_array($addresses) + ) + ); + } + + /** + * @Route("", name="add_address", methods="POST") + * + * @OA\Post( + * path="/address", + * tags={"address"}, + * summary="Add an address to current customer", + * @OA\RequestBody( + * required=true, + * @OA\JsonContent(ref="#/components/schemas/Address") + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/Address" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function createAddress( + Request $request, + OpenApiService $openApiService, + ModelFactory $modelFactory + ) { + $currentCustomer = $openApiService->getCurrentCustomer(); + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $currentCustomer); + + /** @var OpenApiAddress $openApiAddress */ + $openApiAddress = $modelFactory->buildModel('Address', $request->getContent()); + $openApiAddress + ->setCustomer($openApiCustomer) + ->validate(self::GROUP_CREATE); + + $openApiAddress->getLabel() ?: $openApiAddress->setLabel(Translator::getInstance()->trans('Main Address')); + + /** @var Address $theliaAddress */ + $theliaAddress = $openApiAddress->toTheliaModel(); + + $oldDefaultAddress = AddressQuery::create()->filterByCustomer($currentCustomer)->filterByIsDefault(true)->findOne(); + if (null === $oldDefaultAddress || $openApiAddress->getIsDefault()) { + $theliaAddress->makeItDefault(); + } + + $theliaAddress->save(); + + return OpenApiService::jsonResponse($openApiAddress->setId($theliaAddress->getId())); + } + + /** + * @Route("/{id}", name="update_address", methods="PATCH") + * + * @OA\Patch( + * path="/address/{id}", + * tags={"address"}, + * summary="Update address", + * @OA\Parameter( + * name="id", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\RequestBody( + * required=true, + * @OA\JsonContent(ref="#/components/schemas/Address") + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Address") + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function updateAddress( + Request $request, + OpenApiService $openApiService, + ModelFactory $modelFactory, + $id + ) { + $currentCustomer = $openApiService->getCurrentCustomer(); + + $theliaAddress = AddressQuery::create() + ->filterByCustomerId($currentCustomer->getId()) + ->filterById($id) + ->findOne(); + + if (null === $theliaAddress) { + throw $openApiService->buildOpenApiException( + Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME), + Translator::getInstance()->trans(Translator::getInstance()->trans("No address found for id $id for the current customer.", [], OpenApi::DOMAIN_NAME), [], OpenApi::DOMAIN_NAME) + ); + } + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $currentCustomer); + + /** @var OpenApiAddress $openApiAddress */ + $openApiAddress = $modelFactory->buildModel('Address', $request->getContent()); + $openApiAddress + ->setId($id) + ->setCustomer($openApiCustomer) + ->validate(self::GROUP_UPDATE); + + /** @var Address $theliaAddress */ + $theliaAddress = $openApiAddress->toTheliaModel(); + + $oldDefaultAddress = AddressQuery::create()->filterByCustomer($currentCustomer)->filterByIsDefault(true)->findOne(); + $alreadyDefault = false; + + /* + * Force a default address to stay as default + * Because we can't unset a default address, this is only done when a new address is set as default + */ + if (null !== $oldDefaultAddress && $oldDefaultAddress->getId() === $theliaAddress->getId()) { + $alreadyDefault = true; + $theliaAddress->setIsDefault(true); + } + + if ((null === $oldDefaultAddress || $openApiAddress->getIsDefault()) && !$alreadyDefault) { + $theliaAddress->makeItDefault(); + } + + $theliaAddress + ->save(); + + return new JsonResponse($openApiAddress); + } + + /** + * @Route("/{id}", name="delete_address", methods="DELETE") + * + * @OA\Delete( + * path="/address/{id}", + * tags={"address"}, + * summary="Delete address", + * @OA\Parameter( + * name="id", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="204", + * description="Success" + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function deleteAddress( + OpenApiService $openApiService, + ModelFactory $modelFactory, + $id + ) { + $currentCustomer = $openApiService->getCurrentCustomer(); + + $theliaAddress = AddressQuery::create() + ->filterByCustomerId($currentCustomer->getId()) + ->filterById($id) + ->findOne(); + + if (null === $theliaAddress || $theliaAddress->getIsDefault()) { + $errorDescription = $theliaAddress ? 'Impossible to delete the default address.' : "No address found for id $id for the current customer."; + throw $openApiService->buildOpenApiException( + Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME), + Translator::getInstance()->trans($errorDescription, [], OpenApi::DOMAIN_NAME) + ); + } + + $theliaAddress->delete(); + + return new JsonResponse('Success', 204); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/AuthController.php b/domokits/local/modules/OpenApi/Controller/Front/AuthController.php new file mode 100644 index 0000000..b0ec05e --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/AuthController.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace OpenApi\Controller\Front; + +use OpenApi\Annotations as OA; +use OpenApi\Model\Api\Customer as OpenApiCustomer; +use OpenApi\Model\Api\ModelFactory; +use OpenApi\OpenApi; +use OpenApi\Service\OpenApiService; +use Symfony\Component\Routing\Annotation\Route; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Thelia\Action\BaseAction; +use Thelia\Core\Event\Customer\CustomerLoginEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\SecurityContext; +use Thelia\Core\Security\Token\CookieTokenProvider; +use Thelia\Core\Translation\Translator; +use Thelia\Model\ConfigQuery; +use Thelia\Model\CustomerQuery; + +/** + * @Route("", name="auth") + */ +class AuthController extends BaseFrontOpenApiController +{ + /** + * @Route("/login", name="login", methods="POST") + * + * @OA\Post( + * path="/login", + * tags={"customer"}, + * summary="Log in a customer", + * security={}, + * @OA\RequestBody( + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="email", + * type="string" + * ), + * @OA\Property( + * property="password", + * type="string" + * ), + * @OA\Property( + * property="rememberMe", + * type="boolean" + * ), + * ) + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Customer") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function customerLogin( + Request $request, + SecurityContext $securityContext, + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory + ) { + if ($securityContext->hasCustomerUser()) { + throw new \Exception(Translator::getInstance()->trans('A user is already connected. Please disconnect before trying to login in another account.')); + } + + $data = json_decode($request->getContent(), true); + + $customer = CustomerQuery::create() + ->filterByEmail($data['email']) + ->findOne() + ; + + if ($customer === null || !$customer->checkPassword($data['password'])) { + throw new \Exception(Translator::getInstance()->trans('Your username/password pair, does not correspond to any account', [], OpenApi::DOMAIN_NAME)); + } + + $dispatcher->dispatch(new CustomerLoginEvent($customer), TheliaEvents::CUSTOMER_LOGIN); + + /* If the rememberMe property is set to true, we create a new cookie to store the information */ + if (true === (bool) $data['rememberMe']) { + (new CookieTokenProvider())->createCookie( + $customer, + ConfigQuery::read('customer_remember_me_cookie_name', 'crmcn'), + ConfigQuery::read('customer_remember_me_cookie_expiration', 2592000 /* 1 month */) + ); + } + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $customer); + $openApiCustomer->setDefaultAddressId($customer->getDefaultAddress()->getId()); + + return OpenApiService::jsonResponse($openApiCustomer); + } + + /** + * @Route("/logout", name="logout", methods="POST") + * + * @OA\Post( + * path="/logout", + * tags={"customer"}, + * summary="Log out a customer", + * + * @OA\Response( + * response="204", + * description="Success", + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function customerLogout( + SecurityContext $securityContext, + EventDispatcherInterface $dispatcher + ) { + if (!$securityContext->hasCustomerUser()) { + throw new \Exception(Translator::getInstance()->trans('No user is currently logged in.')); + } + + $dispatcher->dispatch((new BaseAction()), TheliaEvents::CUSTOMER_LOGOUT); + (new CookieTokenProvider())->clearCookie(ConfigQuery::read('customer_remember_me_cookie_name', 'crmcn')); + + return OpenApiService::jsonResponse('Success', 204); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/BaseFrontOpenApiController.php b/domokits/local/modules/OpenApi/Controller/Front/BaseFrontOpenApiController.php new file mode 100644 index 0000000..fdb7d85 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/BaseFrontOpenApiController.php @@ -0,0 +1,16 @@ +createResponseFromCart($openApiService); + } + + /** + * @Route("/add", name="add_cartitem", methods="POST") + * + * @OA\Post( + * path="/cart/add", + * tags={"cart"}, + * summary="Add a PSE in a cart", + * + * @OA\RequestBody( + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="pseId", + * type="integer" + * ), + * @OA\Property( + * property="quantity", + * type="integer" + * ), + * @OA\Property( + * property="append", + * type="boolean" + * ), + * @OA\Property( + * property="newness", + * type="boolean" + * ), + * example={"pseId": 18, "quantity": 2, "append": true, "newness": true} + * ) + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * @OA\Items( + * type="object", + * @OA\Property( + * property="cart", + * ref="#/components/schemas/Cart" + * ), + * @OA\Property( + * property="cartItem", + * ref="#/components/schemas/CartItem" + * ) + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function cartAddCartItem( + Request $request, + EventDispatcherInterface $dispatcher, + OpenApiService $openApiService, + ModelFactory $modelFactory + ) { + $cart = $request->getSession()->getSessionCart($dispatcher); + if (null === $cart) { + throw new \Exception(Translator::getInstance()->trans('No cart found', [], OpenApi::DOMAIN_NAME)); + } + + $event = new CartEvent($cart); + + $this->updateCartEventFromJson($request->getContent(), $event); + $dispatcher->dispatch($event, TheliaEvents::CART_ADDITEM); + + return OpenApiService::jsonResponse([ + 'cart' => $openApiService->getCurrentOpenApiCart(), + 'cartItem' => $modelFactory->buildModel('CartItem', $event->getCartItem()), + ]); + } + + /** + * @Route("/{cartItemId}", name="delete_cartitem", methods="DELETE") + * + * @OA\Delete( + * path="/cart/{cartItemId}", + * tags={"cart"}, + * summary="Delete an item in the current cart", + * @OA\Parameter( + * name="cartItemId", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * @OA\Items( + * type="object", + * @OA\Property( + * property="cart", + * ref="#/components/schemas/Cart" + * ), + * @OA\Property( + * property="cartItem", + * ref="#/components/schemas/CartItem" + * ) + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function cartDeleteCartItem( + Request $request, + EventDispatcherInterface $dispatcher, + OpenApiService $openApiService, + $cartItemId + ) { + $cart = $request->getSession()->getSessionCart($dispatcher); + if (null === $cart) { + throw new \Exception(Translator::getInstance()->trans('No cart found', [], OpenApi::DOMAIN_NAME)); + } + + $cartItem = CartItemQuery::create()->filterById($cartItemId)->findOne(); + + if (null === $cartItem) { + throw new \Exception(Translator::getInstance()->trans('Deletion impossible : this cart item does not exists.', [], OpenApi::DOMAIN_NAME)); + } + + $cartEvent = new CartEvent($cart); + $cartEvent->setCartItemId($cartItemId); + + $dispatcher->dispatch( + $cartEvent, + TheliaEvents::CART_DELETEITEM + ); + + return $this->createResponseFromCart($openApiService); + } + + /** + * @Route("/{cartItemId}", name="update_cartitem", methods="PATCH") + * + * @OA\Patch( + * path="/cart/{cartItemId}", + * tags={"cart"}, + * summary="Modify an item in the current cart", + * @OA\Parameter( + * name="cartItemId", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\RequestBody( + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="quantity", + * type="integer" + * ), + * example={"quantity": 0} + * ) + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Cart") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function cartUpdateCartItem( + Request $request, + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory, + OpenApiService $openApiService, + $cartItemId + ) { + $cart = $request->getSession()->getSessionCart($dispatcher); + if (null === $cart) { + throw new \Exception(Translator::getInstance()->trans('No cart found', [], OpenApi::DOMAIN_NAME)); + } + + $cartItem = CartItemQuery::create()->filterById($cartItemId)->findOne(); + + if (null === $cartItem) { + throw new \Exception(Translator::getInstance()->trans('Modification impossible : this cart item does not exists.', [], OpenApi::DOMAIN_NAME)); + } + + /* Check if cart item belongs to user's cart */ + if (!$cartItem || $cartItem->getCartId() !== $cart->getId()) { + throw new \Exception(Translator::getInstance()->trans("This cartItem doesn't belong to this cart.", [], OpenApi::DOMAIN_NAME)); + } + + $event = new CartEvent($cart); + $event->setCartItemId($cartItemId); + + if ($request->get('quantity') === 0) { + $dispatcher->dispatch( + $event, + TheliaEvents::CART_DELETEITEM + ); + } else { + $this->updateCartEventFromJson($request->getContent(), $event); + $dispatcher->dispatch($event, TheliaEvents::CART_UPDATEITEM); + } + + return OpenApiService::jsonResponse([ + 'cart' => $openApiService->getCurrentOpenApiCart(), + 'cartItem' => $modelFactory->buildModel('CartItem', $event->getCartItem()), + ]); + } + + /** + * Create a new JSON response of an OpenApi cart and returns it, from a Thelia Cart. + * + * @param Cart $cart + * + * @return JsonResponse + * + * @throws \Propel\Runtime\Exception\PropelException + */ + protected function createResponseFromCart(OpenApiService $openApiService) + { + return OpenApiService::jsonResponse($openApiService->getCurrentOpenApiCart()); + } + + /** + * @param int $quantity + * + * @return bool + */ + protected function checkAvailableStock(ProductSaleElements $pse, $quantity) + { + if ($pse && $quantity) { + return $quantity > $pse->getQuantity() && ConfigQuery::checkAvailableStock() && !$pse->getProduct()->getVirtual() === 0; + } + + throw new \Exception(Translator::getInstance()->trans('A PSE is needed in the POST request to add an item to the cart.')); + } + + /** + * Update a Cart Event from a json. + * + * @param $json + * + * @throws \Exception + */ + protected function updateCartEventFromJson($json, CartEvent $event): void + { + $data = json_decode($json, true); + + if (!isset($data['quantity'])) { + throw new \Exception(Translator::getInstance()->trans('A quantity is needed in the POST request to add an item to the cart.')); + } + + /* If the function was called from the PATCH route, we just update the quantity and return */ + if ($cartItemId = $event->getCartItemId()) { + $cartItem = CartItemQuery::create()->filterById($cartItemId)->findOne(); + if ($this->checkAvailableStock($cartItem->getProductSaleElements(), $data['quantity'])) { + throw new \Exception(Translator::getInstance()->trans('Desired quantity exceed available stock')); + } + $event->setQuantity($data['quantity']); + + return; + } + + /* If the function was called from the POST route, we need to set the pseId and append properties, as we need a new CartItem */ + if (!isset($data['pseId'])) { + throw new \Exception(Translator::getInstance()->trans('A PSE is needed in the POST request to add an item to the cart.')); + } + if (!isset($data['append'])) { + throw new \Exception(Translator::getInstance()->trans('You need to set the append value in the POST request to add an item to the cart.')); + } + + $pse = ProductSaleElementsQuery::create()->findPk($data['pseId']); + + if ($this->checkAvailableStock($pse, $data['quantity'])) { + throw new \Exception(Translator::getInstance()->trans('Desired quantity exceed available stock')); + } + + /** If newness then force new cart_item id */ + $newness = isset($data['newness']) ? (bool) $data['newness'] : false; + + $event + ->setProduct($pse->getProductId()) + ->setProductSaleElementsId($data['pseId']) + ->setQuantity($data['quantity']) + ->setAppend($data['append']) + ->setNewness($newness) + ; + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/CategoryController.php b/domokits/local/modules/OpenApi/Controller/Front/CategoryController.php new file mode 100644 index 0000000..773445b --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/CategoryController.php @@ -0,0 +1,147 @@ +baseSearchItems("category", $request); + $categories = $query->find(); + return OpenApiService::jsonResponse( + array_map(fn ($category) => $modelFactory->buildModel('Category', $category), iterator_to_array($categories)) + ); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/CheckoutController.php b/domokits/local/modules/OpenApi/Controller/Front/CheckoutController.php new file mode 100644 index 0000000..14756bc --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/CheckoutController.php @@ -0,0 +1,318 @@ +getCurrentCustomer(); + + $cart = $session->getSessionCart($dispatcher); + if ($cart === null || $cart->countCartItems() === 0) { + throw new \Exception(Translator::getInstance()->trans('Cart is empty', [], OpenApi::DOMAIN_NAME)); + } + + if (true === ConfigQuery::checkAvailableStock()) { + if (!$this->checkStockNotEmpty($cart)) { + throw new \Exception(Translator::getInstance()->trans('Not enough stock', [], OpenApi::DOMAIN_NAME)); + } + } + + $decodedContent = json_decode($request->getContent(), true); + + /** @var Checkout $checkout */ + $checkout = $modelFactory->buildModel('Checkout', $decodedContent); + + if (isset($decodedContent['needValidate']) && true === $decodedContent['needValidate']) { + $checkout->checkIsValid(); + } + + $order = $this->getOrder($request); + $orderEvent = new OrderEvent($order); + + $this->setOrderDeliveryPart( + $request, + $session, + $dispatcher, + $securityContext, + $checkout, + $orderEvent + ); + $this->setOrderInvoicePart( + $dispatcher, + $securityContext, + $checkout, + $orderEvent + ); + + $responseCheckout = $checkout + ->createFromOrder($orderEvent->getOrder()); + + return OpenApiService::jsonResponse($responseCheckout); + } + + /** + * @Route("", name="get_checkout", methods="GET") + * @OA\Get( + * path="/checkout", + * tags={"checkout"}, + * summary="get current checkout", + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Checkout"), + * ) + * ) + */ + public function getCheckout( + Request $request, + ModelFactory $modelFactory + ) { + $order = $this->getOrder($request); + + /** @var Checkout $checkout */ + $checkout = ($modelFactory->buildModel('Checkout')) + ->createFromOrder($order); + + $checkout->setPickupAddress($request->getSession()->get(OpenApi::PICKUP_ADDRESS_SESSION_KEY)); + + return OpenApiService::jsonResponse($checkout); + } + + protected function setOrderDeliveryPart( + Request $request, + Session $session, + EventDispatcherInterface $dispatcher, + SecurityContext $securityContext, + Checkout $checkout, + OrderEvent $orderEvent + ): void { + $cart = $session->getSessionCart($dispatcher); + $deliveryAddress = AddressQuery::create()->findPk($checkout->getDeliveryAddressId()); + $deliveryModule = ModuleQuery::create()->findPk($checkout->getDeliveryModuleId()); + + /** In case of pickup point delivery, we cannot use a Thelia address since it won't exist, so we get one from the request */ + $pickupAddress = $checkout->getPickupAddress(); + + if (null !== $deliveryAddress) { + if ($deliveryAddress->getCustomerId() !== $securityContext->getCustomerUser()->getId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'Delivery address does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + } + + if (null !== $pickupAddress && $deliveryAddress && $deliveryModule) { + if (null === AreaDeliveryModuleQuery::create()->findByCountryAndModule( + $deliveryAddress->getCountry(), + $deliveryModule + )) { + throw new \Exception( + Translator::getInstance()->trans( + 'Delivery module cannot be use with selected delivery address', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + } + + $postage = null; + if ($deliveryAddress && $deliveryModule) { + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $dispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + if (!$deliveryPostageEvent->isValidModule()) { + throw new DeliveryException( + Translator::getInstance()->trans('The delivery module is not valid.', [], Front::MESSAGE_DOMAIN) + ); + } + + $postage = $deliveryPostageEvent->getPostage(); + } + + $orderEvent->setDeliveryAddress($deliveryAddress !== null ? $deliveryAddress->getId() : $securityContext->getCustomerUser()?->getDefaultAddress()?->getId()); + $orderEvent->setDeliveryModule($deliveryModule?->getId()); + $orderEvent->setPostage($postage !== null ? $postage->getAmount() : 0.0); + $orderEvent->setPostageTax($postage !== null ? $postage->getAmountTax() : 0.0); + $orderEvent->setPostageTaxRuleTitle($postage !== null ? $postage->getTaxRuleTitle() : ''); + + $dispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_ADDRESS); + $dispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + $dispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + + if ($deliveryAddress && $deliveryModule) { + $this->checkValidDelivery(); + } + + $request->getSession()->set(OpenApi::PICKUP_ADDRESS_SESSION_KEY, json_encode($pickupAddress)); + } + + protected function setOrderInvoicePart( + EventDispatcherInterface $dispatcher, + SecurityContext $securityContext, + Checkout $checkout, + OrderEvent $orderEvent + ): void { + $billingAddress = AddressQuery::create()->findPk($checkout->getBillingAddressId()); + + if ($billingAddress) { + if ($billingAddress->getCustomerId() !== $securityContext->getCustomerUser()->getId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'Invoice address does not belong to the current customer', + [], + Front::MESSAGE_DOMAIN + ) + ); + } + } + + $paymentModule = ModuleQuery::create()->findPk($checkout->getPaymentModuleId()); + + $orderEvent->setInvoiceAddress($billingAddress !== null ? $billingAddress->getId() : null); + $orderEvent->setPaymentModule($paymentModule !== null ? $paymentModule->getId() : null); + $dispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_INVOICE_ADDRESS); + $dispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_PAYMENT_MODULE); + + // Only check invoice is module and address is set + if ($billingAddress && $paymentModule) { + $this->checkValidInvoice(); + } + } + + protected function getOrder(Request $request) + { + $session = $request->getSession(); + + if (null !== $order = $session->getOrder()) { + return $order; + } + + $order = new Order(); + + $session->setOrder($order); + + return $order; + } + + protected function checkValidDelivery(): void + { + $order = $this->getSession()->getOrder(); + if (null === $order + || + null === $order->getChoosenDeliveryAddress() + || + null === $order->getDeliveryModuleId() + || + null === AddressQuery::create()->findPk($order->getChoosenDeliveryAddress()) + || + null === ModuleQuery::create()->findPk($order->getDeliveryModuleId())) { + throw new \Exception(Translator::getInstance()->trans('Invalid delivery', [], OpenApi::DOMAIN_NAME)); + } + } + + protected function checkValidInvoice(): void + { + $order = $this->getSession()->getOrder(); + if (null === $order + || + null === $order->getChoosenInvoiceAddress() + || + null === $order->getPaymentModuleId() + || + null === AddressQuery::create()->findPk($order->getChoosenInvoiceAddress()) + || + null === ModuleQuery::create()->findPk($order->getPaymentModuleId())) { + throw new \Exception(Translator::getInstance()->trans('Invalid invoice', [], OpenApi::DOMAIN_NAME)); + } + } + + protected function checkStockNotEmpty(Cart $cart) + { + $cartItems = $cart->getCartItems(); + + foreach ($cartItems as $cartItem) { + $pse = $cartItem->getProductSaleElements(); + + $product = $cartItem->getProduct(); + + if ($pse->getQuantity() <= 0 && $product->getVirtual() !== 1) { + return false; + } + } + + return true; + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/ConfigController.php b/domokits/local/modules/OpenApi/Controller/Front/ConfigController.php new file mode 100644 index 0000000..5d282b4 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/ConfigController.php @@ -0,0 +1,54 @@ +filterByName($key)->findOne(); + if ($config && in_array($config->getId(), explode(',', OpenApi::getConfigValue('config_variables')))) { + return new JsonResponse($config->getValue()); + } + + return new JsonResponse(Translator::getInstance()->trans('You are not allowed to access this config'), 401); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/ContentController.php b/domokits/local/modules/OpenApi/Controller/Front/ContentController.php new file mode 100755 index 0000000..568bab0 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/ContentController.php @@ -0,0 +1,187 @@ +baseSearchItems("content", $request); + $contents = $query->find(); + + return OpenApiService::jsonResponse( + array_map(fn ($content) => $modelFactory->buildModel('Content', $content), iterator_to_array($contents)) + ); + } + + + /** + * @Route("/{id}", name="get_content", methods="GET", requirements={"collectionId"="\d+"}) + * + * @OA\Get( + * path="/content/{id}", + * tags={"content"}, + * summary="Get content values by ID", + * @OA\Parameter( + * name="id", + * in="path", + * required=true, + * example="1", + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Content") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + * + * @throws Exception + */ + public function getContent(ModelFactory $modelFactory, $id) + { + $content = ContentQuery::create() + ->findOneById($id); + $apiContent = $modelFactory->buildModel('Content', $content); + + if (null === $content) { + throw new Exception(Translator::getInstance()->trans('Content does not exist.', [], OpenApi::DOMAIN_NAME)); + } + + return new JsonResponse($apiContent); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/CouponController.php b/domokits/local/modules/OpenApi/Controller/Front/CouponController.php new file mode 100644 index 0000000..7942226 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/CouponController.php @@ -0,0 +1,180 @@ +getSession()->getSessionCart($dispatcher); + if (null === $cart) { + throw new \Exception(Translator::getInstance()->trans('No cart found', [], OpenApi::DOMAIN_NAME)); + } + + /** @var Coupon $openApiCoupon */ + $openApiCoupon = $modelFactory->buildModel('Coupon', $request->getContent()); + if (null === $openApiCoupon->getCode()) { + throw new \Exception(Translator::getInstance()->trans('Coupon code cannot be null', [], OpenApi::DOMAIN_NAME)); + } + + /** We verify that the given coupon actually exists in the base */ + $theliaCoupon = CouponQuery::create()->filterByCode($openApiCoupon->getCode())->findOne(); + if (null === $theliaCoupon) { + throw new \Exception(Translator::getInstance()->trans('No coupons were found for this coupon code.', [], OpenApi::DOMAIN_NAME)); + } + + try { + $event = new CouponConsumeEvent($openApiCoupon->getCode()); + $dispatcher->dispatch($event, TheliaEvents::COUPON_CONSUME); + $openApiCoupon = $modelFactory->buildModel('Coupon', $theliaCoupon); + } catch (UnmatchableConditionException $exception) { + throw new \Exception(Translator::getInstance()->trans('You should sign in or register to use this coupon.', [], OpenApi::DOMAIN_NAME)); + } + + return OpenApiService::jsonResponse($openApiCoupon); + } + + /** + * @Route("/clear_all", name="clear_all_coupon", methods="GET") + * + * @OA\Get( + * path="/coupon/clear_all", + * tags={"coupon"}, + * summary="Clear all coupons", + * + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Cart") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function clearAllCoupon( + Request $request, + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory + ) { + $cart = $request->getSession()->getSessionCart($dispatcher); + try { + $dispatcher->dispatch((new Event()), TheliaEvents::COUPON_CLEAR_ALL); + } catch (\Exception $exception) { + throw new \Exception(Translator::getInstance()->trans('An error occurred while clearing coupons : ') . $exception->getMessage()); + } + + return OpenApiService::jsonResponse($modelFactory->buildModel('Cart', $cart)); + } + + /** + * @Route("/clear/{id}", name="clear_coupon", methods="GET") + * + * @OA\Get( + * path="/coupon/clear/{id}", + * tags={"coupon"}, + * summary="Clear a specific coupon from cart", + * @OA\Parameter( + * name="id", + * in="path", + * required=true, + * example="1", + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/Cart") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function clearCoupon( + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory, + Session $session, + $id + ) { + $cart = $session->getSessionCart($dispatcher); + + try { + $coupon = CouponQuery::create()->findOneById($id); + + if (null === $coupon) { + throw new Exception(); + } + + $consumedCoupons = $session->getConsumedCoupons(); + + unset($consumedCoupons[$coupon->getCode()]); + + $session->setConsumedCoupons($consumedCoupons); + } catch (Exception $e) { + throw new Exception(Translator::getInstance()->trans('An error occurred while clearing coupon ' . $id . ' : ') . $e->getMessage()); + } + + return OpenApiService::jsonResponse($modelFactory->buildModel('Cart', $cart)); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/CustomerController.php b/domokits/local/modules/OpenApi/Controller/Front/CustomerController.php new file mode 100644 index 0000000..64dcc1c --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/CustomerController.php @@ -0,0 +1,230 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace OpenApi\Controller\Front; + +use OpenApi\Annotations as OA; +use OpenApi\Model\Api\Address as OpenApiAddress; +use OpenApi\Model\Api\Customer as OpenApiCustomer; +use OpenApi\Model\Api\ModelFactory; +use OpenApi\OpenApi; +use OpenApi\Service\OpenApiService; +use Propel\Runtime\Propel; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\SecurityContext; +use Thelia\Core\Translation\Translator; +use Thelia\Model\Address; +use Thelia\Model\Customer; + +/** + * @Route("/customer", name="customer") + */ +class CustomerController extends BaseFrontOpenApiController +{ + /** + * @Route("", name="get_customer", methods="GET") + * + * @OA\Get( + * path="/customer", + * tags={"customer"}, + * summary="Get current customer", + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/Customer" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + * ) + */ + public function getCustomer( + OpenApiService $openApiService, + ModelFactory $modelFactory + ) { + $currentCustomer = $openApiService->getCurrentCustomer(); + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $currentCustomer); + $openApiCustomer->validate(self::GROUP_READ); + + return OpenApiService::jsonResponse($openApiCustomer); + } + + /** + * @Route("", name="add_customer", methods="POST") + * + * @OA\Post( + * path="/customer", + * tags={"customer"}, + * summary="Create a new customer", + * @OA\RequestBody( + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="customer", + * type="object", + * ref="#/components/schemas/Customer", + * ), + * @OA\Property( + * property="address", + * type="object", + * ref="#/components/schemas/Address", + * ), + * @OA\Property( + * property="password", + * type="string", + * ), + * ), + * ), + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/Customer" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function createCustomer(Request $request, ModelFactory $modelFactory) + { + $data = json_decode($request->getContent(), true); + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $data['customer']); + $openApiCustomer->validate(self::GROUP_CREATE); + + /** We create a Propel transaction to save the customer and get its ID necessary for the validation + * of the address without actually commiting to the base until everything is in order. + */ + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + /** @var Customer $theliaCustomer */ + $theliaCustomer = $openApiCustomer->toTheliaModel(); + $theliaCustomer->setPassword($data['password'])->save(); + $openApiCustomer->setId($theliaCustomer->getId()); + + /** We must catch the validation exception if it is thrown to rollback the Propel transaction before throwing the exception again */ + /** @var OpenApiAddress $openApiAddress */ + $openApiAddress = $modelFactory->buildModel('Address', $data['address']); + $openApiAddress->setCustomer($openApiCustomer)->validate(self::GROUP_CREATE); + + /** @var Address $theliaAddress */ + $theliaAddress = $openApiAddress->toTheliaModel(); + $theliaAddress + ->setLabel(Translator::getInstance()->trans('Main Address', [], OpenApi::DOMAIN_NAME)) + ->setIsDefault(1) + ->save() + ; + } catch (\Exception $exception) { + $con->rollBack(); + throw $exception; + } + + /* If everything went fine, we actually commit the changes to the base. */ + $con->commit(); + + $openApiCustomer->setDefaultAddressId($theliaAddress->getId()); + + return OpenApiService::jsonResponse($openApiCustomer); + } + + /** + * @Route("", name="update_customer", methods="PATCH") + * + * @OA\Patch( + * path="/customer", + * tags={"customer"}, + * summary="Edit the current customer", + * @OA\RequestBody( + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property( + * property="customer", + * type="object", + * ref="#/components/schemas/Customer", + * ), + * @OA\Property( + * property="password", + * type="string", + * ), + * ), + * ), + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/Customer" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function updateCustomer( + Request $request, + SecurityContext $securityContext, + OpenApiService $openApiService, + ModelFactory $modelFactory + ) { + $currentCustomer = $openApiService->getCurrentCustomer(); + + $data = json_decode($request->getContent(), true); + + /** @var OpenApiCustomer $openApiCustomer */ + $openApiCustomer = $modelFactory->buildModel('Customer', $data['customer']); + $openApiCustomer->setId($currentCustomer->getId())->validate(self::GROUP_UPDATE); + + /** @var Customer $theliaCustomer */ + $theliaCustomer = $openApiCustomer->toTheliaModel(); + $theliaCustomer->setNew(false); + + if (\array_key_exists('password', $data) && null !== $newPassword = $data['password']) { + $theliaCustomer->setPassword($newPassword); + } + + $theliaCustomer->save(); + + $securityContext->setCustomerUser($theliaCustomer); + + return OpenApiService::jsonResponse($openApiCustomer); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/DeliveryController.php b/domokits/local/modules/OpenApi/Controller/Front/DeliveryController.php new file mode 100644 index 0000000..b1c0163 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/DeliveryController.php @@ -0,0 +1,403 @@ +get('stateId') ? (StateQuery::create())->filterById($request->get('stateId'))->findOne() : null; + $country = $request->get('countryId') ? (CountryQuery::create())->filterById($request->get('countryId'))->findOne() : null; + $pickupLocationEvent = new PickupLocationEvent( + null, + $request->get('radius'), + $request->get('maxRelays'), + $request->get('address'), + $request->get('city'), + $request->get('zipCode'), + $request->get('orderWeight'), + $state, + $country, + $request->get('moduleIds') + ); + + $dispatcher->dispatch($pickupLocationEvent, TheliaEvents::MODULE_DELIVERY_GET_PICKUP_LOCATIONS); + + return OpenApiService::jsonResponse( + array_map( + fn (PickupLocation $pickupLocation) => $pickupLocation->toArray(), + $pickupLocationEvent->getLocations() + ) + ); + } + + /** + * @Route("/simple-modules", name="delivery_simple_modules", methods="GET") + * + * @OA\Get( + * path="/delivery/simple-modules", + * tags={"delivery", "modules"}, + * summary="List all delivery modules as simple list (without postages and options)", + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/DeliveryModule" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function getSimpleDeliveryModules(ModelFactory $modelFactory) + { + $modules = ModuleQuery::create() + ->filterByActivate(1) + ->filterByType(BaseModule::DELIVERY_MODULE_TYPE) + ->find(); + + return OpenApiService::jsonResponse( + array_map( + function (Module $module) use ($modelFactory) { + /** @var AbstractDeliveryModule $moduleInstance */ + $moduleInstance = $module->getDeliveryModuleInstance($this->container); + + /** @var DeliveryModule $deliveryModule */ + $deliveryModule = $modelFactory->buildModel('DeliveryModule', $module); + $deliveryModule->setDeliveryMode($moduleInstance->getDeliveryMode()); + + return $deliveryModule; + }, + iterator_to_array($modules) + ) + ); + } + + /** + * @Route("/modules", name="delivery_modules", methods="GET") + * + * @OA\Get( + * path="/delivery/modules", + * tags={"delivery", "modules"}, + * summary="List all available delivery modules", + * @OA\Parameter( + * name="addressId", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="moduleId", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent( + * type="array", + * @OA\Items( + * ref="#/components/schemas/DeliveryModule" + * ) + * ) + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function getDeliveryModules( + Request $request, + SecurityContext $securityContext, + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory + ) { + $deliveryAddress = $this->getDeliveryAddress($request, $securityContext); + + if (null === $deliveryAddress) { + throw new \Exception(Translator::getInstance()->trans('You must either pass an address id or have a customer connected', [], OpenApi::DOMAIN_NAME)); + } + + $cart = $request->getSession()->getSessionCart($dispatcher); + $country = $deliveryAddress->getCountry(); + $state = $deliveryAddress->getState(); + + $moduleQuery = ModuleQuery::create() + ->filterByActivate(1) + ->filterByType(BaseModule::DELIVERY_MODULE_TYPE); + + if (null !== $moduleId = $request->get('moduleId')) { + $moduleQuery->filterById($moduleId); + } + + $modules = $moduleQuery->find(); + + $class = $this; + + return OpenApiService::jsonResponse( + array_map( + fn ($module) => $class->getDeliveryModule($module, $dispatcher, $cart, $modelFactory, $deliveryAddress, $country, $state), + iterator_to_array($modules) + ) + ); + } + + /** + * @Route("/set-delivery", name="set_delivery_modules", methods="GET") + * + * @OA\Get( + * path="/delivery/set-delivery", + * tags={"delivery", "modules"}, + * summary="Set delivery module on session to calculate postage", + * @OA\Parameter( + * name="delivery_module_id", + * in="query", + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function setDeliveryModules(Request $request) + { + $deliveryModuleId = $request->get('delivery_module_id'); + $session = $request->getSession(); + $order = $session->getOrder(); + + if (!$order) { + return new JsonResponse(); + } + + $order->setDeliveryModuleId($deliveryModuleId); + $session->setOrder($order); + + return new JsonResponse(); + } + + protected function getDeliveryModule( + Module $theliaDeliveryModule, + EventDispatcherInterface $dispatcher, + Cart $cart, + ModelFactory $modelFactory, + $address, + $country, + $state + ) { + $areaDeliveryModule = AreaDeliveryModuleQuery::create() + ->findByCountryAndModule($country, $theliaDeliveryModule, $state); + $isCartVirtual = $cart->isVirtual(); + + $isValid = true; + if (false === $isCartVirtual && null === $areaDeliveryModule) { + $isValid = false; + } + + $moduleInstance = $theliaDeliveryModule->getDeliveryModuleInstance($this->container); + + if (true === $isCartVirtual && false === $moduleInstance->handleVirtualProductDelivery()) { + $isValid = false; + } + + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $address, $country, $state); + try { + $dispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + } catch (DeliveryException $exception) { + $isValid = false; + } + + if (!$deliveryPostageEvent->isValidModule()) { + $isValid = false; + } + + $deliveryModuleOptionEvent = new DeliveryModuleOptionEvent($theliaDeliveryModule, $address, $cart, $country, $state); + + $dispatcher->dispatch( + $deliveryModuleOptionEvent, + OpenApiEvents::MODULE_DELIVERY_GET_OPTIONS + ); + + /** @var DeliveryModule $deliveryModule */ + $deliveryModule = $modelFactory->buildModel('DeliveryModule', $theliaDeliveryModule); + + $deliveryModule + ->setDeliveryMode($deliveryPostageEvent->getDeliveryMode()) + ->setValid($isValid) + ->setOptions($deliveryModuleOptionEvent->getDeliveryModuleOptions()) + ; + + return $deliveryModule; + } + + protected function getDeliveryAddress(Request $request, SecurityContext $securityContext) + { + $addressId = $request->get('addressId'); + + if (null === $addressId) { + $addressId = $request->getSession()->getOrder()->getChoosenDeliveryAddress(); + } + + if (null !== $addressId) { + $address = AddressQuery::create()->findPk($addressId); + if (null !== $address) { + return $address; + } + } + + // If no address in request or in order take customer default address + $currentCustomer = $securityContext->getCustomerUser(); + + if (null === $currentCustomer) { + return null; + } + + return $currentCustomer->getDefaultAddress(); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/FolderController.php b/domokits/local/modules/OpenApi/Controller/Front/FolderController.php new file mode 100644 index 0000000..0f45f15 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/FolderController.php @@ -0,0 +1,147 @@ +baseSearchItems("folder", $request); + $folders = $query->find(); + return OpenApiService::jsonResponse( + array_map(fn ($folder) => $modelFactory->buildModel('Folder', $folder), iterator_to_array($folders)) + ); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/PaymentController.php b/domokits/local/modules/OpenApi/Controller/Front/PaymentController.php new file mode 100644 index 0000000..1779b14 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/PaymentController.php @@ -0,0 +1,115 @@ +getSession()->getSessionCart($dispatcher); + $lang = $request->getSession()->getLang(); + $moduleQuery = ModuleQuery::create() + ->filterByActivate(1) + ->filterByType(BaseModule::PAYMENT_MODULE_TYPE) + ->orderByPosition(); + + if (null !== $moduleId = $request->get('moduleId')) { + $moduleQuery->filterById($moduleId); + } + + $modules = $moduleQuery->find(); + + // Return formatted valid payment + return OpenApiService::jsonResponse( + array_map( + fn ($module) => $this->getPaymentModule($dispatcher, $modelFactory, $module, $cart, $lang), + iterator_to_array($modules) + ) + ); + } + + protected function getPaymentModule( + EventDispatcherInterface $dispatcher, + ModelFactory $modelFactory, + Module $paymentModule, + Cart $cart, + Lang $lang + ) { + $paymentModule->setLocale($lang->getLocale()); + $moduleInstance = $paymentModule->getPaymentModuleInstance($this->container); + + $isValidPaymentEvent = new IsValidPaymentEvent($moduleInstance, $cart); + $dispatcher->dispatch( + $isValidPaymentEvent, + TheliaEvents::MODULE_PAYMENT_IS_VALID + ); + + /** @var PaymentModule $paymentModule */ + $paymentModule = $modelFactory->buildModel('PaymentModule', $paymentModule); + $paymentModule->setValid($isValidPaymentEvent->isValidModule()) + ->setCode($moduleInstance->getCode()) + ->setMinimumAmount($isValidPaymentEvent->getMinimumAmount()) + ->setMaximumAmount($isValidPaymentEvent->getMaximumAmount()); + + return $paymentModule; + } +} diff --git a/domokits/local/modules/OpenApi/Controller/Front/ProductController.php b/domokits/local/modules/OpenApi/Controller/Front/ProductController.php new file mode 100644 index 0000000..16cb416 --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/Front/ProductController.php @@ -0,0 +1,213 @@ +get('id')) { + $productQuery->filterById($id); + } + + if (null !== $ids = $request->get('ids')) { + $productQuery->filterById($ids, Criteria::IN); + } + + if (null !== $reference = $request->get('reference')) { + $productQuery->filterByRef($reference); + } + + $productQuery->filterByVisible((bool) json_decode(json_encode($request->get('visible', true)))); + + $order = $request->get('order', 'alpha'); + $locale = $request->get('locale', $request->getSession()->getLang()->getLocale()); + $title = $request->get('title'); + $description = $request->get('description'); + $chapo = $request->get('chapo'); + $postscriptum = $request->get('postscriptum'); + + $productQuery + ->limit($request->get('limit', 20)) + ->offset($request->get('offset', 0)); + + switch ($order) { + case 'created': + $productQuery->orderByCreatedAt(); + break; + case 'created_reverse': + $productQuery->orderByCreatedAt(Criteria::DESC); + break; + } + + if (null !== $title || null !== $description || null !== $chapo || null !== $postscriptum) { + $productI18nQuery = $productQuery + ->useProductI18nQuery() + ->filterByLocale($locale); + + if (null !== $title) { + $productI18nQuery->filterByTitle('%'.$title.'%', Criteria::LIKE); + } + + if (null !== $description) { + $productI18nQuery->filterByDescription('%'.$description.'%', Criteria::LIKE); + } + + if (null !== $chapo) { + $productI18nQuery->filterByChapo('%'.$chapo.'%', Criteria::LIKE); + } + + if (null !== $postscriptum) { + $productI18nQuery->filterByPostscriptum('%'.$postscriptum.'%', Criteria::LIKE); + } + + switch ($order) { + case 'alpha': + $productI18nQuery->orderByTitle(); + break; + case 'alpha_reverse': + $productI18nQuery->orderByTitle(Criteria::DESC); + break; + } + + $productI18nQuery->endUse(); + } + + $products = $productQuery->find(); + + $products = array_map(fn ($product) => $modelFactory->buildModel('Product', $product), iterator_to_array($products)); + + return OpenApiService::jsonResponse($products); + } +} diff --git a/domokits/local/modules/OpenApi/Controller/OpenApiController.php b/domokits/local/modules/OpenApi/Controller/OpenApiController.php new file mode 100644 index 0000000..e65a2ce --- /dev/null +++ b/domokits/local/modules/OpenApi/Controller/OpenApiController.php @@ -0,0 +1,56 @@ +toJson(), true); + + $modelAnnotations = $annotations['components']['schemas']; + foreach ($modelAnnotations as $modelName => $modelAnnotation) { + $isExtend = preg_match('/.*(Extend)(.*)/', $modelName, $matches); + if (!$isExtend) { + continue; + } + + $modelExtendedName = $matches[2]; + + $modelAnnotations[$modelExtendedName] = array_replace_recursive($modelAnnotations[$modelExtendedName], $modelAnnotation); + unset($modelAnnotations[$modelName]); + } + + $annotations['components']['schemas'] = $modelAnnotations; + + $host = $request->getSchemeAndHttpHost(); + $annotations['servers'] = [ + ['url' => $host.'/open_api'], + ['url' => $host.'/index_dev.php/open_api'], + ]; + + return $this->render('swagger-ui', [ + 'spec' => json_encode($annotations), + ]); + } +} diff --git a/domokits/local/modules/OpenApi/EventListener/ExceptionListener.php b/domokits/local/modules/OpenApi/EventListener/ExceptionListener.php new file mode 100644 index 0000000..31872c4 --- /dev/null +++ b/domokits/local/modules/OpenApi/EventListener/ExceptionListener.php @@ -0,0 +1,77 @@ +modelFactory = $modelFactory; + } + + /** + * Convert all exception to OpenApiException if route is an open api route. + */ + public function catchAllException(ExceptionEvent $event): void + { + // Do nothing if this is already an Open Api Exception + if ($event->getThrowable() instanceof OpenApiException) { + return; + } + + // Do nothing on non-api routes + if (!$event->getRequest()->attributes->get(OpenApi::OPEN_API_ROUTE_REQUEST_KEY, false)) { + return; + } + + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + [ + 'title' => Translator::getInstance()->trans('Unexpected error', [], OpenApi::DOMAIN_NAME), + 'description' => $event->getThrowable()->getMessage(), + ] + ); + + $event->setThrowable((new OpenApiException($error))); + } + + /** + * Format OpenApiException to JSON response. + */ + public function catchOpenApiException(ExceptionEvent $event): void + { + if (!$event->getThrowable() instanceof OpenApiException) { + return; + } + + /** @var OpenApiException $openApiException */ + $openApiException = $event->getThrowable(); + + $response = new JsonResponse($openApiException->getError(), $openApiException->getHttpCode()); + $event->setResponse($response); + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::EXCEPTION => [ + ['catchOpenApiException', 256], + ['catchAllException', 512], + ], + ]; + } +} diff --git a/domokits/local/modules/OpenApi/EventListener/LogoutListener.php b/domokits/local/modules/OpenApi/EventListener/LogoutListener.php new file mode 100644 index 0000000..6354800 --- /dev/null +++ b/domokits/local/modules/OpenApi/EventListener/LogoutListener.php @@ -0,0 +1,33 @@ +request = $request; + } + + + public static function getSubscribedEvents() + { + return [ + TheliaEvents::CUSTOMER_LOGOUT => ['emptyOrderSession', 30] + ]; + } + + public function emptyOrderSession() + { + $this->request->getSession()->set('thelia.order', null); + } +} \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/EventListener/OrderListener.php b/domokits/local/modules/OpenApi/EventListener/OrderListener.php new file mode 100644 index 0000000..7fe8e35 --- /dev/null +++ b/domokits/local/modules/OpenApi/EventListener/OrderListener.php @@ -0,0 +1,58 @@ +request = $requestStack->getCurrentRequest(); + $this->modelFactory = $modelFactory; + } + + public function setPickupAddress(OrderEvent $event): void + { + /** @var Address $pickupAddress */ + $pickupAddressJson = $this->request->getSession()->get(OpenApi::PICKUP_ADDRESS_SESSION_KEY); + $pickupAddress = $this->modelFactory->buildModel('Address', $pickupAddressJson); + + if (null === $pickupAddress || null === $pickupAddress->getAddress1() || null === $pickupAddress->getCity()) { + return; + } + + $orderAddress = OrderAddressQuery::create() + ->findPK($event->getOrder()->getDeliveryOrderAddressId()) + ->setCompany($pickupAddress->getCompany()) + ->setAddress1($pickupAddress->getAddress1()) + ->setAddress2($pickupAddress->getAddress2()) + ->setAddress3($pickupAddress->getAddress3()) + ->setZipcode($pickupAddress->getZipcode()) + ->setCity($pickupAddress->getCity()) + ; + $orderAddress->save(); + $event->setDeliveryAddress($orderAddress->getId()); + + // Reset pickup address + $this->request->getSession()->set(OpenApi::PICKUP_ADDRESS_SESSION_KEY, null); + } + + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_BEFORE_PAYMENT => ['setPickupAddress', 256], + ]; + } +} diff --git a/domokits/local/modules/OpenApi/EventListener/RequestListener.php b/domokits/local/modules/OpenApi/EventListener/RequestListener.php new file mode 100644 index 0000000..4effe92 --- /dev/null +++ b/domokits/local/modules/OpenApi/EventListener/RequestListener.php @@ -0,0 +1,41 @@ +securityContext = $securityContext; + } + + public function markRequestAsOpenApi(ControllerEvent $event): void + { + $controller = $event->getController(); + if (is_array($controller) && isset($controller[0]) && $controller[0] instanceof BaseFrontOpenApiController) { + $currentRequest = $event->getRequest(); + $currentRequest->attributes->set('_previous_url', 'dont-save'); + $currentRequest->attributes->set(OpenApi::OPEN_API_ROUTE_REQUEST_KEY, true); + } + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::CONTROLLER => [ + ['markRequestAsOpenApi', 512], + ], + ]; + } +} diff --git a/domokits/local/modules/OpenApi/Events/DeliveryModuleOptionEvent.php b/domokits/local/modules/OpenApi/Events/DeliveryModuleOptionEvent.php new file mode 100644 index 0000000..f6f572c --- /dev/null +++ b/domokits/local/modules/OpenApi/Events/DeliveryModuleOptionEvent.php @@ -0,0 +1,189 @@ +module = $module; + $this->address = $address; + $this->cart = $cart; + $this->country = $country; + $this->state = $state; + + if (null === $this->module || null === $this->address) { + throw new \Exception(Translator::getInstance()->trans('Not enough informations to retrieve module options')); + } + + if (!$module->isDeliveryModule()) { + throw new \Exception(Translator::getInstance()->trans($module->getTitle().' is not a delivery module.')); + } + } + + /** + * @return array + */ + public function getDeliveryModuleOptions() + { + return $this->deliveryModuleOptions; + } + + /** + * @param array $deliveryModuleOptions + * + * @return DeliveryModuleOptionEvent + */ + public function setDeliveryModuleOptions($deliveryModuleOptions) + { + $this->deliveryModuleOptions = $deliveryModuleOptions; + + return $this; + } + + /** + * @param DeliveryModuleOption $deliveryModuleOption + * + * @return DeliveryModuleOptionEvent + */ + public function appendDeliveryModuleOptions($deliveryModuleOption) + { + $this->deliveryModuleOptions[] = $deliveryModuleOption; + + return $this; + } + + /** + * @return Module + */ + public function getModule() + { + return $this->module; + } + + /** + * @param Module $module + * + * @return DeliveryModuleOptionEvent + */ + public function setModule($module) + { + $this->module = $module; + + return $this; + } + + /** + * @return Cart + */ + public function getCart() + { + return $this->cart; + } + + /** + * @param Cart $cart + * + * @return DeliveryModuleOptionEvent + */ + public function setCart($cart) + { + $this->cart = $cart; + + return $this; + } + + /** + * @return Address + */ + public function getAddress() + { + return $this->address; + } + + /** + * @param Address $address + * + * @return DeliveryModuleOptionEvent + */ + public function setAddress($address) + { + $this->address = $address; + + return $this; + } + + /** + * @return Country + */ + public function getCountry() + { + return $this->country; + } + + /** + * @param Country $country + * + * @return DeliveryModuleOptionEvent + */ + public function setCountry($country) + { + $this->country = $country; + + return $this; + } + + /** + * @return State + */ + public function getState() + { + return $this->state; + } + + /** + * @param State $state + * + * @return DeliveryModuleOptionEvent + */ + public function setState($state) + { + $this->state = $state; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Events/ModelExtendDataEvent.php b/domokits/local/modules/OpenApi/Events/ModelExtendDataEvent.php new file mode 100644 index 0000000..8e2fae8 --- /dev/null +++ b/domokits/local/modules/OpenApi/Events/ModelExtendDataEvent.php @@ -0,0 +1,101 @@ +data; + } + + /** + * @param mixed $data + * + * @return ModelExtendDataEvent + */ + public function setData($data) + { + $this->data = $data; + + return $this; + } + + /** + * @return mixed + */ + public function getLocale() + { + return $this->locale; + } + + /** + * @param mixed $locale + * + * @return ModelExtendDataEvent + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * @return BaseApiModel + */ + public function getModel() + { + return $this->model; + } + + /** + * @param BaseApiModel $model + * + * @return ModelExtendDataEvent + */ + public function setModel($model) + { + $this->model = $model; + + return $this; + } + + /** + * @return mixed + */ + public function getExtendData() + { + return $this->extendedData; + } + + /** + * @param $key + * @param $value + * + * @return $this + */ + public function setExtendDataKeyValue($key, $value) + { + $this->extendedData[$key] = $value; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Events/ModelValidationEvent.php b/domokits/local/modules/OpenApi/Events/ModelValidationEvent.php new file mode 100644 index 0000000..a9a70ce --- /dev/null +++ b/domokits/local/modules/OpenApi/Events/ModelValidationEvent.php @@ -0,0 +1,123 @@ +model = $model; + $this->modelFactory = $modelFactory; + $this->propertyPatchPrefix = $propertyPatchPrefix; + $this->violations = $violations; + $this->groups = $groups; + } + + + /** + * @return BaseApiModel + */ + public function getModel(): BaseApiModel + { + return $this->model; + } + + /** + * @param BaseApiModel $model + */ + public function setModel(BaseApiModel $model): void + { + $this->model = $model; + } + + /** + * @return array + */ + public function getViolations() + { + return $this->violations; + } + + /** + * @param array $violations + */ + public function setViolations($violations): void + { + $this->violations = $violations; + } + + /** + * @return ModelFactory + */ + public function getModelFactory(): ModelFactory + { + return $this->modelFactory; + } + + /** + * @param ModelFactory $modelFactory + */ + public function setModelFactory(ModelFactory $modelFactory): void + { + $this->modelFactory = $modelFactory; + } + + /** + * @return string + */ + public function getPropertyPatchPrefix(): string + { + return $this->propertyPatchPrefix; + } + + /** + * @param string $propertyPatchPrefix + */ + public function setPropertyPatchPrefix(string $propertyPatchPrefix): void + { + $this->propertyPatchPrefix = $propertyPatchPrefix; + } + + /** + * @return mixed + */ + public function getGroups() + { + return $this->groups; + } + + /** + * @param mixed $groups + */ + public function setGroups($groups): void + { + $this->groups = $groups; + } + +} \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/Events/OpenApiEvents.php b/domokits/local/modules/OpenApi/Events/OpenApiEvents.php new file mode 100644 index 0000000..14941e8 --- /dev/null +++ b/domokits/local/modules/OpenApi/Events/OpenApiEvents.php @@ -0,0 +1,8 @@ +error = $error; + $this->httpCode = $httpCode; + } + + /** + * @return string + */ + public function getHttpCode() + { + return $this->httpCode; + } + + /** + * @param string $httpCode + * + * @return OpenApiException + */ + public function setHttpCode($httpCode) + { + $this->httpCode = $httpCode; + + return $this; + } + + /** + * @return Error + */ + public function getError() + { + return $this->error; + } + + /** + * @param Error $error + * + * @return OpenApiException + */ + public function setError($error) + { + $this->error = $error; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Form/ConfigForm.php b/domokits/local/modules/OpenApi/Form/ConfigForm.php new file mode 100644 index 0000000..d9e9f3e --- /dev/null +++ b/domokits/local/modules/OpenApi/Form/ConfigForm.php @@ -0,0 +1,28 @@ +formBuilder + ->add( + 'enable_config', + CollectionType::class, + [ + 'entry_type' => CheckboxType::class, + 'allow_add' => true, + 'allow_delete' => true, + ] + ) + ; + } + +} \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/Hook/BackHook.php b/domokits/local/modules/OpenApi/Hook/BackHook.php new file mode 100644 index 0000000..06fef12 --- /dev/null +++ b/domokits/local/modules/OpenApi/Hook/BackHook.php @@ -0,0 +1,17 @@ +add($this->render('configuration.html', ['configs' => $configVariables])); + } +} \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/I18n/en_US.php b/domokits/local/modules/OpenApi/I18n/en_US.php new file mode 100755 index 0000000..59f1911 --- /dev/null +++ b/domokits/local/modules/OpenApi/I18n/en_US.php @@ -0,0 +1,5 @@ + 'TEST translation constraints', +]; diff --git a/domokits/local/modules/OpenApi/I18n/fr_FR.php b/domokits/local/modules/OpenApi/I18n/fr_FR.php new file mode 100755 index 0000000..be498d9 --- /dev/null +++ b/domokits/local/modules/OpenApi/I18n/fr_FR.php @@ -0,0 +1,11 @@ + 'Le contenu demandé n\'éxiste pas.', + 'No coupons were found for this coupon code.' => 'Aucun code promo correspondant', + 'No customer found for this email.' => 'Aucun compte client correspondant', + 'This value should not be blank' => 'Cette valeur ne peut pas être vide', + 'You should sign in or register to use this coupon.' => 'Vous devez vous connecter ou vous inscrire pour utiliser ce coupon', + 'This zip code should respect the following format : %format.' => 'Ce code postal doit respecter le format suivant : %format.', + 'Your username/password pair, does not correspond to any account' => 'Votre couple identifiant/mot de passe, ne correspond à aucun compte' +]; \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/Model/Api/Address.php b/domokits/local/modules/OpenApi/Model/Api/Address.php new file mode 100644 index 0000000..3b4a1da --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Address.php @@ -0,0 +1,638 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace OpenApi\Model\Api; + +use OpenApi\Annotations as OA; +use OpenApi\Constraint; +use Thelia\Model\Address as TheliaAddress; +use Thelia\Model\CountryQuery; +use Thelia\Model\StateQuery; + +/** + * @OA\Schema( + * schema="Address", + * title="Address", + * description="Address model" + * ) + */ +class Address extends BaseApiModel +{ + public static $serviceAliases = ['PickupAddress']; + + /** + * @var int + * @OA\Property( + * type="integer" + * ) + * @Constraint\NotBlank(groups={"read", "update"}) + */ + protected $id; + + /** + * @var bool + * @OA\Property( + * type="boolean" + * ) + * @Constraint\NotNull(groups={"create", "update"}) + */ + protected $isDefault; + + /** + * @var string + * @OA\Property( + * type="string", + * description="The name for this address", + * ) + * @Constraint\NotBlank(groups={"create","update"}) + */ + protected $label; + + /** + * @var Customer + * @OA\Property( + * ref="#/components/schemas/Customer" + * ), + * @Constraint\NotNull(groups={"create","update"}) + */ + protected $customer; + + /** + * @var CivilityTitle + * @OA\Property( + * ref="#/components/schemas/CivilityTitle" + * ), + * @Constraint\NotNull(groups={"create","update"}) + */ + protected $civilityTitle; + + /** + * @var string + * @OA\Property( + * type="string", + * ), + * @Constraint\NotNull(groups={"create","update"}) + */ + protected $firstName; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotNull(groups={"create","update"}) + */ + protected $lastName; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $cellphone; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $phone; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $company; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"create","update"}) + */ + protected $address1; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $address2; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $address3; + + /** + * @var string + * @OA\Property( + * type="string", + * ), + * @Constraint\NotBlank(groups={"create","update"}) + * @Constraint\Zipcode(groups={"create","update"}) + */ + protected $zipCode; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"create","update"}) + */ + protected $city; + + /** + * @var string + * @OA\Property( + * type="string", + * description="Country ISO 3166-1 alpha-2 code" + * ) + * @Constraint\NotBlank(groups={"create","update"}) + * @Constraint\Length( + * min = 2, + * max = 2 + * ) + */ + protected $countryCode; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $stateCode; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $stateName; + + /** + * @var object + * @OA\Property( + * type="object" + * ) + */ + protected $additionalData; + + /** + * @param TheliaAddress $address + * @param string $locale + * + * @return $this|Address + * + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createFromTheliaModel($address, $locale = 'en_US') + { + parent::createFromTheliaModel($address, $locale); + + $customerTitle = $address->getCustomerTitle() + ->setLocale($locale); + + /** @var CivilityTitle $civ */ + $civ = $this->modelFactory->buildModel('Title', $customerTitle); + + $this + ->setCivilityTitle($civ) + ->setCountryCode($address->getCountry()->getIsoalpha2()) + ; + if (null !== $state = $address->getState()) { + $this + ->setStateCode($state->getIsocode()) + ->setStateName($state->setLocale($locale)->getTitle()); + } + + return $this; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return Address + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function getIsDefault() + { + return $this->isDefault; + } + + /** + * @param bool $isDefault + * + * @return Address + */ + public function setIsDefault($isDefault) + { + $this->isDefault = $isDefault; + + return $this; + } + + /** + * @return string + */ + public function getLabel() + { + return $this->label; + } + + /** + * @param string $label + * + * @return Address + */ + public function setLabel($label) + { + $this->label = $label; + + return $this; + } + + /** + * @return Customer + */ + public function getCustomer() + { + return $this->customer; + } + + /** + * @param Customer $customer + * + * @return Address + */ + public function setCustomer($customer) + { + $this->customer = $customer; + + return $this; + } + + /** + * @return CivilityTitle + */ + public function getCivilityTitle() + { + return $this->civilityTitle; + } + + /** + * @param CivilityTitle $civilityTitle + * + * @return Address + */ + public function setCivilityTitle($civilityTitle) + { + $this->civilityTitle = $civilityTitle; + + return $this; + } + + /** + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * @param string $firstName + * + * @return Address + */ + public function setFirstName($firstName) + { + $this->firstName = $firstName; + + return $this; + } + + /** + * @return string + */ + public function getLastName() + { + return $this->lastName; + } + + /** + * @param string $lastName + * + * @return Address + */ + public function setLastName($lastName) + { + $this->lastName = $lastName; + + return $this; + } + + /** + * @return string + */ + public function getCompany() + { + return $this->company; + } + + /** + * @param string $company + * + * @return Address + */ + public function setCompany($company) + { + $this->company = $company; + + return $this; + } + + /** + * @return string + */ + public function getAddress1() + { + return $this->address1; + } + + /** + * @param string $address1 + * + * @return Address + */ + public function setAddress1($address1) + { + $this->address1 = $address1; + + return $this; + } + + /** + * @return string + */ + public function getAddress2() + { + return $this->address2; + } + + /** + * @param string $address2 + * + * @return Address + */ + public function setAddress2($address2) + { + $this->address2 = $address2; + + return $this; + } + + /** + * @return string + */ + public function getAddress3() + { + return $this->address3; + } + + /** + * @param string $address3 + * + * @return Address + */ + public function setAddress3($address3) + { + $this->address3 = $address3; + + return $this; + } + + /** + * @return string + */ + public function getZipCode() + { + return $this->zipCode; + } + + /** + * @param string $zipCode + * + * @return Address + */ + public function setZipCode($zipCode) + { + $this->zipCode = $zipCode; + + return $this; + } + + /** + * @return string + */ + public function getCity() + { + return $this->city; + } + + /** + * @param string $city + * + * @return Address + */ + public function setCity($city) + { + $this->city = $city; + + return $this; + } + + /** + * @return string + */ + public function getCountryCode() + { + return $this->countryCode; + } + + /** + * @param string $countryCode + * + * @return Address + */ + public function setCountryCode($countryCode) + { + $this->countryCode = $countryCode; + + return $this; + } + + /** + * @return object + */ + public function getAdditionalData() + { + return $this->additionalData; + } + + /** + * @param object $additionalData + * + * @return Address + */ + public function setAdditionalData($additionalData) + { + $this->additionalData = $additionalData; + + return $this; + } + + /** Thelia model creation functions */ + + /** + * @return int + */ + public function getTitleId() + { + $civilityTitle = $this->getCivilityTitle(); + + return null !== $civilityTitle ? $civilityTitle->getId() : null; + } + + /** + * @return int + */ + public function getCustomerId() + { + $customer = $this->getCustomer(); + + return null !== $customer ? $customer->getId() : null; + } + + public function getCountryId() + { + $country = CountryQuery::create()->filterByIsoalpha2($this->getCountryCode())->findOne(); + + return null !== $country ? $country->getId() : null; + } + + /* + * @return string + */ + public function getPhone() + { + return $this->phone; + } + + /* + * @return string + */ + public function getCellphone() + { + return $this->cellphone; + } + + /** + * @param string $phone + * + * @return Address + */ + public function setPhone($phone) + { + $this->phone = $phone; + + return $this; + } + + /** + * @param string $cellphone + * + * @return Address + */ + public function setCellphone($cellphone) + { + $this->cellphone = $cellphone; + + return $this; + } + + public function getStateCode(): ?string + { + return $this->stateCode; + } + + public function setStateCode(string $stateCode = null) + { + $this->stateCode = $stateCode; + + return $this; + } + + public function getStateId() + { + $state = StateQuery::create()->filterByCountryId($this->getCountryId())->filterByIsocode($this->getStateCode())->findOne(); + + return null !== $state ? $state->getId() : null; + } + + /** + * @return string + */ + public function getStateName(): ?string + { + return $this->stateName; + } + + /** + * @param string $stateName + */ + public function setStateName(string $stateName = null) + { + $this->stateName = $stateName; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Attribute.php b/domokits/local/modules/OpenApi/Model/Api/Attribute.php new file mode 100644 index 0000000..2210a39 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Attribute.php @@ -0,0 +1,103 @@ +id; + } + + /** + * @param int $id + * + * @return Attribute + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return array + */ + public function getValues() + { + return $this->values; + } + + /** + * @param array $values + * + * @return Attribute + */ + public function setValues($values) + { + $this->values = $values; + + return $this; + } + + /** + * "setAttributeId" alias to fit Thelia model. + * + * @param int $id + * + * @return Attribute + */ + public function setAttributeId($id) + { + return $this->setId($id); + } + + /** + * "setValues" alias to fit Thelia model. + * + * @param array $values + * + * @return Attribute + */ + public function setAttributeAvs($values) + { + return $this->setValues($values); + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/AttributeValue.php b/domokits/local/modules/OpenApi/Model/Api/AttributeValue.php new file mode 100644 index 0000000..2bd7908 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/AttributeValue.php @@ -0,0 +1,60 @@ +id; + } + + /** + * @param int $id + * + * @return AttributeValue + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * "setAttributeAvId" alias to fit Thelia model. + * + * @param int $id + * + * @return AttributeValue + */ + public function setAttributeAvId($id) + { + return $this->setId($id); + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/BaseApiModel.php b/domokits/local/modules/OpenApi/Model/Api/BaseApiModel.php new file mode 100644 index 0000000..d3ed923 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/BaseApiModel.php @@ -0,0 +1,352 @@ +dispatcher = $dispatcher; + $this->validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->getValidator(); + + $this->modelFactory = $modelFactory; + $this->request = $requestStack->getCurrentRequest(); + $this->country = $taxEngine->getDeliveryCountry(); + $this->state = $taxEngine->getDeliveryState(); + + if (method_exists($this, 'initI18n')) { + $this->initI18n($modelFactory); + } + } + + public function getCurrentLocale() + { + return $this->request?->getSession()?->getLang(true)->getLocale(); + } + + /** + * @param $groups + * + * @return BaseApiModel + * + * @throws OpenApiException + */ + public function validate($groups, $recursively = true) + { + $violations = $this->getViolations($groups, $recursively); + + if (empty($violations)) { + return $this; + } + + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + ['title' => Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME)] + ); + + $error->setSchemaViolations($violations); + + throw new OpenApiException($error); + } + + public function getViolations($groups, $recursively = true, $propertyPatchPrefix = '') + { + $modelFactory = $this->modelFactory; + $violations = array_reduce( + iterator_to_array($this->validator->validate($this, null, $groups)), + function ($carry, $violation) use ($modelFactory, $propertyPatchPrefix) { + $carry[$propertyPatchPrefix.$violation->getPropertyPath()] = $modelFactory->buildModel('SchemaViolation', ['message' => $violation->getMessage()]); + return $carry; + }, + [] + ); + + if ($recursively === true) { + foreach (get_object_vars($this) as $key => $value) { + if ($value instanceof self) { + $violations = array_merge($violations, $value->getViolations('read', true, $propertyPatchPrefix.$key.'.')); + } + } + } + + $event = new ModelValidationEvent($this, $modelFactory, $groups, $propertyPatchPrefix); + $this->dispatcher->dispatch($event, ModelValidationEvent::MODEL_VALIDATION_EVENT_PREFIX.$this->snakeCaseName()); + + return array_merge($violations, $event->getViolations()); + } + + public function jsonSerialize() + { + $normalizer = new ModelApiNormalizer(); + $serializer = new Serializer([$normalizer]); + + return $serializer->normalize($this, null); + } + + public function createOrUpdateFromData($data, $locale = null): void + { + if (null === $locale) { + $locale = $this->getCurrentLocale(); + } + + if (\is_object($data)) { + $this->createFromTheliaModel($data, $locale); + } + + if (\is_string($data)) { + $data = json_decode($data, true); + } + + if (\is_array($data) || $data instanceof \Traversable) { + foreach ($data as $key => $value) { + $setMethodName = 'set'.ucfirst($key); + $getMethodName = 'get'.ucfirst($key); + if (method_exists($this, $setMethodName)) { + if (\is_array($value)) { + if (method_exists($this, $getMethodName) && $this->$getMethodName() instanceof self) { + $this->$setMethodName($this->$getMethodName()->updateFromData($value)); + continue; + } + $openApiModel = $this->modelFactory->buildModel(ucfirst($key), $value); + $value = null !== $openApiModel ? $openApiModel : $value; + } + $this->$setMethodName($value); + } + } + } + + $modelExtendEvent = (new ModelExtendDataEvent()) + ->setData($data) + ->setLocale($locale) + ->setModel($this); + + $this->dispatcher->dispatch( + $modelExtendEvent, + ModelExtendDataEvent::ADD_EXTEND_DATA_PREFIX.$this->snakeCaseName() + ); + + $this->setExtendData($modelExtendEvent->getExtendData()); + } + + /** + * Override to return the propel model associated with the OpenApi model instead of null. + * + * @return mixed + */ + protected function getTheliaModel($propelModelName = null) + { + if (null === $propelModelName) { + $propelModelName = "Thelia\Model\\".basename(str_replace('\\', '/', static::class)); + } + + if (!class_exists($propelModelName)) { + return null; + } + + if (method_exists($this, 'getId') && null !== $id = $this->getId()) { + $theliaModelQueryName = $propelModelName.'Query'; + + return $theliaModelQueryName::create()->filterById($id)->findOne(); + } + + /** @var ActiveRecordInterface $newTheliaModel */ + $newTheliaModel = new $propelModelName(); + $newTheliaModel->setNew(true); + + return $newTheliaModel; + } + + public function toTheliaModel($locale = null) + { + if (null === $theliaModel = $this->getTheliaModel()) { + throw new \Exception(Translator::getInstance()->trans('Propel model not found automatically for class %className%. Please override the getTheliaModel method to use the toTheliaModel method.', ['%className%' => basename(static::class)], OpenApi::DOMAIN_NAME)); + } + + // If model need locale, set it + if (method_exists($theliaModel, 'setLocale')) { + $theliaModel->setLocale($locale !== null ? $locale : $this->getCurrentLocale()); + } + + // Look all method of Open API model + foreach (get_class_methods($this) as $methodName) { + $getter = $methodName; + $setter = null; + + // If it's not a getter skip it + if (0 === strncasecmp('get', $methodName, 3)) { + // Build thelia setter name + $setter = 'set'.substr($getter, 3); + } + + // For boolean method like "isVisible" + if ($setter === null && 0 === strncasecmp('is', $methodName, 2)) { + // Build thelia setter name + $setter = 'set'.substr($getter, 2); + } + + // Check if setter exist in Thelia model + if (null === $setter || !method_exists($theliaModel, $setter)) { + continue; + } + + $value = $this->$getter(); + + // If Values are the same skip this property + if (method_exists($theliaModel, $getter) && $theliaModel->$getter() === $value) { + continue; + } + + // if the property is another Api model + if ($value instanceof self) { + // If it doesn't have a correspondant thelia model skip it + if (null === $value->getTheliaModel()) { + continue; + } + + // Else try to set the model id + $setModelIdMethod = $setter.'Id'; + if (!method_exists($theliaModel, $setModelIdMethod)) { + continue; + } + $setter = $setModelIdMethod; + $value = $value->getId(); + } + + // Todo transform array to collection + if (is_array($value)) { + continue; + } + + $theliaModel->$setter($value); + } + + return $theliaModel; + } + + public function createFromTheliaModel($theliaModel, $locale = null) + { + if (method_exists($theliaModel, 'setLocale')) { + $theliaModel->setLocale($locale !== null ? $locale : $this->getCurrentLocale()); + } + + foreach (get_class_methods($this) as $modelMethod) { + if (0 === strncasecmp('set', $modelMethod, 3)) { + $property = ucfirst(substr($modelMethod, 3)); + $lowercaseProperty = ucfirst(strtolower($property)); + + // List all possible getters for this property in propel + $propelPossibleMethods = [ // EXAMPLE : + 'get'.$property, // getProductSaleElements + 'get'.$property.'s', // getProductSaleElementss + 'get'.$lowercaseProperty, // getProductsaleelements + 'get'.$lowercaseProperty.'s', // getProductsaleelementss + 'get'.$property.'Model', // getProductSaleElementsModel + 'get'.$lowercaseProperty.'Model', // getProductsaleelementsModel + 'get'.substr(\get_class($theliaModel), strrpos(\get_class($theliaModel), '\\') + 1).$property, // getCartProductSaleElements + 'get'.substr(\get_class($theliaModel), strrpos(\get_class($theliaModel), '\\') + 1).$lowercaseProperty, // getCartProductsaleelements + ]; + + $availableMethods = array_filter(array_intersect($propelPossibleMethods, get_class_methods($theliaModel))); + + if (empty($availableMethods)) { + continue; + } + + $theliaValue = null; + while (!empty($availableMethods) && ($theliaValue === null || empty($theliaValue))) { + $theliaMethod = array_pop($availableMethods); + + $theliaValue = $theliaModel->$theliaMethod(); + + if ($theliaValue instanceof Collection) { + $theliaValue = array_filter(array_map(fn ($value) => $this->modelFactory->buildModel($property, $value), iterator_to_array($theliaValue))); + continue; + } + + if (\is_object($theliaValue) && $this->modelFactory->modelExists($property)) { + $theliaValue = $this->modelFactory->buildModel($property, $theliaValue); + } + } + + $this->$modelMethod($theliaValue); + } + } + + return $this; + } + + public function setExtendData($extendedData) + { + $this->extendedData = $extendedData; + + return $this; + } + + public function extendedDataValue() + { + return $this->extendedData; + } + + protected function snakeCaseName() + { + $name = basename(str_replace('\\', '/', static::class)); + + preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $name, $matches); + $ret = $matches[0]; + foreach ($ret as &$match) { + $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); + } + + return implode('_', $ret); + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Brand.php b/domokits/local/modules/OpenApi/Model/Api/Brand.php new file mode 100644 index 0000000..49bebac --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Brand.php @@ -0,0 +1,74 @@ +id; + } + + /** + * @param int $id + * + * @return Brand + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return Brand + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Cart.php b/domokits/local/modules/OpenApi/Model/Api/Cart.php new file mode 100644 index 0000000..8519ed3 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Cart.php @@ -0,0 +1,467 @@ +container = $container; + } + + public function createFromTheliaModel($theliaModel, $locale = null): void + { + parent::createFromTheliaModel($theliaModel, $locale); + $postageInfo = $this->getEstimatedPostageForCountry($theliaModel, $this->country, $this->state); + $estimatedPostage = $postageInfo['postage']; + $postageTax = $postageInfo['tax']; + + $consumedCoupons = $this->request->getSession()->getConsumedCoupons(); + $coupons = $this->createOpenApiCouponsFromCouponsCodes($consumedCoupons); + + $modelFactory = $this->modelFactory; + $deliveryCountry = $this->country; + $cartItems = array_map( + function ($theliaCartItem) use ($modelFactory, $deliveryCountry) { + /** @var CartItem $cartItem */ + $cartItem = $modelFactory->buildModel('CartItem', $theliaCartItem); + $cartItem->fillFromTheliaCartItemAndCountry($theliaCartItem, $deliveryCountry); + + return $cartItem; + }, + iterator_to_array($theliaModel->getCartItems()) + ); + + $this + ->setDeliveryTax($postageTax) + ->setTaxes($theliaModel->getTotalVAT($deliveryCountry, null, false)) + ->setDelivery($estimatedPostage) + ->setCoupons($coupons) + ->setTotal($theliaModel->getTaxedAmount($deliveryCountry, false, null)) + ->setCurrency($theliaModel->getCurrency()->getSymbol()) + ->setItems($cartItems) + ->setVirtual($theliaModel->isVirtual()); + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return Cart + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return float + */ + public function getTaxes() + { + return $this->taxes; + } + + /** + * @param float $taxes + * + * @return Cart + */ + public function setTaxes($taxes) + { + $this->taxes = $taxes; + + return $this; + } + + /** + * @return float + */ + public function getDelivery() + { + return $this->delivery; + } + + /** + * @param float $delivery + * + * @return Cart + */ + public function setDelivery($delivery) + { + $this->delivery = $delivery; + + return $this; + } + + /** + * @return array + */ + public function getCoupons() + { + return $this->coupons; + } + + /** + * @param array $coupons + * + * @return Cart + */ + public function setCoupons($coupons) + { + $this->coupons = $coupons; + + return $this; + } + + /** + * @return float + */ + public function getDeliveryTax() + { + return $this->deliveryTax; + } + + /** + * @param float $deliveryTax + */ + public function setDeliveryTax($deliveryTax) + { + $this->deliveryTax = $deliveryTax; + + return $this; + } + + + + /** + * @return float + */ + public function getDiscount() + { + return $this->discount; + } + + /** + * @param float $discount + * + * @return Cart + */ + public function setDiscount($discount) + { + $this->discount = (float)$discount; + return $this; + } + + /** + * @return boolean + */ + public function getVirtual() + { + return $this->virtual; + } + + /** + * @param boolean $virtual + * @return Cart + */ + public function setVirtual($virtual) + { + $this->virtual = $virtual; + return $this; + } + + /** + * @return float + */ + public function getTotal() + { + return $this->total; + } + + /** + * @param float $total + * + * @return Cart + */ + public function setTotal($total) + { + $this->total = $total; + + return $this; + } + + /** + * @return string + */ + public function getCurrency() + { + return $this->currency; + } + + /** + * @param string $currency + * + * @return Cart + */ + public function setCurrency($currency) + { + $this->currency = $currency; + + return $this; + } + + /** + * @return array + */ + public function getItems() + { + return $this->items; + } + + /** + * @param array $items + * + * @return Cart + */ + public function setItems($items) + { + $this->items = $items; + + return $this; + } + + /** + * Creates an array of OpenApi coupons from an array of coupons codes, then returns it. + * + * @param $couponsCodes + * + * @return array + */ + protected function createOpenApiCouponsFromCouponsCodes($couponsCodes) + { + $coupons = CouponQuery::create()->filterByCode($couponsCodes)->find(); + + $factory = $this->modelFactory; + + return array_map( + fn ($coupon) => $factory->buildModel('Coupon', $coupon), + iterator_to_array($coupons) + ); + } + + /** + * Return the minimum expected postage for a cart in a given country. + * + * @return array + * + * @throws \Propel\Runtime\Exception\PropelException + */ + protected function getEstimatedPostageForCountry(\Thelia\Model\Cart $cart, Country $country, State $state = null) + { + $orderSession = $this->request->getSession()->getOrder(); + $deliveryModules = []; + + if ($deliveryModule = ModuleQuery::create()->findPk($orderSession->getDeliveryModuleId())) { + $deliveryModules[] = $deliveryModule; + } + + if (empty($deliveryModules)) { + $deliveryModules = ModuleQuery::create() + ->filterByActivate(1) + ->filterByType(BaseModule::DELIVERY_MODULE_TYPE, Criteria::EQUAL) + ->find(); + } + + $virtual = $cart->isVirtual(); + $postage = null; + $postageTax = null; + + /** @var \Thelia\Model\Module $deliveryModule */ + foreach ($deliveryModules as $deliveryModule) { + $areaDeliveryModule = AreaDeliveryModuleQuery::create() + ->findByCountryAndModule($country, $deliveryModule, $state); + + if (null === $areaDeliveryModule && false === $virtual) { + continue; + } + + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + + if (true === $virtual && false === $moduleInstance->handleVirtualProductDelivery()) { + continue; + } + + try { + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, null, $country, $state); + $this->dispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + if ($deliveryPostageEvent->isValidModule()) { + $modulePostage = $deliveryPostageEvent->getPostage(); + + if (null === $postage || $postage > $modulePostage->getAmount()) { + $postage = $modulePostage->getAmount() - $modulePostage->getAmountTax(); + $postageTax = $modulePostage->getAmountTax(); + } + } + } catch (DeliveryException $ex) { + // Module is not available + } + } + + return [ + 'postage' => $postage, + 'tax' => $postageTax + ]; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/CartItem.php b/domokits/local/modules/OpenApi/Model/Api/CartItem.php new file mode 100644 index 0000000..69e2d80 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/CartItem.php @@ -0,0 +1,309 @@ +id = $cartItem->getId(); + /** @var Product $product */ + $product = $this->modelFactory->buildModel('Product', $cartItem->getProduct()); + $this->product = $product; + + /** @var ProductSaleElement $productSaleElements */ + $productSaleElements = $this->modelFactory->buildModel('ProductSaleElement'); + $productSaleElements->fillFromTheliaPseAndCountry($cartItem->getProductSaleElements(), $country); + $this->productSaleElement = $productSaleElements; + + $this->isPromo = (bool) $cartItem->getPromo(); + $this->price = $this->modelFactory->buildModel( + 'Price', + [ + 'taxed' => $cartItem->getTaxedPrice($country), + 'untaxed' => $cartItem->getPrice(), + ] + ); + $this->promoPrice = $this->modelFactory->buildModel( + 'Price', + [ + 'taxed' => $cartItem->getTaxedPromoPrice($country), + 'untaxed' => $cartItem->getPromoPrice(), + ] + ); + $this->quantity = $cartItem->getQuantity(); + + /** If there are PSE specific images, we use them. Otherwise, we just use the product images */ + $modelFactory = $this->modelFactory; + + try { + $images = array_map( + fn ($productSaleElementsImage) => $modelFactory->buildModel('Image', $productSaleElementsImage->getProductImage()), + iterator_to_array($cartItem->getProductSaleElements()->getProductSaleElementsProductImages()) + ); + } catch (\Exception $exception) { + $images = []; + } + + $this->images = !empty($images) ? $images : $this->product->getImages(); + + return $this; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return CartItem + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isPromo() + { + return $this->isPromo; + } + + /** + * @param bool $isPromo + * + * @return CartItem + */ + public function setIsPromo($isPromo) + { + $this->isPromo = $isPromo; + + return $this; + } + + /** + * @return Product + */ + public function getProduct() + { + return $this->product; + } + + /** + * @param Product $product + * + * @return CartItem + */ + public function setProduct($product) + { + $this->product = $product; + + return $this; + } + + /** + * @return ProductSaleElement + */ + public function getProductSaleElement() + { + return $this->productSaleElement; + } + + /** + * @param ProductSaleElement $productSaleElement + * + * @return CartItem + */ + public function setProductSaleElement($productSaleElement) + { + $this->productSaleElement = $productSaleElement; + + return $this; + } + + /** + * @return array + */ + public function getImages() + { + return $this->images; + } + + /** + * @param array $images + * + * @return CartItem + */ + public function setImages($images) + { + $this->images = $images; + + return $this; + } + + /** + * @return Price + */ + public function getPrice() + { + return $this->price; + } + + /** + * @param Price $price + * + * @return CartItem + */ + public function setPrice($price) + { + $this->price = $price; + + return $this; + } + + /** + * @return Price + */ + public function getPromoPrice() + { + return $this->promoPrice; + } + + /** + * @param Price $promoPrice + * + * @return CartItem + */ + public function setPromoPrice($promoPrice) + { + $this->promoPrice = $promoPrice; + + return $this; + } + + /** + * @return int + */ + public function getQuantity() + { + return $this->quantity; + } + + /** + * @param int $quantity + * + * @return CartItem + */ + public function setQuantity($quantity) + { + $this->quantity = $quantity; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Category.php b/domokits/local/modules/OpenApi/Model/Api/Category.php new file mode 100644 index 0000000..0c3b0e7 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Category.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace OpenApi\Model\Api; + +use OpenApi\Annotations as OA; +use OpenApi\Constraint; +use OpenApi\Model\Api\ModelTrait\translatable; + +/** + * Class Category. + * + * @OA\Schema( + * description="A Category" + * ) + */ +class Category extends BaseApiModel +{ + use translatable; + + /** + * @var int + * + * @OA\Property( + * type="integer", + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $id; + + /** + * @var bool + * + * @OA\Property( + * type="boolean", + * ) + */ + protected $visible; + + /** + * @var string + * + * @OA\Property( + * type="string", + * ) + */ + protected $url; + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return Category + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return Category + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string $url + * + * @return Category + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Checkout.php b/domokits/local/modules/OpenApi/Model/Api/Checkout.php new file mode 100644 index 0000000..7c0e0e6 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Checkout.php @@ -0,0 +1,309 @@ +setDeliveryAddressId($order->getChoosenDeliveryAddress()); + $this->setBillingAddressId($order->getChoosenInvoiceAddress()); + + $this->setDeliveryModuleId($order->getDeliveryModuleId()) + ->setPaymentModuleId($order->getPaymentModuleId()); + + return $this; + } + + /** + * @OA\Property( + * property="isComplete", + * description="Tell if a checkout has defined a Module and an Address for both delivery and billing", + * type="boolean" + * ) + * + * @return bool + */ + public function getIsComplete() + { + if (null === $this->getDeliveryModuleId()) { + return false; + } + + if (null === $this->getDeliveryAddressId()) { + return false; + } + + if (null === $this->getBillingAddressId()) { + return false; + } + + if (null === $this->getPaymentModuleId()) { + return false; + } + + return true; + } + + /** + * @throws \Exception + */ + public function checkIsValid(): void + { + if (null === $this->getDeliveryModuleId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'You must choose a delivery module', + [], + OpenApi::DOMAIN_NAME + ) + ); + } + + if (null === $this->getPaymentModuleId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'You must choose a payment module', + [], + OpenApi::DOMAIN_NAME + ) + ); + } + + if (null === $this->getDeliveryAddressId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'You must choose a delivery address', + [], + OpenApi::DOMAIN_NAME + ) + ); + } + + if (null === $this->getBillingAddressId()) { + throw new \Exception( + Translator::getInstance()->trans( + 'You must choose a billing address', + [], + OpenApi::DOMAIN_NAME + ) + ); + } + + if (false === $this->isAcceptedTermsAndConditions()) { + throw new \Exception( + Translator::getInstance()->trans( + 'You must accept the terms and conditions', + [], + OpenApi::DOMAIN_NAME + ) + ); + } + } + + /** + * @return int + */ + public function getDeliveryModuleId() + { + return $this->deliveryModuleId; + } + + /** + * @param int $deliveryModuleId + * + * @return Checkout + */ + public function setDeliveryModuleId($deliveryModuleId) + { + $this->deliveryModuleId = $deliveryModuleId; + + return $this; + } + + /** + * @return int + */ + public function getPaymentModuleId() + { + return $this->paymentModuleId; + } + + /** + * @param int $paymentModuleId + * + * @return Checkout + */ + public function setPaymentModuleId($paymentModuleId) + { + $this->paymentModuleId = $paymentModuleId; + + return $this; + } + + /** + * @return int + */ + public function getBillingAddressId() + { + return $this->billingAddressId; + } + + /** + * @param int $billingAddressId + * + * @return Checkout + */ + public function setBillingAddressId($billingAddressId) + { + $this->billingAddressId = $billingAddressId; + + return $this; + } + + /** + * @return int + */ + public function getDeliveryAddressId() + { + return $this->deliveryAddressId; + } + + /** + * @param int $deliveryAddressId + * + * @return Checkout + */ + public function setDeliveryAddressId($deliveryAddressId) + { + $this->deliveryAddressId = $deliveryAddressId; + + return $this; + } + + /** + * @return Address + */ + public function getPickupAddress() + { + return $this->pickupAddress; + } + + /** + * @param Address $pickupAddress + * + * @return Checkout + */ + public function setPickupAddress($pickupAddress) + { + $this->pickupAddress = $pickupAddress; + + return $this; + } + + public function isAcceptedTermsAndConditions(): bool + { + return $this->acceptedTermsAndConditions; + } + + public function setAcceptedTermsAndConditions(bool $acceptedTermsAndConditions): self + { + $this->acceptedTermsAndConditions = $acceptedTermsAndConditions; + + return $this; + } + + /** + * @return string + */ + public function getDeliveryModuleOptionCode() + { + return $this->deliveryModuleOptionCode; + } + + /** + * @param $deliveryModuleOptionCode + * @return Checkout + */ + public function setDeliveryModuleOptionCode($deliveryModuleOptionCode) + { + $this->deliveryModuleOptionCode = $deliveryModuleOptionCode; + return $this; + } + + +} diff --git a/domokits/local/modules/OpenApi/Model/Api/CivilityTitle.php b/domokits/local/modules/OpenApi/Model/Api/CivilityTitle.php new file mode 100644 index 0000000..d77ed64 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/CivilityTitle.php @@ -0,0 +1,112 @@ +id; + } + + /** + * @param int $id + * + * @return CivilityTitle + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getShort() + { + return $this->short; + } + + /** + * @param string $short + * + * @return CivilityTitle + */ + public function setShort($short) + { + $this->short = $short; + + return $this; + } + + /** + * @return string + */ + public function getLong() + { + return $this->long; + } + + /** + * @param string $long + * + * @return CivilityTitle + */ + public function setLong($long) + { + $this->long = $long; + + return $this; + } + + /** + * @return CustomerTitle + */ + protected function getCustomerTitle() + { + return new CustomerTitle(); + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Content.php b/domokits/local/modules/OpenApi/Model/Api/Content.php new file mode 100644 index 0000000..e5e8b91 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Content.php @@ -0,0 +1,75 @@ +id; + } + + /** + * @param int $id + * + * @return Content + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return Content + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Coupon.php b/domokits/local/modules/OpenApi/Model/Api/Coupon.php new file mode 100644 index 0000000..4837106 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Coupon.php @@ -0,0 +1,104 @@ +id; + } + + /** + * @param int $id + * + * @return Coupon + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * @param string $code + * + * @return Coupon + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * @return float + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param float $amount + * + * @return Coupon + */ + public function setAmount($amount) + { + $this->amount = $amount; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Customer.php b/domokits/local/modules/OpenApi/Model/Api/Customer.php new file mode 100644 index 0000000..cf08b33 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Customer.php @@ -0,0 +1,381 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace OpenApi\Model\Api; + +use OpenApi\Annotations as OA; +use OpenApi\Constraint; + +/** + * @OA\Schema( + * schema="Customer", + * title="Customer", + * description="Customer model" + * ) + */ +class Customer extends BaseApiModel +{ + /** + * @var int + * @OA\Property( + * type="integer", + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $id; + + /** + * @var CivilityTitle + * @OA\Property( + * type="object", + * ref="#/components/schemas/CivilityTitle", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $civilityTitle; + + /** + * @var Lang + * @OA\Property( + * type="object", + * ref="#/components/schemas/Lang", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $lang; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"update"}) + */ + protected $reference; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $firstName; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $lastName; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $email; + + /** + * @var bool + * @OA\Property( + * type="boolean", + * ) + */ + protected $rememberMe; + + /** + * @var float + * @OA\Property( + * type="number", + * format="float", + * ) + * @Constraint\NotBlank(groups={"create", "update"}) + */ + protected $discount; + + /** + * @var bool + * @OA\Property( + * type="boolean", + * ) + */ + protected $reseller; + + /** + * @var int + * @OA\Property( + * type="integer", + * ) + */ + protected $defaultAddressId; + + public function createFromTheliaModel($theliaModel, $locale = null): void + { + parent::createFromTheliaModel($theliaModel, $locale); + $this->setDefaultAddressId($theliaModel->getDefaultAddress()->getId()); + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return Customer + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return CivilityTitle + */ + public function getCivilityTitle() + { + return $this->civilityTitle; + } + + /** + * @param CivilityTitle $civilityTitle + * + * @return Customer + */ + public function setCivilityTitle($civilityTitle) + { + $this->civilityTitle = $civilityTitle; + + return $this; + } + + /** + * @return Lang + */ + public function getLang() + { + return $this->lang; + } + + /** + * @param Lang $lang + * + * @return Customer + */ + public function setLang($lang) + { + $this->lang = $lang; + + return $this; + } + + /** + * @return string + */ + public function getReference() + { + return $this->reference; + } + + /** + * @param string $reference + * + * @return Customer + */ + public function setReference($reference) + { + $this->reference = $reference; + + return $this; + } + + /** + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * @param string $firstName + * + * @return Customer + */ + public function setFirstname($firstName) + { + $this->firstName = $firstName; + + return $this; + } + + /** + * @return string + */ + public function getLastName() + { + return $this->lastName; + } + + /** + * @param string $lastName + * + * @return Customer + */ + public function setLastname($lastName) + { + $this->lastName = $lastName; + + return $this; + } + + /** + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * @param string $email + * + * @return Customer + */ + public function setEmail($email) + { + $this->email = $email; + + return $this; + } + + /** + * @return bool + */ + public function isRememberMe() + { + return $this->rememberMe; + } + + /** + * @param bool $rememberMe + * + * @return Customer + */ + public function setRememberMe($rememberMe) + { + $this->rememberMe = $rememberMe; + + return $this; + } + + /** + * @return float + */ + public function getDiscount() + { + return $this->discount; + } + + /** + * @param float $discount + * + * @return Customer + */ + public function setDiscount($discount) + { + $this->discount = $discount; + + return $this; + } + + /** + * @return bool + */ + public function isReseller() + { + return $this->reseller; + } + + /** + * @param bool $reseller + * + * @return Customer + */ + public function setReseller($reseller) + { + $this->reseller = $reseller; + + return $this; + } + + /** + * @return int + */ + public function getTitleId() + { + return $this->getCivilityTitle()->getId(); + } + + /** + * @return int + */ + public function getLangId() + { + return $this->getLang()->getId(); + } + + public function setTitle(CivilityTitle $civilityTitle) + { + $this->civilityTitle = $civilityTitle; + + return $this; + } + + public function setRef($ref) + { + $this->reference = $ref; + + return $this; + } + + /** + * @return int + */ + public function getDefaultAddressId() + { + return $this->defaultAddressId; + } + + /** + * @param int $id + * + * @return Customer + */ + public function setDefaultAddressId($id) + { + $this->defaultAddressId = $id; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/DeliveryModule.php b/domokits/local/modules/OpenApi/Model/Api/DeliveryModule.php new file mode 100644 index 0000000..81a7e2d --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/DeliveryModule.php @@ -0,0 +1,214 @@ + At customer adress; pickup -> At carrier pickup point; localPickup -> At store pickup point", + * enum={"delivery", "pickup", "localPickup"} + * ) + */ + protected $deliveryMode; + + /** + * @var int + * @OA\Property( + * type="integer" + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $id; + + /** + * @var bool + * @OA\Property( + * type="boolean" + * ) + */ + protected $valid; + + /** + * @var string + * @OA\Property( + * type="string" + * ) + */ + protected $code; + + /** + * @var array + * @OA\Property( + * type="array", + * @OA\Items( + * ref="#/components/schemas/DeliveryModuleOption" + * ) + * ) + */ + protected $options; + + /** + * @var array + * @OA\Property( + * type="array", + * @OA\Items( + * ref="#/components/schemas/File" + * ) + * ) + */ + protected $images = []; + + /** + * @return string + */ + public function getDeliveryMode() + { + return $this->deliveryMode; + } + + /** + * @param string $deliveryMode + * + * @return DeliveryModule + * + * @throws \Exception + */ + public function setDeliveryMode($deliveryMode) + { + if (!\in_array($deliveryMode, ['delivery', 'pickup', 'localPickup'])) { + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + [ + 'title' => Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME), + 'description' => Translator::getInstance()->trans("Delivery mode can only be 'delivery', 'pickup' or 'localPickup'", [], OpenApi::DOMAIN_NAME), + ] + ); + + throw new OpenApiException($error); + } + + $this->deliveryMode = $deliveryMode; + + return $this; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return DeliveryModule + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isValid() + { + return $this->valid; + } + + /** + * @param bool $valid + * + * @return DeliveryModule + */ + public function setValid($valid) + { + $this->valid = $valid; + + return $this; + } + + /** + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * @param string $code + * + * @return DeliveryModule + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * @param array $options + * + * @return DeliveryModule + */ + public function setOptions($options) + { + $this->options = $options; + + return $this; + } + + /** + * @return array + */ + public function getImages() + { + return $this->images; + } + + /** + * @param array $images + * + * @return DeliveryModule + */ + public function setImages($images) + { + $this->images = $images; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/DeliveryModuleOption.php b/domokits/local/modules/OpenApi/Model/Api/DeliveryModuleOption.php new file mode 100644 index 0000000..9ca2ee3 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/DeliveryModuleOption.php @@ -0,0 +1,275 @@ +code; + } + + /** + * @param string $code + * + * @return DeliveryModuleOption + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * @return bool + */ + public function isValid() + { + return $this->valid; + } + + /** + * @param bool $valid + * + * @return DeliveryModuleOption + */ + public function setValid($valid) + { + $this->valid = $valid; + + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + * + * @return DeliveryModuleOption + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getImage() + { + return $this->image; + } + + /** + * @param string $image + * + * @return DeliveryModuleOption + */ + public function setImage($image) + { + $this->image = $image; + + return $this; + } + + /** + * @return string + */ + public function getMinimumDeliveryDate() + { + return $this->minimumDeliveryDate; + } + + /** + * @param string $minimumDeliveryDate + * + * @return DeliveryModuleOption + */ + public function setMinimumDeliveryDate($minimumDeliveryDate) + { + $this->minimumDeliveryDate = $minimumDeliveryDate; + + return $this; + } + + /** + * @return string + */ + public function getMaximumDeliveryDate() + { + return $this->maximumDeliveryDate; + } + + /** + * @param string $maximumDeliveryDate + * + * @return DeliveryModuleOption + */ + public function setMaximumDeliveryDate($maximumDeliveryDate) + { + $this->maximumDeliveryDate = $maximumDeliveryDate; + + return $this; + } + + /** + * @return float + */ + public function getPostage() + { + return $this->postage; + } + + /** + * @param float $postage + * + * @return DeliveryModuleOption + */ + public function setPostage($postage) + { + $this->postage = $postage; + + return $this; + } + + /** + * @return float + */ + public function getPostageTax() + { + return $this->postageTax; + } + + /** + * @param float $postageTax + * + * @return DeliveryModuleOption + */ + public function setPostageTax($postageTax) + { + $this->postageTax = $postageTax; + + return $this; + } + + /** + * @return float + */ + public function getPostageUntaxed() + { + return $this->postageUntaxed; + } + + /** + * @param float $postageUntaxed + * + * @return DeliveryModuleOption + */ + public function setPostageUntaxed($postageUntaxed) + { + $this->postageUntaxed = $postageUntaxed; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Document.php b/domokits/local/modules/OpenApi/Model/Api/Document.php new file mode 100644 index 0000000..01f51c7 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Document.php @@ -0,0 +1,37 @@ +documentService = $documentService; + } + + /** + * @param $theliaModel + * @param null $locale + * @param null $type + * + * @return $this + */ + public function createFromTheliaModel($theliaModel, $locale = null, $type = null) + { + parent::createFromTheliaModel($theliaModel, $locale); + $this->url = $this->documentService->getDocumentUrl($theliaModel, $type); + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Error.php b/domokits/local/modules/OpenApi/Model/Api/Error.php new file mode 100644 index 0000000..13aec31 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Error.php @@ -0,0 +1,115 @@ +title; + } + + /** + * @param string $title + * + * @return Error + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $description + * + * @return Error + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * @return array + */ + public function getSchemaViolations() + { + return $this->schemaViolations; + } + + /** + * @param array $schemaViolations + * + * @return Error + */ + public function setSchemaViolations($schemaViolations) + { + $this->schemaViolations = $schemaViolations; + + return $this; + } + + /** + * @param $schemaViolation SchemaViolation + * + * @return $this + */ + public function appendViolation($schemaViolation) + { + $this->schemaViolations[] = $schemaViolation; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Feature.php b/domokits/local/modules/OpenApi/Model/Api/Feature.php new file mode 100644 index 0000000..52fd2d8 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Feature.php @@ -0,0 +1,91 @@ +id; + } + + /** + * @param int $id + * + * @return Feature + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return array + */ + public function getValues() + { + return $this->values; + } + + /** + * @param array $values + * + * @return Feature + */ + public function setValues($values) + { + $this->values = $values; + + return $this; + } + + /** + * "setValues" alias to fit Thelia model. + * + * @param array $values + * + * @return Feature + */ + public function setFeatureAvs($values) + { + return $this->setValues($values); + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/FeatureValue.php b/domokits/local/modules/OpenApi/Model/Api/FeatureValue.php new file mode 100644 index 0000000..28f6cf7 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/FeatureValue.php @@ -0,0 +1,48 @@ +id; + } + + /** + * @param int $id + * + * @return FeatureValue + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/File.php b/domokits/local/modules/OpenApi/Model/Api/File.php new file mode 100644 index 0000000..0467ec9 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/File.php @@ -0,0 +1,131 @@ +id; + } + + /** + * @param int $id + * + * @return File + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string $url + * + * @return File + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * @param int $position + * + * @return File + */ + public function setPosition($position) + { + $this->position = $position; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return File + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Folder.php b/domokits/local/modules/OpenApi/Model/Api/Folder.php new file mode 100644 index 0000000..3ec32a7 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Folder.php @@ -0,0 +1,76 @@ +id; + } + + /** + * @param int $id + * + * @return Folder + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return Folder + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/I18n.php b/domokits/local/modules/OpenApi/Model/Api/I18n.php new file mode 100644 index 0000000..e9ec962 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/I18n.php @@ -0,0 +1,211 @@ +title; + } + + /** + * @param string $title + * + * @return I18n + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $description + * + * @return I18n + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * @return string + */ + public function getChapo() + { + return $this->chapo; + } + + /** + * @param string $chapo + * + * @return I18n + */ + public function setChapo($chapo) + { + $this->chapo = $chapo; + + return $this; + } + + /** + * @return string + */ + public function getPostscriptum() + { + return $this->postscriptum; + } + + /** + * @param string $postscriptum + * + * @return I18n + */ + public function setPostscriptum($postscriptum) + { + $this->postscriptum = $postscriptum; + + return $this; + } + + /** + * @return string + */ + public function getMetaTitle() + { + return $this->metaTitle; + } + + /** + * @param string $metaTitle + * + * @return I18n + */ + public function setMetaTitle($metaTitle) + { + $this->metaTitle = $metaTitle; + + return $this; + } + + /** + * @return string + */ + public function getMetaDescription() + { + return $this->metaDescription; + } + + /** + * @param string $metaDescription + * + * @return I18n + */ + public function setMetaDescription($metaDescription) + { + $this->metaDescription = $metaDescription; + + return $this; + } + + /** + * @return string + */ + public function getMetaKeywords() + { + return $this->metaKeywords; + } + + /** + * @param string $metaKeywords + * + * @return I18n + */ + public function setMetaKeywords($metaKeywords) + { + $this->metaKeywords = $metaKeywords; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Image.php b/domokits/local/modules/OpenApi/Model/Api/Image.php new file mode 100644 index 0000000..39c69c7 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Image.php @@ -0,0 +1,35 @@ +imageService = $imageService; + } + + /** + * @param $theliaModel + * @param null $locale + * @param null $type + * + * @return $this + */ + public function createFromTheliaModel($theliaModel, $locale = null, $type = null) + { + parent::createFromTheliaModel($theliaModel, $locale); + $this->url = $this->imageService->getImageUrl($theliaModel, $type); + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Lang.php b/domokits/local/modules/OpenApi/Model/Api/Lang.php new file mode 100644 index 0000000..5f3f014 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Lang.php @@ -0,0 +1,411 @@ +id; + } + + /** + * @param int $id + * + * @return Lang + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + * + * @return Lang + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * @param string $code + * + * @return Lang + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * @return string + */ + public function getLocale() + { + return $this->locale; + } + + /** + * @param string $locale + * + * @return Lang + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string $url + * + * @return Lang + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * @return string + */ + public function getDateFormat() + { + return $this->dateFormat; + } + + /** + * @param string $dateFormat + * + * @return Lang + */ + public function setDateFormat($dateFormat) + { + $this->dateFormat = $dateFormat; + + return $this; + } + + /** + * @return string + */ + public function getTimeFormat() + { + return $this->timeFormat; + } + + /** + * @param string $timeFormat + * + * @return Lang + */ + public function setTimeFormat($timeFormat) + { + $this->timeFormat = $timeFormat; + + return $this; + } + + /** + * @return string + */ + public function getDatetimeFormat() + { + return $this->datetimeFormat; + } + + /** + * @param string $datetimeFormat + * + * @return Lang + */ + public function setDatetimeFormat($datetimeFormat) + { + $this->datetimeFormat = $datetimeFormat; + + return $this; + } + + /** + * @return string + */ + public function getDecimalSeparator() + { + return $this->decimalSeparator; + } + + /** + * @param string $decimalSeparator + * + * @return Lang + */ + public function setDecimalSeparator($decimalSeparator) + { + $this->decimalSeparator = $decimalSeparator; + + return $this; + } + + /** + * @return string + */ + public function getThousandsSeparator() + { + return $this->thousandsSeparator; + } + + /** + * @param string $thousandsSeparator + * + * @return Lang + */ + public function setThousandsSeparator($thousandsSeparator) + { + $this->thousandsSeparator = $thousandsSeparator; + + return $this; + } + + /** + * @return bool + */ + public function isActive() + { + return $this->active; + } + + /** + * @param bool $active + * + * @return Lang + */ + public function setActive($active) + { + $this->active = $active; + + return $this; + } + + /** + * @return bool + */ + public function isVisible() + { + return $this->visible; + } + + /** + * @param bool $visible + * + * @return Lang + */ + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } + + /** + * @return string + */ + public function getDecimals() + { + return $this->decimals; + } + + /** + * @param string $decimals + * + * @return Lang + */ + public function setDecimals($decimals) + { + $this->decimals = $decimals; + + return $this; + } + + /** + * @return bool + */ + public function isByDefault() + { + return $this->byDefault; + } + + /** + * @param bool $byDefault + * + * @return Lang + */ + public function setByDefault($byDefault) + { + $this->byDefault = $byDefault; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/ModelFactory.php b/domokits/local/modules/OpenApi/Model/Api/ModelFactory.php new file mode 100644 index 0000000..ed3036c --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/ModelFactory.php @@ -0,0 +1,61 @@ +container = $container; + } + + public function buildModel($modelName, $data = null, $locale = null) + { + try { + $openApiModels = $this->container->getParameter(OpenApi::OPEN_API_MODELS_PARAMETER_KEY); + + // If no correspondent OpenApi model was found + if (!\is_array($openApiModels) || !\array_key_exists($modelName, $openApiModels)) { + $modelName = rtrim($modelName, 's'); + // Try to remove trailing "s" for plural + if (!\array_key_exists($modelName, $openApiModels)) { + return null; + } + } + + $modelServiceId = $openApiModels[$modelName]; + + /** @var BaseApiModel $model */ + $model = $this->container->get($modelServiceId); + + if (null !== $data) { + $model->createOrUpdateFromData($data, $locale); + } + + return $model; + } catch (\Exception $exception) { + Tlog::getInstance()->addError("Error for building api model \"$modelName\" : ".$exception->getMessage()); + + return null; + } + } + + public function modelExists($modelName) + { + $openApiModels = $this->container->getParameter(OpenApi::OPEN_API_MODELS_PARAMETER_KEY); + + if (!\is_array($openApiModels) || !\array_key_exists($modelName, $openApiModels)) { + return false; + } + + return true; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/ModelTrait/translatable.php b/domokits/local/modules/OpenApi/Model/Api/ModelTrait/translatable.php new file mode 100644 index 0000000..9629a47 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/ModelTrait/translatable.php @@ -0,0 +1,120 @@ +i18n = $modelFactory->buildModel('I18n'); + } + + public function getI18n() + { + return $this->i18n; + } + + /** + * @param string $title + * + * @return translatable + */ + public function setTitle($title) + { + $this->i18n->setTitle($title); + + return $this; + } + + /** + * @param string $description + * + * @return translatable + */ + public function setDescription($description) + { + $this->i18n->setDescription($description); + + return $this; + } + + /** + * @param string $chapo + * + * @return translatable + */ + public function setChapo($chapo) + { + $this->i18n->setChapo($chapo); + + return $this; + } + + /** + * @param string $postscriptum + * + * @return translatable + */ + public function setPostscriptum($postscriptum) + { + $this->i18n->setPostscriptum($postscriptum); + + return $this; + } + + /** + * @param string $metaTitle + * + * @return translatable + */ + public function setMetaTitle($metaTitle) + { + $this->i18n->setMetaTitle($metaTitle); + + return $this; + } + + /** + * @param string $metaDescription + * + * @return translatable + */ + public function setMetaDescription($metaDescription) + { + $this->i18n->setMetaDescription($metaDescription); + + return $this; + } + + /** + * @param string $metaKeywords + * + * @return translatable + */ + public function setMetaKeywords($metaKeywords) + { + $this->i18n->setMetaKeywords($metaKeywords); + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/PaymentModule.php b/domokits/local/modules/OpenApi/Model/Api/PaymentModule.php new file mode 100644 index 0000000..25a8759 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/PaymentModule.php @@ -0,0 +1,192 @@ +id; + } + + /** + * @param int $id + * + * @return PaymentModule + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isValid() + { + return $this->valid; + } + + /** + * @param bool $valid + * + * @return PaymentModule + */ + public function setValid($valid) + { + $this->valid = $valid; + + return $this; + } + + /** + * @return int + */ + public function getCode() + { + return $this->code; + } + + /** + * @param int $code + * + * @return PaymentModule + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + /** + * @return float + */ + public function getMinimumAmount() + { + return $this->minimumAmount; + } + + /** + * @param float $minimumAmount + * + * @return PaymentModule + */ + public function setMinimumAmount($minimumAmount) + { + $this->minimumAmount = $minimumAmount; + + return $this; + } + + /** + * @return float + */ + public function getMaximumAmount() + { + return $this->maximumAmount; + } + + /** + * @param float $maximumAmount + * + * @return PaymentModule + */ + public function setMaximumAmount($maximumAmount) + { + $this->maximumAmount = $maximumAmount; + + return $this; + } + + /** + * @return array + */ + public function getImages() + { + return $this->images; + } + + /** + * @param array $images + * + * @return PaymentModule + */ + public function setImages($images) + { + $this->images = $images; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/PickupLocation.php b/domokits/local/modules/OpenApi/Model/Api/PickupLocation.php new file mode 100644 index 0000000..3fdfec9 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/PickupLocation.php @@ -0,0 +1,158 @@ +id; + } + + /** + * @param int $id + * + * @return PickupLocation + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return float + */ + public function getLatitude() + { + return $this->latitude; + } + + /** + * @param float $latitude + * + * @return PickupLocation + */ + public function setLatitude($latitude) + { + $this->latitude = $latitude; + + return $this; + } + + /** + * @return float + */ + public function getLongitude() + { + return $this->longitude; + } + + /** + * @param float $longitude + * + * @return PickupLocation + */ + public function setLongitude($longitude) + { + $this->longitude = $longitude; + + return $this; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + * + * @return PickupLocation + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * @return Address + */ + public function getAddress() + { + return $this->address; + } + + /** + * @param Address $address + * + * @return PickupLocation + */ + public function setAddress($address) + { + $this->address = $address; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Price.php b/domokits/local/modules/OpenApi/Model/Api/Price.php new file mode 100644 index 0000000..768ba50 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Price.php @@ -0,0 +1,96 @@ +filterByProductSaleElements($pse)->findOne(); + $pse->setVirtualColumn('price_PRICE', (float) $price->getPrice()); + $pse->setVirtualColumn('price_PROMO_PRICE', (float) $price->getPromoPrice()); + $this->untaxed = $isPromo ? $pse->getPromoPrice() : $pse->getPrice(); + $this->taxed = $isPromo ? $pse->getTaxedPromoPrice($country) : $pse->getTaxedPrice($country); + + return $this; + } + + /** + * @return float + */ + public function getUntaxed() + { + return $this->untaxed; + } + + /** + * @param float $untaxed + * + * @return Price + */ + public function setUntaxed($untaxed) + { + $this->untaxed = $untaxed; + + return $this; + } + + /** + * @return float + */ + public function getTaxed() + { + return $this->taxed; + } + + /** + * @param float $taxed + * + * @return Price + */ + public function setTaxed($taxed) + { + $this->taxed = $taxed; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Product.php b/domokits/local/modules/OpenApi/Model/Api/Product.php new file mode 100644 index 0000000..a16acd3 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Product.php @@ -0,0 +1,428 @@ +modelFactory; + $this->features = array_filter( + array_map( + function (FeatureProduct $featureProduct) use ($modelFactory) { + $propelFeature = $featureProduct->getFeature(); + if (null === $propelFeature){ + return false; + } + + if (null !== $featureProduct->getFeatureAv()) { + // Temporary set only product feature av to build good feature av list + $propelFeature->addFeatureAv($featureProduct->getFeatureAv()); + } + $propelFeature->resetPartialFeatureAvs(false); + + $feature = $modelFactory->buildModel('Feature', $propelFeature); + + $propelFeature->clearFeatureAvs(); + + return $feature; + }, + iterator_to_array($theliaModel->getFeatureProducts())), + function($value){ + return $value; + } + ); + + $this->categories = array_map( + function (ProductCategory $productCategory) use ($modelFactory) { + $propelCategory = $productCategory->getCategory(); + + $category = $modelFactory->buildModel('Category', $propelCategory); + + if ($productCategory->isDefaultCategory()) { + $this->defaultCategory = $category; + } + + return $category; + }, + iterator_to_array($theliaModel->getProductCategories()) + ); + + usort($this->images, function ($item1, $item2) { + return $item1->getPosition() <=> $item2->getPosition(); + }); + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return Product + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return string + */ + public function getReference() + { + return $this->reference; + } + + /** + * @param string $reference + * + * @return Product + */ + public function setReference($reference) + { + $this->reference = $reference; + + return $this; + } + + /** + * Method alias to match thelia getter name. + * + * @param string $reference + * + * @return Product + */ + public function setRef($reference) + { + $this->setReference($reference); + + return $this; + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string $url + * + * @return Product + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * @return array + */ + public function getImages() + { + return $this->images; + } + + /** + * @param array $images + * + * @return Product + */ + public function setImages($images) + { + $this->images = $images; + + return $this; + } + + /** + * @return array + */ + public function getProductSaleElements() + { + return $this->productSaleElements; + } + + /** + * @param array $productSaleElements + * + * @return Product + */ + public function setProductSaleElements($productSaleElements) + { + $this->productSaleElements = $productSaleElements; + + return $this; + } + + public function isVirtual(): bool + { + return $this->virtual; + } + + public function setVirtual(bool $virtual): self + { + $this->virtual = $virtual; + + return $this; + } + + public function isVisible(): bool + { + return $this->visible; + } + + public function setVisible(bool $visible): self + { + $this->visible = $visible; + + return $this; + } + + /** + * @return Brand + */ + public function getBrand(): ?Brand + { + return $this->brand; + } + + /** + * @param Brand $brand + */ + public function setBrand(Brand $brand = null): self + { + $this->brand = $brand; + + return $this; + } + + public function getDefaultCategory(): Category + { + return $this->defaultCategory; + } + + public function setDefaultCategory(Category $defaultCategory): self + { + $this->defaultCategory = $defaultCategory; + + return $this; + } + + public function getCategories(): array + { + return $this->categories; + } + + public function setCategories(array $categories): self + { + $this->categories = $categories; + + return $this; + } + + /** + * Method alias to match thelia getter name. + */ + public function setProductCategories(array $categories = []): self + { + return $this->setCategories($categories); + } + + public function getContents(): array + { + return $this->contents; + } + + public function setContents(array $contents = []): self + { + $this->contents = $contents; + + return $this; + } + + public function getDocuments(): array + { + return $this->documents; + } + + public function setDocuments(array $documents = []): self + { + $this->documents = $documents; + + return $this; + } + + /** + * Method alias to match thelia getter name. + */ + public function setProductDocuments(array $documents = []): self + { + return $this->setDocuments($documents); + } + + public function getFeatures(): array + { + return $this->features; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/ProductSaleElement.php b/domokits/local/modules/OpenApi/Model/Api/ProductSaleElement.php new file mode 100644 index 0000000..a6e1b6a --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/ProductSaleElement.php @@ -0,0 +1,502 @@ +filterByProductSaleElements($theliaModel)->findOne(); + $theliaModel->setVirtualColumn('price_PRICE', (float) $price->getPrice()); + $theliaModel->setVirtualColumn('price_PROMO_PRICE', (float) $price->getPromoPrice()); + + parent::createFromTheliaModel($theliaModel, $locale); + + $modelFactory = $this->modelFactory; + $this->attributes = array_map( + function (AttributeCombination $attributeCombination) use ($modelFactory) { + $propelAttribute = $attributeCombination->getAttribute(); + + // Temporary set only pse attribute av to build good attribute av list + $propelAttribute->addAttributeAv($attributeCombination->getAttributeAv()); + + $attribute = $modelFactory->buildModel('Attribute', $propelAttribute); + + // Reset attribute av to all for next use of attribute (because of propel "cache") + $propelAttribute->clearAttributeAvs(); + + return $attribute; + }, + iterator_to_array($theliaModel->getAttributeCombinations()) + ); + + $this->isPromo = (bool) $theliaModel->getPromo(); + $this->price = $this->modelFactory->buildModel('Price', ['untaxed' => $theliaModel->getPrice(), 'taxed' => $theliaModel->getTaxedPrice($this->country)]); + $this->promoPrice = $this->modelFactory->buildModel('Price', ['untaxed' => $theliaModel->getPromoPrice(), 'taxed' => $theliaModel->getTaxedPromoPrice($this->country)]); + } + + /** + * Create an OpenApi ProductSaleElement from a Thelia ProductSaleElements and a Country, then returns it. + * + * @return $this + * + * @throws \Propel\Runtime\Exception\PropelException + */ + public function fillFromTheliaPseAndCountry(ProductSaleElements $pse, Country $country) + { + $modelFactory = $this->modelFactory; + $attributes = array_map( + function (AttributeCombination $attributeCombination) use ($modelFactory) { + $attribute = $attributeCombination->getAttribute(); + $attribute->setAttributeAvs((new Collection())); + $attribute->addAttributeAv($attributeCombination->getAttributeAv()); + + return $modelFactory->buildModel('Attribute', $attribute); + }, + iterator_to_array($pse->getAttributeCombinations()) + ); + + $this->id = $pse->getId(); + $this->isPromo = (bool) $pse->getPromo(); + + /** @var Price $price */ + $price = $this->modelFactory->buildModel('Price'); + $price->fillFromTheliaPseAndCountry($pse, $country); + $this->price = $price; + + /** @var Price $promoPrice */ + $promoPrice = $this->modelFactory->buildModel('Price'); + $promoPrice->fillFromTheliaPseAndCountry($pse, $country); + $this->promoPrice = $price; + $this->weight = $pse->getWeight(); + + $this->reference = $pse->getRef(); + $this->attributes = $attributes; + + $this->quantity = $pse->getQuantity(); + + return $this; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param int $id + * + * @return ProductSaleElement + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return bool + */ + public function isPromo() + { + return $this->isPromo; + } + + /** + * @param bool $isPromo + * + * @return ProductSaleElement + */ + public function setIsPromo($isPromo) + { + $this->isPromo = $isPromo; + + return $this; + } + + /** + * @return string + */ + public function getReference() + { + return $this->reference; + } + + /** + * @param string $reference + * + * @return ProductSaleElement + */ + public function setReference($reference) + { + $this->reference = $reference; + + return $this; + } + + /** + * @param $reference + * + * @return $this + */ + public function setRef($reference) + { + return $this->setReference($reference); + } + + /** + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * @param array $attributes + * + * @return ProductSaleElement + */ + public function setAttributes($attributes) + { + $this->attributes = $attributes; + + return $this; + } + + /** + * @return float + */ + public function getQuantity() + { + return $this->quantity; + } + + /** + * @param float $quantity + * + * @return ProductSaleElement + */ + public function setQuantity($quantity) + { + $this->quantity = $quantity; + + return $this; + } + + /** + * @return bool + */ + public function isNewness() + { + return $this->newness; + } + + /** + * @param bool $newness + * + * @return ProductSaleElement + */ + public function setNewness($newness) + { + $this->newness = $newness; + + return $this; + } + + /** + * @return float + */ + public function getWeight() + { + return $this->weight; + } + + /** + * @param float $weight + * + * @return ProductSaleElement + */ + public function setWeight($weight) + { + $this->weight = $weight; + + return $this; + } + + /** + * @return bool + */ + public function isDefault() + { + return $this->isDefault; + } + + /** + * @param bool $isDefault + * + * @return ProductSaleElement + */ + public function setIsDefault($isDefault) + { + $this->isDefault = $isDefault; + + return $this; + } + + /** + * @return string + */ + public function getEan() + { + return $this->ean; + } + + /** + * @param string $ean + * + * @return ProductSaleElement + */ + public function setEan($ean) + { + $this->ean = $ean; + + return $this; + } + + /** + * @param string $ean + * + * @return ProductSaleElement + */ + public function setEanCode($ean) + { + return $this->setEan($ean); + } + + /** + * @return array + */ + public function getImages() + { + return $this->images; + } + + /** + * @param array $images + * + * @return ProductSaleElement + */ + public function setImages($images) + { + $this->images = $images; + + return $this; + } + + /** + * @return array + */ + public function getDocuments() + { + return $this->documents; + } + + /** + * @param array $documents + * + * @return ProductSaleElement + */ + public function setDocuments($documents) + { + $this->documents = $documents; + + return $this; + } + + /** + * @return Price + */ + public function getPrice() + { + return $this->price; + } + + /** + * @param Price $price + * + * @return ProductSaleElement + */ + public function setPrice($price) + { + $this->price = $price; + + return $this; + } + + /** + * @return Price + */ + public function getPromoPrice() + { + return $this->promoPrice; + } + + /** + * @param Price $promoPrice + * + * @return ProductSaleElement + */ + public function setPromoPrice($promoPrice) + { + $this->promoPrice = $promoPrice; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Result.php b/domokits/local/modules/OpenApi/Model/Api/Result.php new file mode 100644 index 0000000..03c7723 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Result.php @@ -0,0 +1,100 @@ +weight; + } + + /** + * @param float $weight + * + * @return Result + */ + public function setWeight($weight) + { + $this->weight = $weight; + + return $this; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + * + * @return Result + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } + + /** + * @return BaseApiModel + */ + public function getObject() + { + return $this->object; + } + + /** + * @param BaseApiModel $object + * + * @return Result + */ + public function setObject($object) + { + $this->object = $object; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/SchemaViolation.php b/domokits/local/modules/OpenApi/Model/Api/SchemaViolation.php new file mode 100644 index 0000000..0a3bde9 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/SchemaViolation.php @@ -0,0 +1,43 @@ +message; + } + + /** + * @param string $message + * + * @return SchemaViolation + */ + public function setMessage($message) + { + $this->message = $message; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Model/Api/Search.php b/domokits/local/modules/OpenApi/Model/Api/Search.php new file mode 100644 index 0000000..1d5b401 --- /dev/null +++ b/domokits/local/modules/OpenApi/Model/Api/Search.php @@ -0,0 +1,133 @@ +results; + } + + /** + * @param Result $results + * + * @return Search + */ + public function setResults($results) + { + $this->results = $results; + + return $this; + } + + /** + * @return int + */ + public function getPage() + { + return $this->page; + } + + /** + * @param int $page + * + * @return Search + */ + public function setPage($page) + { + $this->page = $page; + + return $this; + } + + /** + * @return int + */ + public function getPageTotal() + { + return $this->pageTotal; + } + + /** + * @param int $pageTotal + * + * @return Search + */ + public function setPageTotal($pageTotal) + { + $this->pageTotal = $pageTotal; + + return $this; + } + + /** + * @return int + */ + public function getTotal() + { + return $this->total; + } + + /** + * @param int $total + * + * @return Search + */ + public function setTotal($total) + { + $this->total = $total; + + return $this; + } +} diff --git a/domokits/local/modules/OpenApi/Normalizer/ModelApiNormalizer.php b/domokits/local/modules/OpenApi/Normalizer/ModelApiNormalizer.php new file mode 100644 index 0000000..b821e4f --- /dev/null +++ b/domokits/local/modules/OpenApi/Normalizer/ModelApiNormalizer.php @@ -0,0 +1,25 @@ +extendedDataValue())) { + foreach ($object->extendedDataValue() as $key => $value) { + if (isset($data[$key])) { + continue; + } + + $data[$key] = $value; + } + } + + return $data; + } +} diff --git a/domokits/local/modules/OpenApi/OpenApi.php b/domokits/local/modules/OpenApi/OpenApi.php new file mode 100644 index 0000000..47d6ae3 --- /dev/null +++ b/domokits/local/modules/OpenApi/OpenApi.php @@ -0,0 +1,69 @@ +load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } + + public static function loadConfiguration(ContainerBuilder $containerBuilder): void + { + $containerBuilder->registerForAutoconfiguration(BaseApiModel::class) + ->setPublic(true) + ->setShared(false) + ->setParent("open_api.base.model") + ->addTag('open_api.model'); + } + + public static function getAnnotationRoutePrefix(): string + { + return 'open_api'; + } +} diff --git a/domokits/local/modules/OpenApi/Readme.md b/domokits/local/modules/OpenApi/Readme.md new file mode 100644 index 0000000..7dd89d0 --- /dev/null +++ b/domokits/local/modules/OpenApi/Readme.md @@ -0,0 +1,3 @@ +# WIP + +This module is under development, please do not try to use it. \ No newline at end of file diff --git a/domokits/local/modules/OpenApi/Service/DocumentService.php b/domokits/local/modules/OpenApi/Service/DocumentService.php new file mode 100644 index 0000000..3d0265e --- /dev/null +++ b/domokits/local/modules/OpenApi/Service/DocumentService.php @@ -0,0 +1,62 @@ +dispatcher = $dispatcher; + } + + /** + * Returns an document URL. + * + * @param $documentModel + * @param $documentType + * + * @return string + */ + public function getDocumentUrl($documentModel, $documentType = null) + { + if (null === $documentType) { + $documentType = str_replace(['document', 'thelia\\model\\'], '', strtolower(\get_class($documentModel))); + } + + $baseSourceFilePath = ConfigQuery::read('documents_library_path'); + if ($baseSourceFilePath === null) { + $baseSourceFilePath = THELIA_LOCAL_DIR.'media'.DS.'documents'; + } else { + $baseSourceFilePath = THELIA_ROOT.$baseSourceFilePath; + } + + $event = new DocumentEvent(); + // Put source document file path + $sourceFilePath = sprintf( + '%s/%s/%s', + $baseSourceFilePath, + $documentType, + $documentModel->getFile() + ); + + $event->setSourceFilepath($sourceFilePath); + $event->setCacheSubdirectory($documentType); + + $this->dispatcher->dispatch($event, TheliaEvents::DOCUMENT_PROCESS); + + return $event->getDocumentUrl(); + } +} diff --git a/domokits/local/modules/OpenApi/Service/ImageService.php b/domokits/local/modules/OpenApi/Service/ImageService.php new file mode 100644 index 0000000..c034d43 --- /dev/null +++ b/domokits/local/modules/OpenApi/Service/ImageService.php @@ -0,0 +1,142 @@ +dispatcher = $dispatcher; + } + + /** + * Returns an image URL. + * + * @param $imageModel + * @param $imageType + * + * @return string + */ + public function getImageUrl($imageModel, $imageType = null) + { + return $this->transformImage($imageModel, $imageType); + } + + /** + * Transform an image according to the parameters, and returns the + * transformed image URL. + * + * imageFile can be of type Thelia\Model\ProductImage, ContentImage etc + * + * @param ProductImage|ContentImage|BrandImage|CategoryImage|FolderImage|ModuleImage $imageModel + * @param $imageType + * @param bool $allowZoom + * @param string $resize + * @param null $width + * @param null $height + * @param null $rotation + * @param null $backgroundColor + * @param null $quality + * @param null $effects + * + * @return string The transformed Image URL + */ + public function transformImage( + $imageModel, + $imageType = null, + $allowZoom = false, + $resize = 'none', + $width = null, + $height = null, + $rotation = null, + $backgroundColor = null, + $quality = null, + $effects = null + ) { + switch ($resize) { + case 'crop': + $resizeMode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP; + break; + + case 'borders': + $resizeMode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS; + break; + + case 'none': + default: + $resizeMode = \Thelia\Action\Image::KEEP_IMAGE_RATIO; + } + + $event = $this->createImageEvent($imageModel, $imageType); + $event + ->setAllowZoom($allowZoom) + ->setResizeMode($resizeMode) + ->setWidth($width) + ->setHeight($height) + ->setRotation($rotation) + ->setBackgroundColor($backgroundColor) + ->setQuality($quality) + ; + + /* Needed as setting effects as null will throw an exception during dispatch */ + if ($effects) { + $event->setEffects($effects); + } + + $this->dispatcher->dispatch($event, TheliaEvents::IMAGE_PROCESS); + + return $event->getFileUrl(); + } + + /** + * @param ProductImage|ContentImage|BrandImage|CategoryImage|FolderImage|ModuleImage $imageModel + * @param null $imageType + * + * @return ImageEvent + */ + protected function createImageEvent($imageModel, $imageType = null) + { + $imageEvent = new ImageEvent(); + $baseSourceFilePath = ConfigQuery::read('images_library_path'); + + if (null === $imageType) { + $imageType = str_replace(['image', 'thelia\\model\\'], '', strtolower(\get_class($imageModel))); + } + + if ($baseSourceFilePath === null) { + $baseSourceFilePath = THELIA_LOCAL_DIR.'media'.DS.'images'; + } else { + $baseSourceFilePath = THELIA_ROOT.$baseSourceFilePath; + } + + /** Put source image file path */ + $sourceFilePath = sprintf( + '%s/%s/%s', + $baseSourceFilePath, + $imageType, + $imageModel->getFile() + ); + + $imageEvent->setSourceFilepath($sourceFilePath); + $imageEvent->setCacheSubdirectory($imageType); + + return $imageEvent; + } +} diff --git a/domokits/local/modules/OpenApi/Service/OpenApiService.php b/domokits/local/modules/OpenApi/Service/OpenApiService.php new file mode 100644 index 0000000..d9c28a6 --- /dev/null +++ b/domokits/local/modules/OpenApi/Service/OpenApiService.php @@ -0,0 +1,149 @@ +securityContext = $securityContext; + $this->modelFactory = $modelFactory; + $this->requestStack = $requestStack; + $this->currentRequest = $requestStack->getCurrentRequest(); + $this->dispatcher = $dispatcher; + } + + public static function jsonResponse($data, $code = 200, $cors = '*') + { + $response = (new JsonResponse()) + ->setContent(json_encode($data)); + + $response->headers->set('Access-Control-Allow-Origin', $cors); + $response->setStatusCode($code); + + return $response; + } + + /** + * @param bool $throwExceptionIfNull + * + * @return \Thelia\Model\Customer + * + * @throws OpenApiException + */ + public function getCurrentCustomer($throwExceptionIfNull = true) + { + $currentCustomer = $this->securityContext->getCustomerUser(); + + if (null === $currentCustomer && $throwExceptionIfNull) { + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + [ + 'title' => Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME), + 'description' => Translator::getInstance()->trans('No customer found', [], OpenApi::DOMAIN_NAME), + ] + ); + throw new OpenApiException($error); + } + + return $currentCustomer; + } + + /** + * @param bool $throwExceptionIfNull + * + * @return \Thelia\Model\Cart + * + * @throws OpenApiException + */ + public function getSessionCart($throwExceptionIfNull = true) + { + $cart = $this->currentRequest->getSession()->getSessionCart($this->dispatcher); + + if (null === $cart && $throwExceptionIfNull) { + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + [ + 'title' => Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME), + 'description' => Translator::getInstance()->trans('No cart found', [], OpenApi::DOMAIN_NAME), + ] + ); + throw new OpenApiException($error); + } + + return $cart; + } + + public function getRequestValue($key, $default = null) + { + $requestData = json_decode($this->currentRequest->getContent(), true); + + if (!isset($requestData[$key]) || null === $requestData[$key]) { + return $default; + } + + return $requestData[$key]; + } + + public function buildOpenApiException($title, $description = ''): OpenApiException + { + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + [ + 'title' => $title, + 'description' => $description, + ] + ); + + return new OpenApiException($error); + } + + public function getCurrentOpenApiCart() + { + $cart = $this->currentRequest->getSession()->getSessionCart($this->dispatcher); + + return $this->modelFactory->buildModel('Cart', $cart); + } +} diff --git a/domokits/local/modules/OpenApi/Service/SearchService.php b/domokits/local/modules/OpenApi/Service/SearchService.php new file mode 100644 index 0000000..d040950 --- /dev/null +++ b/domokits/local/modules/OpenApi/Service/SearchService.php @@ -0,0 +1,88 @@ +get('id')) { + $itemQuery->filterById($id); + } + + if (null !== $ids = $request->get('ids')) { + $itemQuery->filterById($ids, Criteria::IN); + } + + if ((null !== $parentsIds = $request->get('parentsIds')) && method_exists($itemQuery, "filterByParent")) { + $itemQuery->filterByParent($parentsIds, Criteria::IN); + } + + $itemQuery->filterByVisible((bool) json_decode(json_encode($request->get('visible', true)))); + + $order = $request->get('order', 'alpha'); + $locale = $request->get('locale', $request->getSession()->getLang()->getLocale()); + $title = $request->get('title'); + $description = $request->get('description'); + $chapo = $request->get('chapo'); + $postscriptum = $request->get('postscriptum'); + + $itemQuery + ->limit($request->get('limit', 20)) + ->offset($request->get('offset', 0)); + + switch ($order) { + case 'created': + $itemQuery->orderByCreatedAt(); + break; + case 'created_reverse': + $itemQuery->orderByCreatedAt(Criteria::DESC); + break; + } + + if (null !== $title || null !== $description || null !== $chapo || null !== $postscriptum) { + $useI18nMethodName = "use".ucfirst($itemType)."I18nQuery"; + $itemI18nQuery = $itemQuery + ->$useI18nMethodName() + ->filterByLocale($locale); + + if (null !== $title) { + $itemI18nQuery->filterByTitle('%'.$title.'%', Criteria::LIKE); + } + + if (null !== $description) { + $itemI18nQuery->filterByDescription('%'.$description.'%', Criteria::LIKE); + } + + if (null !== $chapo) { + $itemI18nQuery->filterByChapo('%'.$chapo.'%', Criteria::LIKE); + } + + if (null !== $postscriptum) { + $itemI18nQuery->filterByPostscriptum('%'.$postscriptum.'%', Criteria::LIKE); + } + + switch ($order) { + case 'alpha': + $itemI18nQuery->orderByTitle(); + break; + case 'alpha_reverse': + $itemI18nQuery->orderByTitle(Criteria::DESC); + break; + } + + $itemI18nQuery->endUse(); + } + + return $itemQuery; + } +} diff --git a/domokits/local/modules/OpenApi/composer.json b/domokits/local/modules/OpenApi/composer.json new file mode 100644 index 0000000..ce36a22 --- /dev/null +++ b/domokits/local/modules/OpenApi/composer.json @@ -0,0 +1,13 @@ +{ + "name": "thelia/open-api-module", + "description": "A modern and documented open api for Thelia", + "license": "LGPL-3.0-or-later", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1", + "zircote/swagger-php": "~3.1.0" + }, + "extra": { + "installer-name": "OpenApi" + } +} diff --git a/domokits/local/modules/OpenApi/templates/backOffice/default/configuration.html b/domokits/local/modules/OpenApi/templates/backOffice/default/configuration.html new file mode 100644 index 0000000..62bfb8b --- /dev/null +++ b/domokits/local/modules/OpenApi/templates/backOffice/default/configuration.html @@ -0,0 +1,42 @@ +
+
{intl l="OpenAPI configurations" d="openapi.bo.default"}
+ {form name="openapi_form_config_form"} +
+ {include + file = "includes/inner-form-toolbar.html" + hide_submit_buttons = false + hide_flags = true + hide_save_and_close_button = true + + page_url = {url path="/admin/module/OpenApi"} + close_url = {url path="/admin/modules"} + } + {if $form_error|default:null}
{$form_error_message}
{/if} +
+ {form_hidden_fields} + {render_form_field field="success_url" value={url path='/admin/module/OpenApi'}} + {render_form_field field="error_url" value={url path='/admin/module/OpenApi'}} + + + + + + + + + {loop type="config" name="config-loop"} + + + + + {/loop} + +
{intl l="Active" d="openapi.bo.default"}{intl l="Name" d="openapi.bo.default"}
+ {form_field field="enable_config" value_key=$ID} + + {/form_field} + {$NAME}
+
+
+ {/form} +
\ No newline at end of file diff --git a/domokits/local/modules/OpenApi/templates/frontOffice/default/swagger-ui.html b/domokits/local/modules/OpenApi/templates/frontOffice/default/swagger-ui.html new file mode 100644 index 0000000..0ec5ae5 --- /dev/null +++ b/domokits/local/modules/OpenApi/templates/frontOffice/default/swagger-ui.html @@ -0,0 +1,22 @@ + + + + + + Swagger UI + + + + + +
+ + + + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/.github/workflows/release.yml b/domokits/local/modules/PayPal/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/PayPal/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/PayPal/Config/Update/3.0.2.sql b/domokits/local/modules/PayPal/Config/Update/3.0.2.sql new file mode 100644 index 0000000..c3df234 --- /dev/null +++ b/domokits/local/modules/PayPal/Config/Update/3.0.2.sql @@ -0,0 +1,234 @@ +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- paypal_customer +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_customer` +( + `id` INTEGER NOT NULL, + `paypal_user_id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `name` VARCHAR(255), + `given_name` VARCHAR(255), + `family_name` VARCHAR(255), + `middle_name` VARCHAR(255), + `picture` VARCHAR(255), + `email_verified` TINYINT, + `gender` VARCHAR(255), + `birthday` VARCHAR(255), + `zoneinfo` VARCHAR(255), + `locale` VARCHAR(255), + `language` VARCHAR(255), + `verified` TINYINT, + `phone_number` VARCHAR(255), + `verified_account` VARCHAR(255), + `account_type` VARCHAR(255), + `age_range` VARCHAR(255), + `payer_id` VARCHAR(255), + `postal_code` VARCHAR(255), + `locality` VARCHAR(255), + `region` VARCHAR(255), + `country` VARCHAR(255), + `street_address` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`,`paypal_user_id`), + CONSTRAINT `fk_paypal_payer_customer_id` + FOREIGN KEY (`id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_planified_payment` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `frequency` VARCHAR(255) NOT NULL, + `frequency_interval` INTEGER NOT NULL, + `cycle` INTEGER NOT NULL, + `min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `position` INTEGER DEFAULT 0 NOT NULL, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_cart +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_cart` +( + `id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `planified_payment_id` INTEGER, + `express_payment_id` VARCHAR(255), + `express_payer_id` VARCHAR(255), + `express_token` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `FI_paypal_cart_planified_payment_id` (`planified_payment_id`), + CONSTRAINT `fk_paypal_cart_cart_id` + FOREIGN KEY (`id`) + REFERENCES `cart` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_cart_planified_payment_id` + FOREIGN KEY (`planified_payment_id`) + REFERENCES `paypal_planified_payment` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_order +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_order` +( + `id` INTEGER NOT NULL, + `payment_id` VARCHAR(50), + `agreement_id` VARCHAR(255), + `credit_card_id` VARCHAR(40), + `state` VARCHAR(20), + `amount` DECIMAL(16,6) DEFAULT 0.000000, + `description` LONGTEXT, + `payer_id` VARCHAR(255), + `token` VARCHAR(255), + `planified_title` VARCHAR(255) NOT NULL, + `planified_description` LONGTEXT, + `planified_frequency` VARCHAR(255) NOT NULL, + `planified_frequency_interval` INTEGER NOT NULL, + `planified_cycle` INTEGER NOT NULL, + `planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL, + `planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `created_at` DATETIME, + `updated_at` DATETIME, + `version` INTEGER DEFAULT 0, + `version_created_at` DATETIME, + `version_created_by` VARCHAR(100), + PRIMARY KEY (`id`), + CONSTRAINT `fk_paypal_order_order_id` + FOREIGN KEY (`id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_plan +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_plan` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `paypal_order_id` INTEGER NOT NULL, + `plan_id` VARCHAR(255), + `state` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `FI_paypal_plan_paypal_order_id` (`paypal_order_id`), + CONSTRAINT `fk_paypal_plan_paypal_order_id` + FOREIGN KEY (`paypal_order_id`) + REFERENCES `paypal_order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_log +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_log` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER, + `order_id` INTEGER, + `hook` VARCHAR(255), + `channel` VARCHAR(255), + `level` INTEGER, + `message` LONGTEXT, + `time` INTEGER, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `FI_paypal_log_customer_id` (`customer_id`), + INDEX `FI_paypal_log_order_id` (`order_id`), + CONSTRAINT `fk_paypal_log_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_log_order_id` + FOREIGN KEY (`order_id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment_i18n +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_planified_payment_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255) NOT NULL, + `description` LONGTEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `paypal_planified_payment_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `paypal_planified_payment` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_order_version +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_order_version` +( + `id` INTEGER NOT NULL, + `payment_id` VARCHAR(50), + `agreement_id` VARCHAR(255), + `credit_card_id` VARCHAR(40), + `state` VARCHAR(20), + `amount` DECIMAL(16,6) DEFAULT 0.000000, + `description` LONGTEXT, + `payer_id` VARCHAR(255), + `token` VARCHAR(255), + `planified_title` VARCHAR(255) NOT NULL, + `planified_description` LONGTEXT, + `planified_frequency` VARCHAR(255) NOT NULL, + `planified_frequency_interval` INTEGER NOT NULL, + `planified_cycle` INTEGER NOT NULL, + `planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL, + `planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `created_at` DATETIME, + `updated_at` DATETIME, + `version` INTEGER DEFAULT 0 NOT NULL, + `version_created_at` DATETIME, + `version_created_by` VARCHAR(100), + `id_version` INTEGER DEFAULT 0, + PRIMARY KEY (`id`,`version`), + CONSTRAINT `paypal_order_version_FK_1` + FOREIGN KEY (`id`) + REFERENCES `paypal_order` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/PayPal/Config/config.xml b/domokits/local/modules/PayPal/Config/config.xml new file mode 100644 index 0000000..0ffddf3 --- /dev/null +++ b/domokits/local/modules/PayPal/Config/config.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/PayPal/Config/create.sql b/domokits/local/modules/PayPal/Config/create.sql new file mode 100644 index 0000000..79aba18 --- /dev/null +++ b/domokits/local/modules/PayPal/Config/create.sql @@ -0,0 +1,195 @@ +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- paypal_customer +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_customer` +( + `id` INTEGER NOT NULL, + `paypal_user_id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `name` VARCHAR(255), + `given_name` VARCHAR(255), + `family_name` VARCHAR(255), + `middle_name` VARCHAR(255), + `picture` VARCHAR(255), + `email_verified` TINYINT, + `gender` VARCHAR(255), + `birthday` VARCHAR(255), + `zoneinfo` VARCHAR(255), + `locale` VARCHAR(255), + `language` VARCHAR(255), + `verified` TINYINT, + `phone_number` VARCHAR(255), + `verified_account` VARCHAR(255), + `account_type` VARCHAR(255), + `age_range` VARCHAR(255), + `payer_id` VARCHAR(255), + `postal_code` VARCHAR(255), + `locality` VARCHAR(255), + `region` VARCHAR(255), + `country` VARCHAR(255), + `street_address` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`,`paypal_user_id`), + CONSTRAINT `fk_paypal_payer_customer_id` + FOREIGN KEY (`id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_planified_payment` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `frequency` VARCHAR(255) NOT NULL, + `frequency_interval` INTEGER NOT NULL, + `cycle` INTEGER NOT NULL, + `min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `position` INTEGER DEFAULT 0 NOT NULL, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_cart +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_cart` +( + `id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `planified_payment_id` INTEGER, + `express_payment_id` VARCHAR(255), + `express_payer_id` VARCHAR(255), + `express_token` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_cart_planified_payment_id` (`planified_payment_id`), + CONSTRAINT `fk_paypal_cart_cart_id` + FOREIGN KEY (`id`) + REFERENCES `cart` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_cart_planified_payment_id` + FOREIGN KEY (`planified_payment_id`) + REFERENCES `paypal_planified_payment` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_order +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_order` +( + `id` INTEGER NOT NULL, + `payment_id` VARCHAR(50), + `agreement_id` VARCHAR(255), + `credit_card_id` VARCHAR(40), + `state` VARCHAR(20), + `amount` DECIMAL(16,6) DEFAULT 0.000000, + `description` LONGTEXT, + `payer_id` VARCHAR(255), + `token` VARCHAR(255), + `planified_title` VARCHAR(255) NOT NULL, + `planified_description` LONGTEXT, + `planified_frequency` VARCHAR(255) NOT NULL, + `planified_frequency_interval` INTEGER NOT NULL, + `planified_cycle` INTEGER NOT NULL, + `planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL, + `planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + CONSTRAINT `fk_paypal_order_order_id` + FOREIGN KEY (`id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_plan +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_plan` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `paypal_order_id` INTEGER NOT NULL, + `plan_id` VARCHAR(255), + `state` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_plan_paypal_order_id` (`paypal_order_id`), + CONSTRAINT `fk_paypal_plan_paypal_order_id` + FOREIGN KEY (`paypal_order_id`) + REFERENCES `paypal_order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_log +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_log` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER, + `order_id` INTEGER, + `hook` VARCHAR(255), + `channel` VARCHAR(255), + `level` INTEGER, + `message` LONGTEXT, + `time` INTEGER, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_log_customer_id` (`customer_id`), + INDEX `fi_paypal_log_order_id` (`order_id`), + CONSTRAINT `fk_paypal_log_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_log_order_id` + FOREIGN KEY (`order_id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment_i18n +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `paypal_planified_payment_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255) NOT NULL, + `description` LONGTEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `paypal_planified_payment_i18n_fk_c9dfe7` + FOREIGN KEY (`id`) + REFERENCES `paypal_planified_payment` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/PayPal/Config/module.xml b/domokits/local/modules/PayPal/Config/module.xml new file mode 100644 index 0000000..78ea5b5 --- /dev/null +++ b/domokits/local/modules/PayPal/Config/module.xml @@ -0,0 +1,28 @@ + + + PayPal\PayPal + + PayPal + + + PayPal + + + + + en_US + fr_FR + + 4.0.9 + + + gbarral + gbarral@openstudio.fr + + + payment + 2.4.0 + other + diff --git a/domokits/local/modules/PayPal/Config/routing.xml b/domokits/local/modules/PayPal/Config/routing.xml new file mode 100644 index 0000000..2efe25d --- /dev/null +++ b/domokits/local/modules/PayPal/Config/routing.xml @@ -0,0 +1,108 @@ + + + + + + + diff --git a/domokits/local/modules/PayPal/Config/schema.xml b/domokits/local/modules/PayPal/Config/schema.xml new file mode 100644 index 0000000..8d3aea5 --- /dev/null +++ b/domokits/local/modules/PayPal/Config/schema.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/PayPal/Config/sqldb.map b/domokits/local/modules/PayPal/Config/sqldb.map new file mode 100644 index 0000000..63a93ba --- /dev/null +++ b/domokits/local/modules/PayPal/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +thelia.sql=thelia diff --git a/domokits/local/modules/PayPal/Config/thelia.sql b/domokits/local/modules/PayPal/Config/thelia.sql new file mode 100644 index 0000000..5eb2a2a --- /dev/null +++ b/domokits/local/modules/PayPal/Config/thelia.sql @@ -0,0 +1,210 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- paypal_customer +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_customer`; + +CREATE TABLE `paypal_customer` +( + `id` INTEGER NOT NULL, + `paypal_user_id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `name` VARCHAR(255), + `given_name` VARCHAR(255), + `family_name` VARCHAR(255), + `middle_name` VARCHAR(255), + `picture` VARCHAR(255), + `email_verified` TINYINT, + `gender` VARCHAR(255), + `birthday` VARCHAR(255), + `zoneinfo` VARCHAR(255), + `locale` VARCHAR(255), + `language` VARCHAR(255), + `verified` TINYINT, + `phone_number` VARCHAR(255), + `verified_account` VARCHAR(255), + `account_type` VARCHAR(255), + `age_range` VARCHAR(255), + `payer_id` VARCHAR(255), + `postal_code` VARCHAR(255), + `locality` VARCHAR(255), + `region` VARCHAR(255), + `country` VARCHAR(255), + `street_address` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`,`paypal_user_id`), + CONSTRAINT `fk_paypal_payer_customer_id` + FOREIGN KEY (`id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_planified_payment`; + +CREATE TABLE `paypal_planified_payment` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `frequency` VARCHAR(255) NOT NULL, + `frequency_interval` INTEGER NOT NULL, + `cycle` INTEGER NOT NULL, + `min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `position` INTEGER DEFAULT 0 NOT NULL, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_cart +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_cart`; + +CREATE TABLE `paypal_cart` +( + `id` INTEGER NOT NULL, + `credit_card_id` VARCHAR(40), + `planified_payment_id` INTEGER, + `express_payment_id` VARCHAR(255), + `express_payer_id` VARCHAR(255), + `express_token` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_cart_planified_payment_id` (`planified_payment_id`), + CONSTRAINT `fk_paypal_cart_cart_id` + FOREIGN KEY (`id`) + REFERENCES `cart` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_cart_planified_payment_id` + FOREIGN KEY (`planified_payment_id`) + REFERENCES `paypal_planified_payment` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_order +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_order`; + +CREATE TABLE `paypal_order` +( + `id` INTEGER NOT NULL, + `payment_id` VARCHAR(50), + `agreement_id` VARCHAR(255), + `credit_card_id` VARCHAR(40), + `state` VARCHAR(20), + `amount` DECIMAL(16,6) DEFAULT 0.000000, + `description` LONGTEXT, + `payer_id` VARCHAR(255), + `token` VARCHAR(255), + `planified_title` VARCHAR(255) NOT NULL, + `planified_description` LONGTEXT, + `planified_frequency` VARCHAR(255) NOT NULL, + `planified_frequency_interval` INTEGER NOT NULL, + `planified_cycle` INTEGER NOT NULL, + `planified_actual_cycle` INTEGER DEFAULT 0 NOT NULL, + `planified_min_amount` DECIMAL(16,6) DEFAULT 0.000000, + `planified_max_amount` DECIMAL(16,6) DEFAULT 0.000000, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + CONSTRAINT `fk_paypal_order_order_id` + FOREIGN KEY (`id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_plan +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_plan`; + +CREATE TABLE `paypal_plan` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `paypal_order_id` INTEGER NOT NULL, + `plan_id` VARCHAR(255), + `state` VARCHAR(255), + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_plan_paypal_order_id` (`paypal_order_id`), + CONSTRAINT `fk_paypal_plan_paypal_order_id` + FOREIGN KEY (`paypal_order_id`) + REFERENCES `paypal_order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_log +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_log`; + +CREATE TABLE `paypal_log` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER, + `order_id` INTEGER, + `hook` VARCHAR(255), + `channel` VARCHAR(255), + `level` INTEGER, + `message` LONGTEXT, + `time` INTEGER, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_paypal_log_customer_id` (`customer_id`), + INDEX `fi_paypal_log_order_id` (`order_id`), + CONSTRAINT `fk_paypal_log_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE, + CONSTRAINT `fk_paypal_log_order_id` + FOREIGN KEY (`order_id`) + REFERENCES `order` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- paypal_planified_payment_i18n +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `paypal_planified_payment_i18n`; + +CREATE TABLE `paypal_planified_payment_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255) NOT NULL, + `description` LONGTEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `paypal_planified_payment_i18n_fk_c9dfe7` + FOREIGN KEY (`id`) + REFERENCES `paypal_planified_payment` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/PayPal/Controller/ConfigurationController.php b/domokits/local/modules/PayPal/Controller/ConfigurationController.php new file mode 100644 index 0000000..5b50312 --- /dev/null +++ b/domokits/local/modules/PayPal/Controller/ConfigurationController.php @@ -0,0 +1,119 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Controller; + +use PayPal\Form\ConfigurationForm; +use PayPal\PayPal; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Core\Thelia; +use Thelia\Core\Translation\Translator; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Tools\URL; +use Thelia\Tools\Version\Version; +use Symfony\Component\Routing\Annotation\Route; + +/** + * @Route("/admin/module/paypal/configure", name="paypal_configure") + * Class ConfigurePaypal + * @package Paypal\Controller + */ +class ConfigurationController extends BaseAdminController +{ + /* + * Checks paypal.configure || paypal.configure.sandbox form and save config into json file + */ + /** + * @return mixed|\Symfony\Component\HttpFoundation\Response|\Thelia\Core\HttpFoundation\Response + * @Route("", name="_save", methods="POSt") + */ + public function configureAction(RequestStack $requestStack, Translator $translator) + { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'Paypal', AccessManager::UPDATE)) { + return $response; + } + + $configurationForm = $this->createForm(ConfigurationForm::getName()); + + try { + $form = $this->validateForm($configurationForm, "POST"); + + // Get the form field values + $data = $form->getData(); + + foreach ($data as $name => $value) { + if (is_array($value)) { + $value = implode(';', $value); + } + + Paypal::setConfigValue($name, $value); + } + + $this->adminLogAppend( + "paypal.configuration.message", + AccessManager::UPDATE, + sprintf("Paypal configuration updated") + ); + + if ($requestStack->getCurrentRequest()->get('save_mode') === 'stay') { + // If we have to stay on the same page, redisplay the configuration page/ + $url = '/admin/module/Paypal'; + } else { + // If we have to close the page, go back to the module back-office page. + $url = '/admin/modules'; + } + + return $this->generateRedirect(URL::getInstance()->absoluteUrl($url)); + } catch (FormValidationException $ex) { + $error_msg = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + $error_msg = $ex->getMessage(); + } + + $this->setupFormErrorContext( + $translator->trans("Paypal configuration", [], PayPal::DOMAIN_NAME), + $error_msg, + $configurationForm, + $ex + ); + + // Before 2.2, the errored form is not stored in session + if (Version::test(Thelia::THELIA_VERSION, '2.2', false, "<")) { + return $this->render('module-configure', [ 'module_code' => PayPal::getModuleCode()]); + } else { + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/PayPal')); + } + } + + /** + * @return \Thelia\Core\HttpFoundation\Response + * @Route("/log", name="_log", methods="GET") + */ + public function logAction() + { + return $this->render('paypal/paypal-log'); + } +} diff --git a/domokits/local/modules/PayPal/Controller/PayPalPlanifiedPaymentController.php b/domokits/local/modules/PayPal/Controller/PayPalPlanifiedPaymentController.php new file mode 100644 index 0000000..aed050a --- /dev/null +++ b/domokits/local/modules/PayPal/Controller/PayPalPlanifiedPaymentController.php @@ -0,0 +1,356 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Controller; + +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalPlanifiedPaymentEvent; +use PayPal\Form\PayPalFormFields; +use PayPal\Form\PayPalPlanifiedPaymentCreateForm; +use PayPal\Form\PayPalPlanifiedPaymentUpdateForm; +use PayPal\Model\PaypalPlanifiedPayment; +use PayPal\Model\PaypalPlanifiedPaymentQuery; +use PayPal\PayPal; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Translation\TranslatorInterface; +use Thelia\Controller\Admin\AbstractCrudController; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Template\ParserContext; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Tools\TokenProvider; + +/** + * @Route("/admin/module/paypal/configure/planified", name="configure_planified") + * Class PayPalPlanifiedPaymentController + * @package PayPal\Controller + */ +class PayPalPlanifiedPaymentController extends AbstractCrudController +{ + /** @var string */ + protected $currentRouter = PayPal::ROUTER; + + /** + * PayPalPlanifiedPaymentController constructor. + */ + public function __construct() + { + parent::__construct( + 'team', + 'id', + 'order', + 'paypal.back.planified.payment', + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_CREATE, + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_UPDATE, + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_DELETE + ); + } + + /** + * The default action is displaying the list. + * + * @return Response + * @Route("", name="_render", methods="GET") + */ + public function defaultAction() + { + // Check current user authorization + if (null !== $response = $this->checkAuth($this->resourceCode, $this->getModuleCode(), AccessManager::VIEW)) { + return $response; + } + + return $this->renderList(); + } + + /** + * @Route("/create", name="_create", methods="POST") + */ + public function createAction(EventDispatcherInterface $eventDispatcher, TranslatorInterface $translator) + { + return parent::createAction($eventDispatcher, $translator); + } + + /** + * @Route("/create/delete", name="_delete", methods="POST") + */ + public function deleteAction(Request $request, TokenProvider $tokenProvider, EventDispatcherInterface $eventDispatcher, ParserContext $parserContext) + { + return parent::deleteAction($request, $tokenProvider, $eventDispatcher, $parserContext); + } + + /** + * @Route("/{planifiedPaymentId}", name="_update", methods="GET") + */ + public function updateAction(ParserContext $parserContext) + { + return parent::updateAction($parserContext); + } + + /** + * @Route("/{planifiedPaymentId}", name="_process_update", methods="POST") + */ + public function processUpdateAction(Request $request, EventDispatcherInterface $eventDispatcher, TranslatorInterface $translator) + { + return parent::processUpdateAction($request, $eventDispatcher, $translator); + } + + + /** + * Return the creation form for this object + * @return PayPalPlanifiedPaymentCreateForm + */ + protected function getCreationForm() + { + return $this->createForm(PayPalPlanifiedPaymentCreateForm::getName()); + } + + /** + * Return the update form for this object + * @return PayPalPlanifiedPaymentUpdateForm + */ + protected function getUpdateForm() + { + return $this->createForm(PayPalPlanifiedPaymentUpdateForm::getName()); + } + + /** + * Hydrate the update form for this object, before passing it to the update template + * + * @param PaypalPlanifiedPayment $object + * @return PayPalPlanifiedPaymentUpdateForm + */ + protected function hydrateObjectForm(ParserContext $parserContext, $object) + { + /** @var \Thelia\Model\Lang $lang */ + $parserContext->getSession()->get('thelia.current.lang'); + $object->getTranslation($lang->getLocale()); + + $data = [ + PayPalFormFields::FIELD_PP_ID => $object->getId(), + PayPalFormFields::FIELD_PP_TITLE => $object->getTitle(), + PayPalFormFields::FIELD_PP_DESCRIPTION => $object->getDescription(), + PayPalFormFields::FIELD_PP_FREQUENCY => $object->getFrequency(), + PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL => $object->getFrequencyInterval(), + PayPalFormFields::FIELD_PP_CYCLE => $object->getCycle(), + PayPalFormFields::FIELD_PP_MIN_AMOUNT => $object->getMinAmount(), + PayPalFormFields::FIELD_PP_MAX_AMOUNT => $object->getMaxAmount(), + PayPalFormFields::FIELD_PP_POSITION => $object->getPosition() + ]; + + return $this->createForm(PayPalPlanifiedPaymentUpdateForm::getName(), 'form', $data); + } + + /** + * Creates the creation event with the provided form data + * + * @param mixed $formData + * @return PayPalPlanifiedPaymentEvent + */ + protected function getCreationEvent($formData) + { + $planifiedPayment = new PaypalPlanifiedPayment(); + + $planifiedPayment = $this->fillObjectWithDataForm($planifiedPayment, $formData); + + $planifiedPaymentEvent = new PayPalPlanifiedPaymentEvent($planifiedPayment); + + return $planifiedPaymentEvent; + } + + /** + * Creates the update event with the provided form data + * + * @param mixed $formData + * @return PayPalPlanifiedPaymentEvent + */ + protected function getUpdateEvent($formData) + { + if (null === $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById($formData[PayPalFormFields::FIELD_PP_ID])) { + throw new \InvalidArgumentException( + $this->getTranslator()->trans( + 'Invalid planified payment id : %id', + ['%id' => $formData[PayPalFormFields::FIELD_PP_ID]], + PayPal::DOMAIN_NAME + ) + ); + } + + $planifiedPayment = $this->fillObjectWithDataForm($planifiedPayment, $formData); + + $planifiedPaymentEvent = new PayPalPlanifiedPaymentEvent($planifiedPayment); + + return $planifiedPaymentEvent; + } + + /** + * @param PaypalPlanifiedPayment $planifiedPayment + * @param $formData + * @return PaypalPlanifiedPayment + */ + protected function fillObjectWithDataForm(PaypalPlanifiedPayment $planifiedPayment, $formData) + { + $planifiedPayment + ->setFrequency($formData[PayPalFormFields::FIELD_PP_FREQUENCY]) + ->setFrequencyInterval($formData[PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL]) + ->setCycle($formData[PayPalFormFields::FIELD_PP_CYCLE]) + ->setMinAmount($formData[PayPalFormFields::FIELD_PP_MIN_AMOUNT]) + ->setMaxAmount($formData[PayPalFormFields::FIELD_PP_MAX_AMOUNT]) + ->setLocale($formData[PayPalFormFields::FIELD_PP_LOCALE]) + ->setTitle($formData[PayPalFormFields::FIELD_PP_TITLE]) + ->setDescription($formData[PayPalFormFields::FIELD_PP_DESCRIPTION]) + ; + + return $planifiedPayment; + } + + /** + * Creates the delete event with the provided form data + * @return PayPalPlanifiedPaymentEvent + */ + protected function getDeleteEvent() + { + return new PayPalPlanifiedPaymentEvent( + $this->getExistingObject() + ); + } + + /** + * Return true if the event contains the object, e.g. the action has updated the object in the event. + * + * @param PayPalPlanifiedPaymentEvent $event + * @return bool + */ + protected function eventContainsObject($event) + { + return $event->getPayPalPlanifiedPayment() ? true : false; + } + + /** + * Get the created object from an event. + * @param PayPalPlanifiedPaymentEvent $event + * @return PaypalPlanifiedPayment + */ + protected function getObjectFromEvent($event) + { + return $event->getPayPalPlanifiedPayment(); + } + + /** + * Load an existing object from the database + * @return PaypalPlanifiedPayment + */ + protected function getExistingObject() + { + if (null === $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById((int)$this->getRequest()->get('planifiedPaymentId'))) { + throw new \InvalidArgumentException( + $this->getTranslator()->trans('Invalid planified payment id : %id', + ['%id' => (int)$this->getRequest()->get('planifiedPaymentId')], PayPal::DOMAIN_NAME) + ); + } + + return $planifiedPayment; + } + + /** + * Returns the object label form the object event (name, title, etc.) + * + * @param PaypalPlanifiedPayment $object + * @return string + */ + protected function getObjectLabel($object) + { + return $object->getTitle(); + } + + /** + * Returns the object ID from the object + * + * @param PaypalPlanifiedPayment $object + * @return int + */ + protected function getObjectId($object) + { + return $object->getId(); + } + + /** + * Render the main list template + * + * @param mixed $currentOrder , if any, null otherwise. + * @return Response + */ + protected function renderListTemplate($currentOrder) + { + $this->getListOrderFromSession('planified_payment', 'order', 'manual'); + + return $this->render( + 'paypal/planified-payment', + [ + 'order' => $currentOrder, + 'selected_menu' => 'planified' + ] + ); + } + + /** + * Render the edition template + * @return Response + */ + protected function renderEditionTemplate() + { + return $this->render('paypal/planified-payment-edit', $this->getEditionArguments()); + } + + /** + * Must return a RedirectResponse instance + * @return Response + */ + protected function redirectToEditionTemplate() + { + return $this->generateRedirectFromRoute( + 'paypal.admin.configuration.planified.update', + [], + $this->getEditionArguments() + ); + } + + /** + * Must return a RedirectResponse instance + * @return Response + */ + protected function redirectToListTemplate() + { + return $this->generateRedirectFromRoute('paypal.admin.configuration.planified'); + } + + /** + * @return array + */ + private function getEditionArguments() + { + return [ + 'planifiedPaymentId' => (int)$this->getRequest()->get('planifiedPaymentId') + ]; + } +} diff --git a/domokits/local/modules/PayPal/Controller/PayPalResponseController.php b/domokits/local/modules/PayPal/Controller/PayPalResponseController.php new file mode 100644 index 0000000..30493eb --- /dev/null +++ b/domokits/local/modules/PayPal/Controller/PayPalResponseController.php @@ -0,0 +1,970 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Controller; + +use Front\Controller\OrderController; +use Monolog\Logger; +use PayPal\Api\Details; +use PayPal\Api\PayerInfo; +use PayPal\Event\PayPalCartEvent; +use PayPal\Event\PayPalCustomerEvent; +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalOrderEvent; +use PayPal\Exception\PayPalConnectionException; +use PayPal\Model\PaypalCart; +use PayPal\Model\PaypalCartQuery; +use PayPal\Model\PaypalCustomer; +use PayPal\Model\PaypalCustomerQuery; +use PayPal\Model\PaypalOrder; +use PayPal\Model\PaypalOrderQuery; +use PayPal\PayPal; +use PayPal\Service\PayPalAgreementService; +use PayPal\Service\PayPalCustomerService; +use PayPal\Service\PayPalLoggerService; +use PayPal\Service\PayPalPaymentService; +use Propel\Runtime\Propel; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\Router; +use Thelia\Core\Event\Address\AddressCreateOrUpdateEvent; +use Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent; +use Thelia\Core\Event\Customer\CustomerLoginEvent; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\Order\OrderManualEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Security\SecurityContext; +use Thelia\Core\Translation\Translator; +use Thelia\Model\AddressQuery; +use Thelia\Model\CartQuery; +use Thelia\Model\Country; +use Thelia\Model\CountryQuery; +use Thelia\Model\CustomerQuery; +use Thelia\Model\CustomerTitleQuery; +use Thelia\Model\ModuleQuery; +use Thelia\Model\Order; +use Thelia\Model\OrderQuery; +use Thelia\Model\OrderStatusQuery; +use Thelia\Module\Exception\DeliveryException; +use Thelia\Tools\URL; +use Symfony\Component\Routing\Annotation\Route; + +/** + * @Route("", name="paypal") + * Class PayPalResponseController + * @package PayPal\Controller + */ +class PayPalResponseController extends OrderController +{ + /** + * @param $orderId + * @param EventDispatcherInterface $eventDispatcher + * @Route("/module/paypal/cancel/{orderId}", name="_cancel", methods="GET") + */ + public function cancelAction($orderId, EventDispatcherInterface $eventDispatcher) + { + if (!$order = OrderQuery::create()->findOneById($orderId)) { + return $this->pageNotFound(); + } + + $event = new OrderEvent($order); + $event->setStatus(OrderStatusQuery::getCancelledStatus()->getId()); + $eventDispatcher->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + + $orderId = $order->getId(); + $message = Translator::getInstance()->trans('Order cancel', [], PayPal::DOMAIN_NAME); + + return $this->generateRedirect(URL::getInstance()->absoluteUrl("/order/failed/$orderId/$message")); + } + + /** + * @param $orderId + * @param RequestStack $requestStack + * @param EventDispatcherInterface $eventDispatcher + * @return RedirectResponse + * @Route("/module/paypal/ok/{orderId}", name="_ok", methods="GET") + */ + public function okAction($orderId, RequestStack $requestStack, EventDispatcherInterface $eventDispatcher) + { + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + $request = $requestStack->getCurrentRequest(); + $payerId = $request->query->get('PayerID'); + $token = $request->query->get('token'); + $payPalOrder = PaypalOrderQuery::create()->findOneById($orderId); + + if (null !== $payPalOrder && null !== $payerId) { + + $response = $this->executePayment($eventDispatcher, $payPalOrder, $payPalOrder->getPaymentId(), $payerId, $token); + } else { + $con->rollBack(); + $message = Translator::getInstance()->trans( + 'Method okAction => One of this parameter is invalid : $payerId = %payer_id, $orderId = %order_id', + [ + '%payer_id' => $payerId, + '%order_id' => $orderId + ], + PayPal::DOMAIN_NAME + ); + + PayPalLoggerService::log( + $message, + [ + 'order_id' => $orderId + ], + Logger::CRITICAL + ); + + $response = $this->getPaymentFailurePageUrl($orderId, $message); + } + } catch (PayPalConnectionException $e) { + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'order_id' => $orderId + ], + Logger::CRITICAL + ); + $response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage()); + } catch (\Exception $e) { + PayPalLoggerService::log( + $e->getMessage(), + [ + 'order_id' => $orderId + ], + Logger::CRITICAL + ); + + $response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage()); + } + + $con->commit(); + return $response; + } + + + /** + * @param RequestStack $requestStack + * @param EventDispatcherInterface $dispatcher + * @param string $routeId + * @param bool $fromCartView + * @return RedirectResponse + * @Route("/module/paypal/express/checkout", name="_express_checkout", methods="POST") + */ + public function expressCheckoutAction(RequestStack $requestStack, EventDispatcherInterface $dispatcher, $routeId = 'cart.view', $fromCartView = true) + { + $session = $requestStack->getCurrentRequest()->getSession(); + $cart = $session->getSessionCart($dispatcher); + + if (null !== $cart) { + /** @var PayPalPaymentService $payPalService */ + $payPalService = $this->getContainer()->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID); + + $payment = $payPalService->makePaymentFromCart( + $cart, + null, + false, + $fromCartView + ); + $response = new RedirectResponse($payment->getApprovalLink()); + + return $response; + } + + return $this->getUrlFromRouteId('cart.view'); + } + + /** + * @Route("/module/paypal/invoice/express/checkout", name="_invoice_express_checkout", methods="POST") + */ + public function invoiceExpressCheckoutAction(RequestStack $requestStack, EventDispatcherInterface $dispatcher) + { + return $this->expressCheckoutAction($requestStack, $dispatcher, 'order.invoice', false); + } + + /** + * @param int $cartId + * @return RedirectResponse + * @throws PayPalConnectionException + * @throws \Exception + * @Route("/module/paypal/invoice/express/checkout/ok/{cartId}", name="_invoice_express_checkout_ok", methods="GET") + */ + public function invoiceExpressCheckoutOkAction($cartId, RequestStack $requestStack, EventDispatcherInterface $eventDispatcher, SecurityContext $securityContext, Translator $translator) + { + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + $this->fillCartWithExpressCheckout($requestStack->getCurrentRequest(), $eventDispatcher, $securityContext); + + $response = $this->executeExpressCheckoutAction($requestStack, $eventDispatcher,$translator,false); + + } catch (PayPalConnectionException $e) { + $con->rollBack(); + + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + throw $e; + } catch(\Exception $e) { + $con->rollBack(); + + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + throw $e; + } + + $con->commit(); + return $response; + } + + /** + * @Route("/module/paypal/invoice/express/checkout/ko/{cartId}", name="_invoice_express_checkout_ko", methods="GET") + */ + public function invoiceExpressCheckoutKoAction($cartId) + { + return $this->getUrlFromRouteId('order.invoice'); + } + + /** + * @return RedirectResponse + * @throws PayPalConnectionException + * @throws \Exception + * @Route("/module/paypal/express/checkout/ok/{cartId}", name="_express_checkout_ok", methods="POST") + */ + public function expressCheckoutOkAction(RequestStack $requestStack, EventDispatcherInterface $eventDispatcher, SecurityContext $securityContext) + { + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + $this->fillCartWithExpressCheckout($requestStack->getCurrentRequest(), $eventDispatcher, $securityContext); + + $response = $this->getUrlFromRouteId('order.delivery'); + + + } catch (PayPalConnectionException $e) { + $con->rollBack(); + + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + throw $e; + } catch(\Exception $e) { + $con->rollBack(); + + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + throw $e; + } + + $con->commit(); + return $response; + } + + /** + * @return RedirectResponse|\Symfony\Component\HttpFoundation\Response + * @Route("/order/delivery", name="_order_delivery", methods="POST") + */ + public function executeExpressCheckoutAction(RequestStack $requestStack, EventDispatcherInterface $eventDispatcher, Translator $translator, $fromCartView = true) + { + if (null === $responseParent = parent::deliver($eventDispatcher)) { + + if ($fromCartView) { + return $responseParent; + } + } + + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + $session = $requestStack->getCurrentRequest()->getSession(); + $cart = $session->getSessionCart($eventDispatcher); + + if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) { + $con->rollBack(); + return $responseParent; + } + + if (null === $payPalCart->getExpressPaymentId() || null === $payPalCart->getExpressPayerId() || null === $payPalCart->getExpressToken()) { + $con->rollBack(); + return $responseParent; + } + + /** @var PayPalPaymentService $payPalPaymentService */ + $payPalPaymentService = $this->container->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID); + $payment = $payPalPaymentService->getPaymentDetails($payPalCart->getExpressPaymentId()); + + $payerInfo = $payment->getPayer()->getPayerInfo(); + + //Check if invoice adresse already exist + if (null === $payerInfo->getBillingAddress()) { + $line1 = $payerInfo->getShippingAddress()->getLine1(); + $zipCode = $payerInfo->getShippingAddress()->getPostalCode(); + } else { + $line1 = $payerInfo->getBillingAddress()->getLine1(); + $zipCode = $payerInfo->getBillingAddress()->getPostalCode(); + } + + /** @var \Thelia\Model\Address $invoiceAddress */ + if (null === $invoiceAddress = AddressQuery::create() + ->filterByCustomerId($cart->getCustomerId()) + ->filterByIsDefault(0) + ->filterByAddress1($line1) + ->filterByZipcode($zipCode) + ->findOne()) { + + $event = $this->createAddressEvent($payerInfo); + $event->setCustomer($cart->getCustomer()); + + $eventDispatcher->dispatch($event, TheliaEvents::ADDRESS_CREATE); + $invoiceAddress = $event->getAddress(); + } + + if (null === $payPalCustomer = PaypalCustomerQuery::create()->findOneById($cart->getCustomerId())) { + $payPalCustomer = new PaypalCustomer(); + $payPalCustomer->setId($cart->getCustomerId()); + } + + $payPalCustomer + ->setPaypalUserId($payerInfo->getPayerId()) + ->setName($payerInfo->getFirstName()) + ->setGivenName($payerInfo->getFirstName() . ' ' . $payerInfo->getLastName()) + ->setFamilyName($payerInfo->getLastName()) + ->setMiddleName($payerInfo->getMiddleName()) + ->setBirthday($payerInfo->getBirthDate()) + ->setLocale($requestStack->getCurrentRequest()->getSession()->getLang()->getLocale()) + ->setPhoneNumber($payerInfo->getPhone()) + ->setPayerId($payerInfo->getPayerId()) + ->setPostalCode($payerInfo->getShippingAddress()->getPostalCode()) + ->setCountry($payerInfo->getShippingAddress()->getCountryCode()) + ->setStreetAddress($payerInfo->getShippingAddress()->getLine1() . $payerInfo->getShippingAddress()->getLine2()) + ; + + $payPalCustomerEvent = new PayPalCustomerEvent($payPalCustomer); + $eventDispatcher->dispatch($payPalCustomerEvent, PayPalEvents::PAYPAL_CUSTOMER_UPDATE); + + /** @var \Thelia\Model\Address $deliveryAddress */ + $deliveryAddress = $cart->getCustomer()->getDefaultAddress(); + + /** @var \Thelia\Model\Module $deliveryModule */ + $deliveryModule = ModuleQuery::create()->filterByActivate(1)->findOne(); + /** @var \Thelia\Model\Module $paymentModule */ + $paymentModule = ModuleQuery::create()->findPk(PayPal::getModuleId()); + + /** @var \Thelia\Model\Currency $currency */ + $currency = $cart->getCurrency(); + $lang = $requestStack->getCurrentRequest()->getSession()->getLang(); + + $order = new Order(); + $order + ->setCustomerId($cart->getCustomerId()) + ->setCurrencyId($currency->getId()) + ->setCurrencyRate($currency->getRate()) + ->setStatusId(OrderStatusQuery::getNotPaidStatus()->getId()) + ->setLangId($lang->getDefaultLanguage()->getId()) + ->setChoosenDeliveryAddress($deliveryAddress) + ->setChoosenInvoiceAddress($invoiceAddress) + ; + + $orderEvent = new OrderEvent($order); + + /* get postage amount */ + $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $eventDispatcher->dispatch( + $deliveryPostageEvent, + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE + ); + + if (!$deliveryPostageEvent->isValidModule() || null === $deliveryPostageEvent->getPostage()) { + throw new DeliveryException( + $translator->trans('The delivery module is not valid.', [], PayPal::DOMAIN_NAME) + ); + } + + $postage = $deliveryPostageEvent->getPostage(); + + $orderEvent->setPostage($postage->getAmount()); + $orderEvent->setPostageTax($postage->getAmountTax()); + $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); + $orderEvent->setDeliveryAddress($deliveryAddress->getId()); + $orderEvent->setInvoiceAddress($invoiceAddress->getId()); + $orderEvent->setDeliveryModule($deliveryModule->getId()); + $orderEvent->setPaymentModule($paymentModule->getId()); + + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_ADDRESS); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_INVOICE_ADDRESS); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_POSTAGE); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_DELIVERY_MODULE); + $eventDispatcher->dispatch($orderEvent, TheliaEvents::ORDER_SET_PAYMENT_MODULE); + + $orderManualEvent = new OrderManualEvent( + $orderEvent->getOrder(), + $orderEvent->getOrder()->getCurrency(), + $orderEvent->getOrder()->getLang(), + $cart, + $cart->getCustomer() + ); + + $eventDispatcher->dispatch($orderManualEvent, TheliaEvents::ORDER_CREATE_MANUAL); + $order = $orderManualEvent->getPlacedOrder(); + + $payPalOrderEvent = $payPalPaymentService->generatePayPalOrder($order); + $payPalPaymentService->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $payment->getState(), $payment->getId()); + + $response = $this->executePayment( + $eventDispatcher, + $payPalOrderEvent->getPayPalOrder(), + $payPalCart->getExpressPaymentId(), + $payPalCart->getExpressPayerId(), + $payPalCart->getExpressToken(), + PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT, + $payPalPaymentService->createDetails( + $order->getPostage(), + $order->getPostageTax(), + $order->getTotalAmount($tax, false) + ) + ); + + $con->commit(); + } catch (PayPalConnectionException $e) { + $con->rollBack(); + + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + $response = $responseParent; + } catch(\Exception $e) { + $con->rollBack(); + + $customerId = null; + if (isset($customer)) { + $customerId = $customer->getId(); + } + + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $customerId + ], + Logger::CRITICAL + ); + $response = $responseParent; + } + + $con->commit(); + return $response; + } + + /** + * @Route("/module/paypal/express/checkout/ko/{cartId}", name="_express_checkout_ko", methods="POST") + */ + public function expressCheckoutKoAction() + { + PayPalLoggerService::log( + Translator::getInstance()->trans('Express Checkout login failed', [], PayPal::DOMAIN_NAME), + [], + Logger::WARNING + ); + return $this->getUrlFromRouteId('cart.view'); + } + + /** + * Method called when a customer log in with PayPal. + * @param RequestStack $requestStack + * @param EventDispatcherInterface $eventDispatcher + * @return RedirectResponse + * @throws \Propel\Runtime\Exception\PropelException + * @Route("/module/paypal/login/ok", name="_login_ok", methods="GET") + */ + public function loginOkAction(RequestStack $requestStack, EventDispatcherInterface $eventDispatcher) + { + if (null !== $authorizationCode = $requestStack->getCurrentRequest()->query->get('code')) { + + /** @var PayPalCustomerService $payPalCustomerService */ + $payPalCustomerService = $this->container->get(PayPal::PAYPAL_CUSTOMER_SERVICE_ID); + $openIdUserinfo = $payPalCustomerService->getUserInfoWithAuthorizationCode($authorizationCode); + + $payPalCustomer = $payPalCustomerService->getCurrentPayPalCustomer(); + $payPalCustomer + ->setPaypalUserId($openIdUserinfo->getUserId()) + ->setName($openIdUserinfo->getName()) + ->setGivenName($openIdUserinfo->getGivenName()) + ->setFamilyName($openIdUserinfo->getFamilyName()) + ->setMiddleName($openIdUserinfo->getMiddleName()) + ->setPicture($openIdUserinfo->getPicture()) + ->setEmailVerified($openIdUserinfo->getEmailVerified()) + ->setGender($openIdUserinfo->getGender()) + ->setBirthday($openIdUserinfo->getBirthday()) + ->setZoneinfo($openIdUserinfo->getZoneinfo()) + ->setLocale($openIdUserinfo->getLocale()) + ->setLanguage($openIdUserinfo->getLanguage()) + ->setVerified($openIdUserinfo->getVerified()) + ->setPhoneNumber($openIdUserinfo->getPhoneNumber()) + ->setVerifiedAccount($openIdUserinfo->getVerifiedAccount()) + ->setAccountType($openIdUserinfo->getAccountType()) + ->setAgeRange($openIdUserinfo->getAgeRange()) + ->setPayerId($openIdUserinfo->getPayerId()) + ->setPostalCode($openIdUserinfo->getAddress()->getPostalCode()) + ->setLocality($openIdUserinfo->getAddress()->getLocality()) + ->setRegion($openIdUserinfo->getAddress()->getRegion()) + ->setCountry($openIdUserinfo->getAddress()->getCountry()) + ->setStreetAddress($openIdUserinfo->getAddress()->getStreetAddress()) + ; + + $payPalCustomerEvent = new PayPalCustomerEvent($payPalCustomer); + $eventDispatcher->dispatch($payPalCustomerEvent, PayPalEvents::PAYPAL_CUSTOMER_UPDATE); + + $eventDispatcher->dispatch(new CustomerLoginEvent($payPalCustomerEvent->getPayPalCustomer()->getCustomer()), TheliaEvents::CUSTOMER_LOGIN); + } + + return new RedirectResponse(URL::getInstance()->absoluteUrl($requestStack->getCurrentRequest()->getSession()->getReturnToUrl())); + } + + /** + * @Route("/module/paypal/agreement/ok/{orderId}", name="_agreement_ok", methods="GET") + */ + public function agreementOkAction($orderId, RequestStack $requestStack, EventDispatcherInterface $eventDispatcher) + { + $con = Propel::getConnection(); + $con->beginTransaction(); + + $token = $requestStack->getCurrentRequest()->query->get('token'); + $payPalOrder = PaypalOrderQuery::create()->findOneById($orderId); + + if (null !== $payPalOrder && null !== $token) { + + try { + /** @var PayPalAgreementService $payPalAgreementService */ + $payPalAgreementService = $this->container->get(PayPal::PAYPAL_AGREEMENT_SERVICE_ID); + $agreement = $payPalAgreementService->activateBillingAgreementByToken($token); + + $payPalOrder + ->setState($agreement->getState()) + ->setAgreementId($agreement->getId()) + ->setPayerId($agreement->getPayer()->getPayerInfo()->getPayerId()) + ->setToken($token) + ; + $payPalOrderEvent = new PayPalOrderEvent($payPalOrder); + $eventDispatcher->dispatch($payPalOrderEvent, PayPalEvents::PAYPAL_ORDER_UPDATE); + + $event = new OrderEvent($payPalOrder->getOrder()); + $event->setStatus(OrderStatusQuery::getPaidStatus()->getId()); + $eventDispatcher->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + + $response = $this->getPaymentSuccessPageUrl($orderId); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order payed with success in PayPal with method : %method', + [ + '%method' => PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT + ], + PayPal::DOMAIN_NAME + ), + [ + 'order_id' => $payPalOrder->getId(), + 'customer_id' => $payPalOrder->getOrder()->getCustomerId() + ], + Logger::INFO + ); + } catch (PayPalConnectionException $e) { + $con->rollBack(); + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $orderId + ], + Logger::CRITICAL + ); + + $response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage()); + } catch (\Exception $e) { + $con->rollBack(); + PayPalLoggerService::log( + $e->getMessage(), + [ + 'order_id' => $orderId + ], + Logger::CRITICAL + ); + + $response = $this->getPaymentFailurePageUrl($orderId, $e->getMessage()); + } + + } else { + $con->rollBack(); + $message = Translator::getInstance()->trans( + 'Method agreementOkAction => One of this parameter is invalid : $token = %token, $orderId = %order_id', + [ + '%token' => $token, + '%order_id' => $orderId + ], + PayPal::DOMAIN_NAME + ); + + PayPalLoggerService::log( + $message, + [ + 'order_id' => $orderId + ], + Logger::CRITICAL + ); + + $response = $this->getPaymentFailurePageUrl($orderId, $message); + } + + $con->commit(); + return $response; + } + + /** + * @Route("/module/paypal/ipn/{orderId}", name="_ipn", methods="GET") + */ + public function ipnAction($orderId, RequestStack $requestStack) + { + PayPalLoggerService::log('GUIGIT', ['hook' => 'guigit', 'order_id' => $orderId], Logger::DEBUG); + + PayPalLoggerService::log( + print_r($requestStack->getCurrentRequest()->request, true), + [ + 'hook' => 'guigit', + 'order_id' => $orderId + ], + Logger::DEBUG + ); + PayPalLoggerService::log( + print_r($this->getRequest()->attributes, true), + [ + 'hook' => 'guigit', + 'order_id' => $orderId + ], + Logger::DEBUG + ); + } + + /** + * Return the order payment success page URL + * + * @param $orderId + * @return RedirectResponse + */ + public function getPaymentSuccessPageUrl($orderId) + { + return $this->getUrlFromRouteId('order.placed', ['order_id' => $orderId]); + } + + /** + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + protected function fillCartWithExpressCheckout(Request $request, EventDispatcherInterface $eventDispatcher, SecurityContext $securityContext) + { + $paymentId = $request->get('paymentId'); + $token = $request->get('token'); + $payerId = $request->get('PayerID'); + $cartId = $request->get('cartId'); + $cart = CartQuery::create()->findOneById($request->get('cartId')); + + if (null === $paymentId || null === $token || null === $payerId || null === $cart) { + PayPalLoggerService::log( + Translator::getInstance()->trans('Express checkout failed in expressCheckoutOkAction() function', [], PayPal::DOMAIN_NAME), + [], + Logger::CRITICAL + ); + } + + PayPalLoggerService::log( + Translator::getInstance()->trans('Express checkout begin with cart %id', ['%id' => $cartId], PayPal::DOMAIN_NAME) + ); + + /** @var PayPalPaymentService $payPalPaymentService */ + $payPalPaymentService = $this->container->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID); + $payment = $payPalPaymentService->getPaymentDetails($paymentId); + + $payerInfo = $payment->getPayer()->getPayerInfo(); + if (null === $customer = CustomerQuery::create()->findOneByEmail($payment->getPayer()->getPayerInfo()->getEmail())) { + + $customerCreateEvent = $this->createEventInstance($payerInfo, $request); + + $eventDispatcher->dispatch($customerCreateEvent, TheliaEvents::CUSTOMER_CREATEACCOUNT); + + $customer = $customerCreateEvent->getCustomer(); + + } + + //Save informations to use them after customer has choosen the delivery method + if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cartId)) { + $payPalCart = new PaypalCart(); + $payPalCart->setId($cartId); + } + + $payPalCart + ->setExpressPaymentId($paymentId) + ->setExpressPayerId($payerId) + ->setExpressToken($token) + ; + $payPalCartEvent = new PayPalCartEvent($payPalCart); + $eventDispatcher->dispatch($payPalCartEvent, PayPalEvents::PAYPAL_CART_UPDATE); + + $cart->setCustomerId($customer->getId())->save(); + $clonedCart = clone $cart; + $this->dispatch(TheliaEvents::CUSTOMER_LOGIN, new CustomerLoginEvent($customer)); + + //In case of the current customer has changed, re affect the correct cart and customer session + $securityContext->setCustomerUser($customer); + $clonedCart->save(); + $request->getSession()->set("thelia.cart_id", $clonedCart->getId()); + } + + /** + * @param $routeId + * @param array $params + * @return RedirectResponse + */ + protected function getUrlFromRouteId($routeId, $params = []) + { + $frontOfficeRouter = $this->getContainer()->get('router.front'); + + return new RedirectResponse( + URL::getInstance()->absoluteUrl( + $frontOfficeRouter->generate( + $routeId, + $params, + Router::ABSOLUTE_URL + ) + ) + ); + } + + /** + * Redirect the customer to the failure payment page. if $message is null, a generic message is displayed. + * + * @param $orderId + * @param $message + * @return RedirectResponse + */ + public function getPaymentFailurePageUrl($orderId, $message) + { + $frontOfficeRouter = $this->getContainer()->get('router.front'); + + return new RedirectResponse( + URL::getInstance()->absoluteUrl( + $frontOfficeRouter->generate( + "order.failed", + array( + "order_id" => $orderId, + "message" => $message + ), + Router::ABSOLUTE_URL + ) + ) + ); + } + + /** + * @param PaypalOrder $payPalOrder + * @param $paymentId + * @param $payerId + * @param $token + * @param string $method + * @param Details|null $details + * @return RedirectResponse + */ + protected function executePayment(EventDispatcherInterface $eventDispatcher, PaypalOrder $payPalOrder, $paymentId, $payerId, $token, $method = PayPal::PAYPAL_METHOD_PAYPAL, Details $details = null) + { + /** @var PayPalPaymentService $payPalService */ + $payPalService = $this->getContainer()->get(PayPal::PAYPAL_PAYMENT_SERVICE_ID); + $payment = $payPalService->executePayment($paymentId, $payerId, $details); + + $payPalOrder + ->setState($payment->getState()) + ->setPayerId($payerId) + ->setToken($token) + ; + $payPalOrderEvent = new PayPalOrderEvent($payPalOrder); + $eventDispatcher->dispatch($payPalOrderEvent, PayPalEvents::PAYPAL_ORDER_UPDATE); + + $event = new OrderEvent($payPalOrder->getOrder()); + $event->setStatus(OrderStatusQuery::getPaidStatus()->getId()); + $eventDispatcher->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + + $response = $this->getPaymentSuccessPageUrl($payPalOrder->getId()); + + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order payed with success in PayPal with method : %method', + [ + '%method' => $method + ], + PayPal::DOMAIN_NAME + ), + [ + 'order_id' => $payPalOrder->getId(), + 'customer_id' => $payPalOrder->getOrder()->getCustomerId() + ], + Logger::INFO + ); + + + return $response; + } + + /** + * @param PayerInfo $payerInfo + * @return \Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent + */ + protected function createEventInstance(PayerInfo $payerInfo, Request $request) + { + if (null === $country = CountryQuery::create()->findOneByIsoalpha2($payerInfo->getShippingAddress()->getCountryCode())) { + $country = Country::getDefaultCountry(); + } + + $customerCreateEvent = new CustomerCreateOrUpdateEvent( + CustomerTitleQuery::create()->findOne()->getId(), + $payerInfo->getFirstName(), + $payerInfo->getLastName(), + $payerInfo->getShippingAddress()->getLine1(), + $payerInfo->getShippingAddress()->getLine2(), + null, + $payerInfo->getPhone(), + null, + $payerInfo->getShippingAddress()->getPostalCode(), + $payerInfo->getShippingAddress()->getCity(), + $country->getId(), + $payerInfo->getEmail(), + 'random', + $request->getSession()->getLang()->getId(), + null, + null, + null, + null, + null, + null + ); + + return $customerCreateEvent; + } + + /** + * @param PayerInfo $payerInfo + * @return AddressCreateOrUpdateEvent + */ + protected function createAddressEvent(PayerInfo $payerInfo) + { + if (null !== $payerInfo->getBillingAddress()) { + $countryCode = $payerInfo->getBillingAddress()->getCountryCode(); + $line1 = $payerInfo->getBillingAddress()->getLine1(); + $line2 = $payerInfo->getBillingAddress()->getLine2(); + $zipCode = $payerInfo->getBillingAddress()->getPostalCode(); + $city = $payerInfo->getBillingAddress()->getCity(); + } else { + $countryCode = $payerInfo->getShippingAddress()->getCountryCode(); + $line1 = $payerInfo->getShippingAddress()->getLine1(); + $line2 = $payerInfo->getShippingAddress()->getLine2(); + $zipCode = $payerInfo->getShippingAddress()->getPostalCode(); + $city = $payerInfo->getShippingAddress()->getCity(); + } + + if (null === $country = CountryQuery::create()->findOneByIsoalpha2($countryCode)) { + $country = Country::getDefaultCountry(); + } + + return new AddressCreateOrUpdateEvent( + 'Express checkout PayPal', + CustomerTitleQuery::create()->findOne()->getId(), + $payerInfo->getFirstName(), + $payerInfo->getLastName(), + $line1, + ($line2)?$line2:'', + '', + $zipCode, + $city, + $country->getId(), + $payerInfo->getPhone(), + $payerInfo->getPhone(), + '', + 0, + null + ); + } +} diff --git a/domokits/local/modules/PayPal/Controller/PayPalWebHookController.php b/domokits/local/modules/PayPal/Controller/PayPalWebHookController.php new file mode 100644 index 0000000..c254fa5 --- /dev/null +++ b/domokits/local/modules/PayPal/Controller/PayPalWebHookController.php @@ -0,0 +1,344 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Controller; + +use Monolog\Logger; +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalOrderEvent; +use PayPal\Exception\PayPalConnectionException; +use PayPal\Model\PaypalOrderQuery; +use PayPal\Model\PaypalPlanQuery; +use PayPal\PayPal; +use PayPal\Service\PayPalAgreementService; +use PayPal\Service\PayPalLoggerService; +use Propel\Runtime\Propel; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Translation\Translator; +use Thelia\Model\OrderStatusQuery; +use Symfony\Component\Routing\Annotation\Route; + +/** + * @Route("/module/paypal/webhook/all/events", name="paypal_webhook_events") + * Class PayPalWebHookController + * @package PayPal\Controller + */ +class PayPalWebHookController extends BaseFrontController +{ + const HOOK_BILLING_PLAN_CREATED = 'BILLING.PLAN.CREATED'; + const HOOK_BILLING_PLAN_UPDATED = 'BILLING.PLAN.UPDATED'; + const HOOK_BILLING_SUBSCRIPTION_CREATED = 'BILLING.SUBSCRIPTION.CREATED'; + + const HOOK_PAYMENT_SALE_COMPLETED = 'PAYMENT.SALE.COMPLETED'; + const HOOK_PAYMENT_SALE_DENIED = 'PAYMENT.SALE.DENIED'; + + //Classic PayPal payment + const RESOURCE_TYPE_SALE = 'sale'; + + //Planified payment + const RESOURCE_TYPE_PLAN = 'plan'; + const RESOURCE_TYPE_AGREEMENT = 'agreement'; + + /** + * Example of array received in posted params : + * + * + * Array ( + * 'id' => 'WH-0LU96374794024348-4WG31854RU4949452', + * 'event_version' => 1.0, + * 'create_time' => '2017-02-03T15:31:29Z', + * 'resource_type' => 'plan', + * 'event_type' => 'BILLING.PLAN.CREATED', + * 'summary' => 'A billing plan was created', + * 'resource' => Array ( + * 'merchant_preferences' => Array ( + * 'setup_fee' => Array ( + * 'currency' => 'EUR', + * 'value' => 0 + * ), + * 'return_url' => 'http://25b3ee89.ngrok.io/thelia_2_3_3/web/module/paypal/agreement/ok/208', + * 'cancel_url' => 'http://25b3ee89.ngrok.io/thelia_2_3_3/web/module/paypal/agreement/ko/208', + * 'auto_bill_amount' => 'NO', + * 'initial_fail_amount_action' => 'CONTINUE', + * 'max_fail_attempts' => 0 + * ), + * 'update_time' => '2017-02-03T15:31:29.348Z', + * 'create_time' => '2017-02-03T15:31:29.348Z', + * 'name' => 'plan for order 208', + * 'description' => false, + * 'links' => Array ( + * 0 => Array ( + * 'href' => 'api.sandbox.paypal.com/v1/payments/billing-plans/P-2DV20774VJ3968037ASNA3RA', + * 'rel' => 'self', + * 'method' => 'GET' + * ) + * ), + * 'payment_definitions' => Array ( + * 0 => Array ( + * 'name' => 'payment definition for order 208', + * 'type' => 'REGULAR', + * 'frequency' => 'Day', + * 'frequency_interval' => 1, + * 'amount' => Array ( + * 'currency' => 'EUR', + * 'value' => 3.9 + * ), + * 'cycles' => 5, + * 'charge_models' => Array ( + * 0 => Array ( + * 'type' => 'SHIPPING', + * 'amount' => Array ( + * 'currency' => 'EUR', + * 'value' => 0 + * ), + * 'id' => 'CHM-26B03456D8799461GASNA3RA' + * ) + * ), + * 'id' => 'PD-3FB00313143031422ASNA3RA' + * ) + * ), + * 'id' => 'P-2DV20774VJ3968037ASNA3RA', + * 'state' => 'CREATED', + * 'type' => 'FIXED' + * ), + * 'links' => Array ( + * 0 => Array ( + * 'href' => 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0LU96374794024348-4WG31854RU4949452', + * 'rel' => 'self', + * 'method' => 'GET' + * ), + * 1 => Array ( + * 'href' => 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0LU96374794024348-4WG31854RU4949452/resend', + * 'rel' => 'resend', + * 'method' => 'POST' + * ) + * ) + * ); + * + * @Route("", name="_all", methods="GET") + */ + public function allAction(RequestStack $requestStack, EventDispatcherInterface $eventDispatcher) + { + $request = $requestStack->getCurrentRequest(); + $eventType = $request->request->get('event_type'); + $resource = $request->request->get('resource'); + $resourceType = $request->request->get('resource_type'); + + $details = [ + 'request' => $this->getRequest()->request->all() + ]; + + $params = [ + 'hook' => $eventType + ]; + + $con = Propel::getConnection(); + $con->beginTransaction(); + + try { + + $title = $this->getTitle($request); + + if (is_array($resource)) { + + switch (strtolower($resourceType)) { + + case self::RESOURCE_TYPE_SALE: + if (isset($resource['parent_payment'])) { + $params = $this->getParamsForSale($resource['parent_payment'], $params, $eventType); + } + if (isset($resource['billing_agreement_id'])) { + $params = $this->getParamsForAgreement($eventDispatcher, $resource['billing_agreement_id'], $params); + } + break; + + case self::RESOURCE_TYPE_PLAN: + if (isset($resource['id'])) { + $params = $this->getParamsForPlan($resource['id'], $params); + } + break; + + case self::RESOURCE_TYPE_AGREEMENT: + if (isset($resource['id'])) { + $params = $this->getParamsForAgreement($eventDispatcher, $resource['id'], $params); + } + break; + + default: + break; + } + } + + PayPalLoggerService::log( + '

' . $title . '

' . $this->printRecursiveData($details), + $params, + Logger::INFO + ); + + $con->commit(); + } catch (PayPalConnectionException $e) { + + $con->rollBack(); + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log($message, $params, Logger::CRITICAL); + PayPalLoggerService::log($this->printRecursiveData($this->getRequest()->request), $params, Logger::CRITICAL); + + } catch (\Exception $e) { + + $con->rollBack(); + PayPalLoggerService::log($e->getMessage(), $params, Logger::CRITICAL); + PayPalLoggerService::log($this->printRecursiveData($this->getRequest()->request), $params, Logger::CRITICAL); + + } + } + + /** + * @param Request $request + * @return string + */ + protected function getTitle(Request $request) + { + $summary = $request->request->get('summary'); + + $title = ''; + if (null !== $request->get('event_type')) { + $title .= $request->get('event_type') . ' : '; + } + $title .= $summary; + + return $title; + } + + /** + * @param null $paymentId + * @param array $params + * @param null $eventType + * @return array + */ + protected function getParamsForSale($paymentId = null, $params = [], $eventType = null) + { + if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneByPaymentId($paymentId)) { + $params['order_id'] = $payPalOrder->getId(); + $params['customer_id'] = $payPalOrder->getOrder()->getCustomerId(); + + if ($eventType === self::HOOK_PAYMENT_SALE_DENIED) { + $event = new OrderEvent($payPalOrder->getOrder()); + $event->setStatus(OrderStatusQuery::getCancelledStatus()->getId()); + $this->dispatch(TheliaEvents::ORDER_UPDATE_STATUS, $event); + } + } + + return $params; + } + + /** + * @param null $planId + * @param array $params + * @return array + */ + protected function getParamsForPlan($planId = null, $params = []) + { + if (null !== $payPalPlan = PaypalPlanQuery::create()->findOneByPlanId($planId)) { + + $params['order_id'] = $payPalPlan->getPaypalOrderId(); + $params['customer_id'] = $payPalPlan->getPaypalOrder()->getOrder()->getCustomerId(); + + } + + return $params; + } + + /** + * @param null $agreementId + * @param array $params + * @return array + */ + protected function getParamsForAgreement(EventDispatcherInterface $eventDispatcher, $agreementId = null, $params = []) + { + if (null !== $payPalOrder = PaypalOrderQuery::create()->filterByAgreementId($agreementId)->orderById()->findOne()) { + + // Do not duplicate order for the first PayPal payment because order has just been created. + // We will duplicate this order for the next PayPal payment :) + if ($payPalOrder->getPlanifiedActualCycle() > 0) { + $params['order_id'] = $payPalOrder->getId(); + $params['customer_id'] = $payPalOrder->getOrder()->getCustomerId(); + + /** @var PayPalAgreementService $payPalAgreementService */ + $payPalAgreementService = $this->container->get(PayPal::PAYPAL_AGREEMENT_SERVICE_ID); + $newOrder = $payPalAgreementService->duplicateOrder($payPalOrder->getOrder()); + + Translator::getInstance()->trans( + 'New recursive invoice from order %id', + ['%id' => $payPalOrder->getId()], + PayPal::DOMAIN_NAME + ); + + PayPalLoggerService::log( + '

New recursive invoice from order ' . $payPalOrder->getId() . '

', + [ + 'order_id' => $newOrder->getId(), + 'customer_id' => $payPalOrder->getOrder()->getCustomerId() + ], + Logger::INFO + ); + } + + $payPalOrder->setPlanifiedActualCycle($payPalOrder->getPlanifiedActualCycle() + 1); + $payPalOrderEvent = new PayPalOrderEvent($payPalOrder); + $eventDispatcher->dispatch($payPalOrderEvent, PayPalEvents::PAYPAL_ORDER_UPDATE); + } + + return $params; + } + + /** + * @param array $data + * @param int $deep + * @return string + */ + protected function printRecursiveData($data = [], $deep = 0) + { + $formatedString = ''; + foreach ($data as $key => $value) { + + for ($i = 0; $i <= $deep; $i++) { + $formatedString .= '    '; + } + + if (is_array($value)) { + $formatedString .= '' . $key . ' : 
' . $this->printRecursiveData($value, $deep + 1); + } else { + $formatedString .= '' . $key . ' : ' . $value . '
'; + } + + } + + return $formatedString; + } +} diff --git a/domokits/local/modules/PayPal/Event/PayPalCartEvent.php b/domokits/local/modules/PayPal/Event/PayPalCartEvent.php new file mode 100644 index 0000000..432fbba --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalCartEvent.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + +use PayPal\Model\PaypalCart; +use Thelia\Core\Event\ActionEvent; + +/** + * Class PayPalCartEvent + * @package PayPal\Event + */ +class PayPalCartEvent extends ActionEvent +{ + /** @var PaypalCart */ + protected $payPalCart; + + /** + * PayPalCartEvent constructor. + * @param PaypalCart $payPalCart + */ + public function __construct(PaypalCart $payPalCart) + { + $this->payPalCart = $payPalCart; + } + + /** + * @return PaypalCart + */ + public function getPayPalCart() + { + return $this->payPalCart; + } + + /** + * @param PaypalCart $payPalCart + * + * @return $this + */ + public function setPayPalCart($payPalCart) + { + $this->payPalCart = $payPalCart; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Event/PayPalCustomerEvent.php b/domokits/local/modules/PayPal/Event/PayPalCustomerEvent.php new file mode 100644 index 0000000..419afe6 --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalCustomerEvent.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + +use PayPal\Model\PaypalCustomer; +use Thelia\Core\Event\ActionEvent; + +/** + * Class PayPalCustomerEvent + * @package PayPal\Event + */ +class PayPalCustomerEvent extends ActionEvent +{ + /** @var PaypalCustomer */ + protected $payPalCustomer; + + /** + * PayPalCustomerEvent constructor. + * @param PaypalCustomer $payPalCustomer + */ + public function __construct(PaypalCustomer $payPalCustomer) + { + $this->payPalCustomer = $payPalCustomer; + } + + /** + * @return PaypalCustomer + */ + public function getPayPalCustomer() + { + return $this->payPalCustomer; + } + + /** + * @param PaypalCustomer $payPalCustomer + * + * @return $this + */ + public function setPayPalCustomer($payPalCustomer) + { + $this->payPalCustomer = $payPalCustomer; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Event/PayPalEvents.php b/domokits/local/modules/PayPal/Event/PayPalEvents.php new file mode 100644 index 0000000..16a5e5a --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalEvents.php @@ -0,0 +1,57 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + + +/** + * Class PayPalEvents + * @package PayPal\Event + */ +class PayPalEvents +{ + const PAYPAL_ORDER_CREATE = 'action.paypal.order.create'; + const PAYPAL_ORDER_UPDATE = 'action.paypal.order.update'; + const PAYPAL_ORDER_DELETE = 'action.paypal.order.delete'; + const PAYPAL_RECURSIVE_PAYMENT_CREATE = 'action.paypal.recursive.payment.create'; + + const PAYPAL_AGREEMENT_CREATE = 'action.paypal.agreement.create'; + const PAYPAL_AGREEMENT_UPDATE = 'action.paypal.agreement.update'; + const PAYPAL_AGREEMENT_DELETE = 'action.paypal.agreement.delete'; + + const PAYPAL_PLAN_CREATE = 'action.paypal.plan.create'; + const PAYPAL_PLAN_UPDATE = 'action.paypal.plan.update'; + const PAYPAL_PLAN_DELETE = 'action.paypal.plan.delete'; + + const PAYPAL_CUSTOMER_CREATE = 'action.paypal.customer.create'; + const PAYPAL_CUSTOMER_UPDATE = 'action.paypal.customer.update'; + const PAYPAL_CUSTOMER_DELETE = 'action.paypal.customer.delete'; + + const PAYPAL_CART_CREATE = 'action.paypal.cart.create'; + const PAYPAL_CART_UPDATE = 'action.paypal.cart.update'; + const PAYPAL_CART_DELETE = 'action.paypal.cart.delete'; + + const PAYPAL_PLANIFIED_PAYMENT_CREATE = 'action.paypal.planified.payment.create'; + const PAYPAL_PLANIFIED_PAYMENT_UPDATE = 'action.paypal.planified.payment.update'; + const PAYPAL_PLANIFIED_PAYMENT_DELETE = 'action.paypal.planified.payment.delete'; +} diff --git a/domokits/local/modules/PayPal/Event/PayPalOrderEvent.php b/domokits/local/modules/PayPal/Event/PayPalOrderEvent.php new file mode 100644 index 0000000..2193bb3 --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalOrderEvent.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + +use PayPal\Model\PaypalOrder; +use Thelia\Core\Event\ActionEvent; + +/** + * Class PayPalOrderEvent + * @package PayPal\Event + */ +class PayPalOrderEvent extends ActionEvent +{ + /** @var PaypalOrder */ + protected $payPalOrder; + + /** + * PayPalOrderEvent constructor. + * @param PaypalOrder $payPalOrder + */ + public function __construct(PaypalOrder $payPalOrder) + { + $this->payPalOrder = $payPalOrder; + } + + /** + * @return PaypalOrder + */ + public function getPayPalOrder() + { + return $this->payPalOrder; + } + + /** + * @param PaypalOrder $payPalOrder + * + * @return $this + */ + public function setPayPalOrder($payPalOrder) + { + $this->payPalOrder = $payPalOrder; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Event/PayPalPlanEvent.php b/domokits/local/modules/PayPal/Event/PayPalPlanEvent.php new file mode 100644 index 0000000..b1ff2d4 --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalPlanEvent.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + +use PayPal\Model\PaypalPlan; +use Thelia\Core\Event\ActionEvent; + +/** + * Class PayPalPlanEvent + * @package PayPal\Event + */ +class PayPalPlanEvent extends ActionEvent +{ + /** @var PaypalPlan */ + protected $payPalPlan; + + /** + * PayPalPlanEvent constructor. + * @param PaypalPlan $payPalPlan + */ + public function __construct(PaypalPlan $payPalPlan) + { + $this->payPalPlan = $payPalPlan; + } + + /** + * @return PaypalPlan + */ + public function getPayPalPlan() + { + return $this->payPalPlan; + } + + /** + * @param PaypalPlan $payPalPlan + * + * @return $this + */ + public function setPayPalPlan($payPalPlan) + { + $this->payPalPlan = $payPalPlan; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Event/PayPalPlanifiedPaymentEvent.php b/domokits/local/modules/PayPal/Event/PayPalPlanifiedPaymentEvent.php new file mode 100644 index 0000000..2e7988a --- /dev/null +++ b/domokits/local/modules/PayPal/Event/PayPalPlanifiedPaymentEvent.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Event; + +use PayPal\Model\PaypalPlanifiedPayment; +use Thelia\Core\Event\ActionEvent; + +/** + * Class PayPalPlanifiedPaymentEvent + * @package PayPal\Event + */ +class PayPalPlanifiedPaymentEvent extends ActionEvent +{ + /** @var PaypalPlanifiedPayment */ + protected $payPalPlanifiedPayment; + + /** + * PayPalPlanifiedPaymentEvent constructor. + * @param PaypalPlanifiedPayment $payPalPlanifiedPayment + */ + public function __construct(PaypalPlanifiedPayment $payPalPlanifiedPayment) + { + $this->payPalPlanifiedPayment = $payPalPlanifiedPayment; + } + + /** + * @return PaypalPlanifiedPayment + */ + public function getPayPalPlanifiedPayment() + { + return $this->payPalPlanifiedPayment; + } + + /** + * @param PaypalPlanifiedPayment $payPalPlanifiedPayment + * + * @return $this + */ + public function setPayPalPlanifiedPayment($payPalPlanifiedPayment) + { + $this->payPalPlanifiedPayment = $payPalPlanifiedPayment; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/Form/TheliaOrderPaymentForm.php b/domokits/local/modules/PayPal/EventListeners/Form/TheliaOrderPaymentForm.php new file mode 100644 index 0000000..84627b8 --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/Form/TheliaOrderPaymentForm.php @@ -0,0 +1,172 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners\Form; + +use PayPal\Form\PayPalFormFields; +use PayPal\Form\Type\PayPalCreditCardType; +use PayPal\Model\PaypalPlanifiedPayment; +use PayPal\Model\PaypalPlanifiedPaymentQuery; +use PayPal\PayPal; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\TheliaFormEvent; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Core\Translation\Translator; +use Thelia\Model\Cart; +use Thelia\Model\Country; +use Thelia\Model\Order; + +/** + * Class TheliaOrderPaymentForm + * @package PayPal\EventListeners\Form + */ +class TheliaOrderPaymentForm implements EventSubscriberInterface +{ + /** @var RequestStack */ + protected $requestStack; + + /** @var EventDispatcherInterface */ + protected $dispatcher; + + /** + * TheliaOrderPaymentForm constructor. + * @param RequestStack $requestStack + */ + public function __construct(RequestStack $requestStack, EventDispatcherInterface $dispatcher) + { + $this->requestStack = $requestStack; + $this->dispatcher = $dispatcher; + } + + /** + * @param TheliaFormEvent $event + */ + public function afterBuildTheliaOrderPayment(TheliaFormEvent $event) + { + $event->getForm()->getFormBuilder() + ->add( + PayPalFormFields::FIELD_PAYPAL_METHOD, + ChoiceType::class, + [ + 'choices' => [ + PayPal::PAYPAL_METHOD_PAYPAL => PayPal::PAYPAL_METHOD_PAYPAL, + PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT => PayPal::PAYPAL_METHOD_EXPRESS_CHECKOUT, + PayPal::PAYPAL_METHOD_CREDIT_CARD => PayPal::PAYPAL_METHOD_CREDIT_CARD, + PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT => PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT + ], + 'label' => Translator::getInstance()->trans('PayPal method', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PAYPAL_METHOD], + 'required' => false, + ] + ) + ->add( + PayPalCreditCardType::TYPE_NAME, + PayPalCreditCardType::class, + [ + 'label_attr' => [ + 'for' => PayPalCreditCardType::TYPE_NAME + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT, + ChoiceType::class, + [ + 'choices' => $this->getAllowedPlanifiedPayments(), + 'choice_label' => function ($value, $key, $index) { + return $value->getTitle(); + }, + 'choice_value' => function ($value) { + if ($value !== null) { + return $value->getId(); + } + + return null; + }, + "required" => false, + 'empty_data' => null, + 'label' => Translator::getInstance()->trans('Frequency', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT], + ] + ) + ; + } + + /** + * @return array|mixed|\Propel\Runtime\Collection\ObjectCollection + */ + protected function getAllowedPlanifiedPayments() + { + /** @var Session $session */ + $session = $this->requestStack->getCurrentRequest()->getSession(); + + /** @var \Thelia\Model\Lang $lang */ + $lang = $session->getLang(); + + /** @var Cart $cart */ + $cart = $session->getSessionCart($this->dispatcher); + + /** @var Order $order */ + $order = $session->get('thelia.order'); + + $country = Country::getDefaultCountry(); + + $planifiedPayments = (new PaypalPlanifiedPaymentQuery())->joinWithI18n($lang->getLocale())->find(); + if (null !== $cart && null !== $order && null !== $country) { + $totalAmount = $cart->getTaxedAmount($country) + (float)$order->getPostage(); + + $restrictedPlanifiedAmounts = []; + /** @var PaypalPlanifiedPayment $planifiedPayment */ + foreach ($planifiedPayments as $planifiedPayment) { + + if ($planifiedPayment->getMinAmount() > 0 && $planifiedPayment->getMinAmount() > $totalAmount) { + continue; + } + + if ($planifiedPayment->getMaxAmount() > 0 && $planifiedPayment->getMaxAmount() < $totalAmount) { + continue; + } + + $restrictedPlanifiedAmounts[] = $planifiedPayment; + } + + $planifiedPayments = $restrictedPlanifiedAmounts; + } + + return $planifiedPayments; + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::FORM_AFTER_BUILD . '.thelia_order_payment' => ['afterBuildTheliaOrderPayment', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/OrderListener.php b/domokits/local/modules/PayPal/EventListeners/OrderListener.php new file mode 100644 index 0000000..c288f9c --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/OrderListener.php @@ -0,0 +1,273 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalCartEvent; +use PayPal\Event\PayPalEvents; +use PayPal\Form\PayPalFormFields; +use PayPal\Form\Type\PayPalCreditCardType; +use PayPal\PayPal; +use PayPal\Service\PayPalAgreementService; +use PayPal\Service\PayPalPaymentService; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Mailer\MailerFactory; + +/** + * Class OrderListener + * @package PayPal\EventListeners + */ +class OrderListener implements EventSubscriberInterface +{ + /** @var MailerFactory */ + protected $mailer; + + /** @var EventDispatcherInterface */ + protected $dispatcher; + + /** @var RequestStack */ + protected $requestStack; + + /** @var PayPalPaymentService */ + protected $payPalPaymentService; + + /** @var PayPalAgreementService */ + protected $payPalAgreementService; + + /** + * @param MailerFactory $mailer + * @param EventDispatcherInterface $dispatcher + * @param RequestStack $requestStack + * @param PayPalPaymentService $payPalPaymentService + * @param PayPalAgreementService $payPalAgreementService + */ + public function __construct(MailerFactory $mailer, EventDispatcherInterface $dispatcher, RequestStack $requestStack, PayPalPaymentService $payPalPaymentService, PayPalAgreementService $payPalAgreementService) + { + $this->dispatcher = $dispatcher; + $this->mailer = $mailer; + $this->requestStack = $requestStack; + $this->payPalPaymentService = $payPalPaymentService; + $this->payPalAgreementService = $payPalAgreementService; + } + + /** + * @param OrderEvent $event + */ + public function CancelPayPalTransaction(OrderEvent $event) + { + // @TODO : Inform PayPal that this payment is canceled ? + } + + /** + * @param OrderEvent $event + * + * @throws \Exception if the message cannot be loaded. + */ + public function sendConfirmationEmail(OrderEvent $event) + { + if (PayPal::getConfigValue('send_confirmation_message_only_if_paid')) { + // We send the order confirmation email only if the order is paid + $order = $event->getOrder(); + + if (! $order->isPaid() && $order->getPaymentModuleId() == Paypal::getModuleId()) { + $event->stopPropagation(); + } + } + } + + /** + * Checks if order payment module is paypal and if order new status is paid, send an email to the customer. + * + * @param OrderEvent $event + */ + public function updateStatus(OrderEvent $event) + { + $order = $event->getOrder(); + + if ($order->isPaid() && $order->getPaymentModuleId() === Paypal::getModuleId()) { + if (Paypal::getConfigValue('send_payment_confirmation_message')) { + $this->mailer->sendEmailToCustomer( + PayPal::CONFIRMATION_MESSAGE_NAME, + $order->getCustomer(), + [ + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef() + ] + ); + } + + // Send confirmation email if required. + if (Paypal::getConfigValue('send_confirmation_message_only_if_paid')) { + $this->dispatcher->dispatch($event, TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL); + } + } + } + + /** + * @param OrderEvent $event + * @throws \Exception + */ + public function checkPayPalMethod(OrderEvent $event) + { + //First be sure that there is no OLD CREDIT card saved in paypal_cart because of fatal error + $payPalCartEvent = new PayPalCartEvent($this->payPalPaymentService->getCurrentPayPalCart()); + $this->dispatcher->dispatch($payPalCartEvent, PayPalEvents::PAYPAL_CART_DELETE); + + $postedData = $this->requestStack->getCurrentRequest()->get('thelia_order_payment'); + + if (isset($postedData[PayPalFormFields::FIELD_PAYMENT_MODULE]) && PayPal::getModuleId() === $event->getOrder()->getPaymentModuleId()) { + $this->usePayPalMethod($postedData); + } + } + + /** + * @param OrderEvent $event + */ + public function recursivePayment(OrderEvent $event) + { + $this->payPalAgreementService->duplicateOrder($event->getOrder()); + + if (PayPal::getConfigValue('send_recursive_message')) { + $this->mailer->sendEmailToCustomer( + PayPal::RECURSIVE_MESSAGE_NAME, + $event->getOrder()->getCustomer(), + [ + 'order_id' => $event->getOrder()->getId(), + 'order_ref' => $event->getOrder()->getRef() + ] + ); + } + } + + /** + * @param array $postedData + */ + protected function usePayPalMethod($postedData = []) + { + if (isset($postedData[PayPalFormFields::FIELD_PAYPAL_METHOD])) { + $payPalMethod = $postedData[PayPalFormFields::FIELD_PAYPAL_METHOD]; + + switch ($payPalMethod) { + case PayPal::PAYPAL_METHOD_CREDIT_CARD: + $this->usePayPalCreditCardMethod($postedData); + break; + + case PayPal::PAYPAL_METHOD_PLANIFIED_PAYMENT: + $this->usePayPalPlanifiedPaymentMethod($postedData); + break; + } + } + } + + /** + * @param array $postedData + * @throws \Exception + */ + protected function usePayPalCreditCardMethod($postedData = []) + { + if ($this->isValidPaidByPayPalCreditCard($postedData)) { + //save credit card in cart because we will need it in pay() method for payment module + + $creditCardId = $this->payPalPaymentService->getPayPalCreditCardId( + $postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE], + $postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER], + $postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH], + $postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR], + $postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV] + ); + + $payPalCart = $this->payPalPaymentService->getCurrentPayPalCart(); + $payPalCart->setCreditCardId($creditCardId); + $payPalCartEvent = new PayPalCartEvent($payPalCart); + $this->dispatcher->dispatch($payPalCartEvent, PayPalEvents::PAYPAL_CART_UPDATE); + } + } + + /** + * @param array $postedData + * @return bool + */ + protected function isValidPaidByPayPalCreditCard($postedData = []) + { + $isValid = false; + + if (isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_TYPE]) && + isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_NUMBER]) && + isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_MONTH]) && + isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_EXPIRE_YEAR]) && + isset($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV]) && $this->isNotBlank($postedData[PayPalCreditCardType::TYPE_NAME][PayPalFormFields::FIELD_CARD_CVV])) { + $isValid = true; + } + + return $isValid; + } + + /** + * @param array $postedData + */ + protected function usePayPalPlanifiedPaymentMethod($postedData = []) + { + if (isset($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT]) && + $this->isNotBlank($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT])) { + + $payPalCart = $this->payPalPaymentService->getCurrentPayPalCart(); + $payPalCart->setPlanifiedPaymentId($postedData[PayPalFormFields::FIELD_PAYPAL_PLANIFIED_PAYMENT]); + $payPalCartEvent = new PayPalCartEvent($payPalCart); + $this->dispatcher->dispatch($payPalCartEvent, PayPalEvents::PAYPAL_CART_UPDATE); + + } + } + + /** + * @param $value + * @return bool + */ + protected function isNotBlank($value) + { + if (false === $value || (empty($value) && '0' != $value)) { + return false; + } + + return true; + } + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_UPDATE_STATUS => [ + ['CancelPayPalTransaction', 128], + ['updateStatus', 128], + ], + TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => ['sendConfirmationEmail', 129], + TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => ['sendConfirmationEmail', 129], + TheliaEvents::ORDER_SET_PAYMENT_MODULE => ['checkPayPalMethod', 120], + PayPalEvents::PAYPAL_RECURSIVE_PAYMENT_CREATE => ['recursivePayment', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/PayPalCartListener.php b/domokits/local/modules/PayPal/EventListeners/PayPalCartListener.php new file mode 100644 index 0000000..69a0430 --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/PayPalCartListener.php @@ -0,0 +1,67 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalCartEvent; +use PayPal\Event\PayPalEvents; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Class PayPalCartListener + * @package PayPal\EventListeners + */ +class PayPalCartListener implements EventSubscriberInterface +{ + /** + * @param PayPalCartEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createOrUpdate(PayPalCartEvent $event) + { + $event->getPayPalCart()->save(); + } + + /** + * @param PayPalCartEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function delete(PayPalCartEvent $event) + { + $event->getPayPalCart()->delete(); + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + PayPalEvents::PAYPAL_CART_CREATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_CART_UPDATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_CART_DELETE => ['delete', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/PayPalCustomerListener.php b/domokits/local/modules/PayPal/EventListeners/PayPalCustomerListener.php new file mode 100644 index 0000000..58cc1f7 --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/PayPalCustomerListener.php @@ -0,0 +1,87 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalCustomerEvent; +use PayPal\Event\PayPalEvents; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; + +/** + * Class PayPalCustomerListener + * @package PayPal\EventListeners + */ +class PayPalCustomerListener implements EventSubscriberInterface +{ + /** @var RequestStack */ + protected $requestStack; + + /** @var EventDispatcher */ + protected $dispatcher; + + /** + * PayPalCustomerListener constructor. + * @param RequestStack $requestStack + * @param EventDispatcher $dispatcher + */ + public function __construct(RequestStack $requestStack, EventDispatcherInterface $dispatcher) + { + $this->requestStack = $requestStack; + $this->dispatcher = $dispatcher; + } + + /** + * @param PayPalCustomerEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createOrUpdate(PayPalCustomerEvent $event) + { + $event->getPayPalCustomer()->save(); + } + + /** + * @param PayPalCustomerEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function delete(PayPalCustomerEvent $event) + { + $event->getPayPalCustomer()->delete(); + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + PayPalEvents::PAYPAL_CUSTOMER_CREATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_CUSTOMER_UPDATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_CUSTOMER_DELETE => ['delete', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/PayPalOrderListener.php b/domokits/local/modules/PayPal/EventListeners/PayPalOrderListener.php new file mode 100644 index 0000000..b8b021f --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/PayPalOrderListener.php @@ -0,0 +1,68 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalOrderEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + + +/** + * Class PayPalOrderListener + * @package PayPal\EventListeners + */ +class PayPalOrderListener implements EventSubscriberInterface +{ + /** + * @param PayPalOrderEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createOrUpdate(PayPalOrderEvent $event) + { + $event->getPayPalOrder()->save(); + } + + /** + * @param PayPalOrderEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function delete(PayPalOrderEvent $event) + { + $event->getPayPalOrder()->delete(); + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + PayPalEvents::PAYPAL_ORDER_CREATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_ORDER_UPDATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_ORDER_DELETE => ['delete', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/PayPalPlanListener.php b/domokits/local/modules/PayPal/EventListeners/PayPalPlanListener.php new file mode 100644 index 0000000..be9f093 --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/PayPalPlanListener.php @@ -0,0 +1,63 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalPlanEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class PayPalPlanListener implements EventSubscriberInterface +{ + /** + * @param PayPalPlanEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createOrUpdate(PayPalPlanEvent $event) + { + $event->getPayPalPlan()->save(); + } + + /** + * @param PayPalPlanEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function delete(PayPalPlanEvent $event) + { + $event->getPayPalPlan()->delete(); + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + PayPalEvents::PAYPAL_PLAN_CREATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_PLAN_UPDATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_PLAN_DELETE => ['delete', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/EventListeners/PayPalPlanifiedPaymentListener.php b/domokits/local/modules/PayPal/EventListeners/PayPalPlanifiedPaymentListener.php new file mode 100644 index 0000000..9118a5c --- /dev/null +++ b/domokits/local/modules/PayPal/EventListeners/PayPalPlanifiedPaymentListener.php @@ -0,0 +1,63 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\EventListeners; + +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalPlanifiedPaymentEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class PayPalPlanifiedPaymentListener implements EventSubscriberInterface +{ + /** + * @param PayPalPlanifiedPaymentEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function createOrUpdate(PayPalPlanifiedPaymentEvent $event) + { + $event->getPayPalPlanifiedPayment()->save(); + } + + /** + * @param PayPalPlanifiedPaymentEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function delete(PayPalPlanifiedPaymentEvent $event) + { + $event->getPayPalPlanifiedPayment()->delete(); + } + + /** + * @return array The event names to listen to + */ + public static function getSubscribedEvents() + { + return [ + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_CREATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_UPDATE => ['createOrUpdate', 128], + PayPalEvents::PAYPAL_PLANIFIED_PAYMENT_DELETE => ['delete', 128] + ]; + } +} diff --git a/domokits/local/modules/PayPal/Form/ConfigurationForm.php b/domokits/local/modules/PayPal/Form/ConfigurationForm.php new file mode 100644 index 0000000..a1cf3be --- /dev/null +++ b/domokits/local/modules/PayPal/Form/ConfigurationForm.php @@ -0,0 +1,333 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Form; + +use PayPal\PayPal; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Form\BaseForm; + +/** + * Class ConfigurePaypal + * @package Paypal\Form + * @author Thelia + */ +class ConfigurationForm extends BaseForm +{ + const FORM_NAME = 'paypal_form_configure'; + + protected function buildForm() + { + $this->formBuilder + ->add( + 'login', + TextType::class, + [ + 'constraints' => [ new NotBlank() ], + 'label' => $this->translator->trans('login', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('Your Paypal login', [], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'password', + TextType::class, + [ + 'constraints' => [ new NotBlank() ], + 'label' => $this->translator->trans('password', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('Your Paypal password', [], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'merchant_id', + TextType::class, + [ + 'label' => $this->translator->trans('Merchant ID', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('The Paypal identity merchant account', ['%url' => 'https://www.paypal.com/businessprofile/settings/'], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'sandbox', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Activate sandbox mode', [], PayPal::DOMAIN_NAME), + ] + ) + ->add( + 'sandbox_login', + TextType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('login', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('Your Paypal sandbox login', [], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'sandbox_password', + TextType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('password', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('Your Paypal sandbox password', [], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'sandbox_merchant_id', + TextType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Merchant ID', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans('The Paypal identity merchant account', ['%url' => 'https://www.paypal.com/businessprofile/settings/'], PayPal::DOMAIN_NAME) + ] + ] + ) + ->add( + 'allowed_ip_list', + TextareaType::class, + [ + 'required' => false, + 'label' => $this->translator->trans('Allowed IPs in test mode', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line', + [ '%ip' => $this->getRequest()->getClientIp() ], + PayPal::DOMAIN_NAME + ) + ], + 'attr' => [ + 'rows' => 3 + ] + ] + ) + ->add( + 'minimum_amount', + TextType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(array('value' => 0)) + ], + 'required' => false, + 'label' => $this->translator->trans('Minimum order total', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'maximum_amount', + TextType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(array('value' => 0)) + ], + 'required' => false, + 'label' => $this->translator->trans('Maximum order total', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'cart_item_count', + TextType::class, + [ + 'constraints' => [ + new NotBlank(), + new GreaterThanOrEqual(array('value' => 0)) + ], + 'required' => false, + 'label' => $this->translator->trans('Maximum items in cart', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'Maximum number of items in the customer cart for which this payment method is available.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'method_paypal', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Activate payment with PayPal account', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, the order can be paid by PayPal account.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'method_paypal_with_in_context', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Use InContext mode for classic PayPal payment', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, a PayPal popup will be used to execute the payment.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'method_express_checkout', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Activate Express Checkout payment with PayPal', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, the order can be paid directly from cart.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'method_credit_card', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Activate payment with credit card', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, the order can be paid by credit card.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'method_planified_payment', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Activate payment with planified payment', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, the order can be paid by planified payement.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'send_confirmation_message_only_if_paid', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Send order confirmation on payment success', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'send_payment_confirmation_message', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Send a payment confirmation e-mail', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, a payment confirmation e-mail is sent to the customer.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ->add( + 'send_recursive_message', + CheckboxType::class, + [ + 'value' => 1, + 'required' => false, + 'label' => $this->translator->trans('Send a recursive payment confirmation e-mail', [], PayPal::DOMAIN_NAME), + 'label_attr' => [ + 'help' => $this->translator->trans( + 'If checked, a payment confirmation e-mail is sent to the customer after each PayPal transaction.', + [], + PayPal::DOMAIN_NAME + ) + ] + ] + ) + ; + } + + /** + * @return string the name of your form. This name must be unique + */ + public static function getName() + { + return self::FORM_NAME; + } +} diff --git a/domokits/local/modules/PayPal/Form/PayPalFormFields.php b/domokits/local/modules/PayPal/Form/PayPalFormFields.php new file mode 100644 index 0000000..6af046e --- /dev/null +++ b/domokits/local/modules/PayPal/Form/PayPalFormFields.php @@ -0,0 +1,56 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Form; + +/** + * Class PayPalFormFields + * @package PayPal\Form + */ +class PayPalFormFields +{ + const FIELD_PAYMENT_MODULE = 'payment-module'; + + // \Thelia\Form\OrderPayment + const FIELD_PAYPAL_METHOD = 'paypal_method'; + const FIELD_PAYPAL_PLANIFIED_PAYMENT = 'paypal_planified_payment'; + + // \Form\Type\PayPalCreditCardType + const FIELD_CARD_TYPE = 'card_type'; + const FIELD_CARD_NUMBER = 'card_number'; + const FIELD_CARD_EXPIRE_MONTH = 'card_expire_month'; + const FIELD_CARD_EXPIRE_YEAR = 'card_expire_year'; + const FIELD_CARD_CVV = 'card_cvv'; + + // \Form\PayPalPlanifiedPaymentForm + const FIELD_PP_ID = 'id'; + const FIELD_PP_LOCALE = 'locale'; + const FIELD_PP_TITLE = 'title'; + const FIELD_PP_DESCRIPTION = 'description'; + const FIELD_PP_FREQUENCY = 'frequency'; + const FIELD_PP_FREQUENCY_INTERVAL = 'frequency_interval'; + const FIELD_PP_CYCLE = 'cycle'; + const FIELD_PP_MIN_AMOUNT = 'min_amount'; + const FIELD_PP_MAX_AMOUNT = 'max_amount'; + const FIELD_PP_POSITION = 'position'; +} diff --git a/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentCreateForm.php b/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentCreateForm.php new file mode 100644 index 0000000..2570bb0 --- /dev/null +++ b/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentCreateForm.php @@ -0,0 +1,194 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Form; + +use PayPal\PayPal; +use PayPal\Service\PayPalAgreementService; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Validator\Constraints\GreaterThan; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; +use Thelia\Form\BaseForm; + +class PayPalPlanifiedPaymentCreateForm extends BaseForm +{ + const FORM_NAME = 'paypal_planified_payment_create_form'; + + /** + * @return null + */ + protected function buildForm() + { + /** @var \Thelia\Model\Lang $lang */ + $lang = $this->getRequest()->getSession()->get('thelia.current.lang'); + + $this->formBuilder + ->add( + PayPalFormFields::FIELD_PP_LOCALE, + HiddenType::class, + [ + 'constraints' => [ + new NotBlank() + ], + 'required' => true, + 'data' => $lang->getLocale(), + 'label' => $this->trans('The locale of the planified payment'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_LOCALE] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_TITLE, + TextType::class, + [ + 'constraints' => [ + new NotBlank() + ], + 'required' => true, + 'label' => $this->trans('The title of the planified payment'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_TITLE] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_DESCRIPTION, + TextType::class, + [ + 'required' => false, + 'label' => $this->trans('The description of the planified payment'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_DESCRIPTION] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL, + IntegerType::class, + [ + 'label' => $this->trans('Frequency interval'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_FREQUENCY_INTERVAL], + 'required' => true, + 'constraints' => [ + new NotBlank(), + new GreaterThan(['value' => 0]) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_FREQUENCY, + ChoiceType::class, + [ + 'choices' => array_flip(PayPalAgreementService::getAllowedPaymentFrequency()), + 'label' => $this->trans('Frequency'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_FREQUENCY], + 'required' => true, + 'constraints' => [ + new NotBlank() + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_CYCLE, + IntegerType::class, + [ + 'label' => $this->trans('Cycle'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_CYCLE], + 'required' => true, + 'constraints' => [ + new NotBlank(), + new GreaterThan(['value' => 0]) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_MIN_AMOUNT, + NumberType::class, + [ + 'label' => $this->trans('Min amount'), + 'label_attr' => [ + 'for' => PayPalFormFields::FIELD_PP_MIN_AMOUNT, + 'help' => $this->trans("Let value to 0 if you don't want a minimum") + ], + 'required' => false, + 'constraints' => [ + new GreaterThanOrEqual(['value' => 0]) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_MAX_AMOUNT, + NumberType::class, + [ + 'label' => $this->trans('Max amount'), + 'label_attr' => [ + 'for' => PayPalFormFields::FIELD_PP_MAX_AMOUNT, + 'help' => $this->trans("Let value to 0 if you don't want a maximum") + ], + 'required' => false, + 'constraints' => [ + new GreaterThanOrEqual(['value' => 0]) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_PP_POSITION, + IntegerType::class, + [ + 'label' => $this->trans('Position'), + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_POSITION], + 'required' => false + ] + ) + ; + } + + /** + * @return string the name of your form. This name must be unique + */ + public static function getName() + { + return self::FORM_NAME; + } + + /** + * Translates the given message. + * + * @param string $id The message id (may also be an object that can be cast to string) + * @param array $parameters An array of parameters for the message + * @param string|null $domain The domain for the message or null to use the default + * + * @throws \InvalidArgumentException If the locale contains invalid characters + * + * @return string The translated string + */ + protected function trans($id, array $parameters = [], $domain = null) + { + return Translator::getInstance()->trans( + $id, + $parameters, + $domain === null ? PayPal::DOMAIN_NAME : $domain + ); + } +} diff --git a/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentUpdateForm.php b/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentUpdateForm.php new file mode 100644 index 0000000..d0ef1b7 --- /dev/null +++ b/domokits/local/modules/PayPal/Form/PayPalPlanifiedPaymentUpdateForm.php @@ -0,0 +1,56 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Form; + +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Validator\Constraints\NotBlank; + +class PayPalPlanifiedPaymentUpdateForm extends PayPalPlanifiedPaymentCreateForm +{ + const FORM_NAME = 'paypal_planified_payment_update_form'; + + protected function buildForm() + { + parent::buildForm(); + + $this->formBuilder + ->add( + PayPalFormFields::FIELD_PP_ID, + HiddenType::class, + [ + 'required' => true, + 'label_attr' => ['for' => PayPalFormFields::FIELD_PP_ID], + 'constraints' => [ + new NotBlank() + ] + ] + ) + ; + } + + public static function getName() + { + return self::FORM_NAME; + } +} diff --git a/domokits/local/modules/PayPal/Form/Type/PayPalCreditCardType.php b/domokits/local/modules/PayPal/Form/Type/PayPalCreditCardType.php new file mode 100644 index 0000000..4a37abf --- /dev/null +++ b/domokits/local/modules/PayPal/Form/Type/PayPalCreditCardType.php @@ -0,0 +1,247 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Form\Type; + +use PayPal\Form\PayPalFormFields; +use PayPal\PayPal; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Thelia\Core\Form\Type\AbstractTheliaType; +use Thelia\Core\Translation\Translator; + + +/** + * Class PayPalCreditCardType + * @package PayPal\Form\Type + */ +class PayPalCreditCardType extends AbstractTheliaType +{ + const TYPE_NAME = 'paypal_credit_card_type'; + + /** + * @param FormBuilderInterface $builder + * @param array $options + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add( + PayPalFormFields::FIELD_CARD_TYPE, + ChoiceType::class, + [ + 'choices' => $this->getTypes(), + 'label' => Translator::getInstance()->trans('Card type', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_TYPE], + 'required' => false, + 'constraints' => [ + new Callback( + [$this, 'verifyCardType'] + ) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_CARD_NUMBER, + TextType::class, + [ + 'label' => Translator::getInstance()->trans('Card number', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_NUMBER], + 'required' => false, + 'constraints' => [ + new Callback( + [$this, 'verifyCardNumber'] + ) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_CARD_EXPIRE_MONTH, + ChoiceType::class, + [ + 'choices' => $this->getMonths(), + 'label' => Translator::getInstance()->trans('Expire month', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_EXPIRE_MONTH], + 'required' => false, + 'constraints' => [ + new Callback( + [$this, 'verifyCardExpireMonth'] + ) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_CARD_EXPIRE_YEAR, + ChoiceType::class, + [ + 'choices' => $this->getYears(), + 'label' => Translator::getInstance()->trans('Expire year', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_EXPIRE_YEAR], + 'required' => false, + 'constraints' => [ + new Callback( + [$this, 'verifyCardExpireYear'] + ) + ] + ] + ) + ->add( + PayPalFormFields::FIELD_CARD_CVV, + TextType::class, + [ + 'label' => Translator::getInstance()->trans('CVV', [], PayPal::DOMAIN_NAME), + 'label_attr' => ['for' => PayPalFormFields::FIELD_CARD_CVV], + 'required' => false, + 'constraints' => [ + new Callback( + [$this, 'verifyCardCVV'] + ) + ] + ] + ) + ; + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + public function verifyCardType($value, ExecutionContextInterface $context) + { + $this->checkNotBlank($value, $context); + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + public function verifyCardNumber($value, ExecutionContextInterface $context) + { + $this->checkNotBlank($value, $context); + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + public function verifyCardExpireMonth($value, ExecutionContextInterface $context) + { + $this->checkNotBlank($value, $context); + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + public function verifyCardExpireYear($value, ExecutionContextInterface $context) + { + $this->checkNotBlank($value, $context); + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + public function verifyCardCVV($value, ExecutionContextInterface $context) + { + $this->checkNotBlank($value, $context); + } + + /** + * @param $value + * @param ExecutionContextInterface $context + */ + protected function checkNotBlank($value, ExecutionContextInterface $context) + { + $data = $context->getRoot()->getData(); + if (isset($data[PayPalFormFields::FIELD_PAYMENT_MODULE]) && PayPal::getModuleId() === $data[PayPalFormFields::FIELD_PAYMENT_MODULE]) { + if (isset($data[PayPalFormFields::FIELD_PAYPAL_METHOD]) && PayPal::PAYPAL_METHOD_CREDIT_CARD === $data[PayPalFormFields::FIELD_PAYPAL_METHOD]) { + if (false === $value || (empty($value) && '0' != $value)) { + $context->addViolation( + Translator::getInstance()->trans('This value should not be blank', [], PayPal::DOMAIN_NAME) + ); + } + } + } + } + + /** + * @inheritDoc + */ + public static function getName() + { + return self::TYPE_NAME; + } + + /** + * @return array + */ + protected function getTypes() + { + return [ + 'Visa' => PayPal::CREDIT_CARD_TYPE_VISA, + 'MasterCard' => PayPal::CREDIT_CARD_TYPE_MASTERCARD, + 'Discover' => PayPal::CREDIT_CARD_TYPE_DISCOVER, + 'Amex' => PayPal::CREDIT_CARD_TYPE_AMEX + ]; + } + + /** + * @return array + */ + protected function getMonths() + { + return [ + '01' => 1, + '02' => 2, + '03' => 3, + '04' => 4, + '05' => 5, + '06' => 6, + '07' => 7, + '08' => 8, + '09' => 9, + '10' => 10, + '11' => 11, + '12' => 12 + ]; + } + + /** + * @return array + */ + protected function getYears() + { + $actualYear = date("Y"); + + $years = []; + $years[(int)$actualYear] = $actualYear; + for ($i = 1; $i <= 10; $i++) { + $years[$actualYear + $i] = (int)($actualYear + $i); + } + return $years; + } +} diff --git a/domokits/local/modules/PayPal/Hook/BackHookManager.php b/domokits/local/modules/PayPal/Hook/BackHookManager.php new file mode 100644 index 0000000..4c477e7 --- /dev/null +++ b/domokits/local/modules/PayPal/Hook/BackHookManager.php @@ -0,0 +1,95 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Hook; + +use PayPal\Model\PaypalOrderQuery; +use PayPal\PayPal; +use PayPal\Service\Base\PayPalBaseService; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Model\ModuleConfig; +use Thelia\Model\ModuleConfigQuery; + + +/** + * Class BackHookManager + * @package PayPal\Hook + */ +class BackHookManager extends BaseHook +{ + /** + * @param HookRenderEvent $event + */ + public function onModuleConfigure(HookRenderEvent $event) + { + $vars = []; + if (null !== $moduleConfigs = ModuleConfigQuery::create()->findByModuleId(PayPal::getModuleId())) { + /** @var ModuleConfig $moduleConfig */ + foreach ($moduleConfigs as $moduleConfig) { + $vars[ $moduleConfig->getName() ] = $moduleConfig->getValue(); + } + } + + $vars['paypal_appid'] = PayPalBaseService::getLogin(); + $vars['paypal_authend'] = PayPalBaseService::getMode(); + + $event->add( + $this->render('paypal/module-configuration.html', $vars) + ); + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderEditPaymentModuleBottom(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + + if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($event->getArgument('order_id'))) { + $event->add( + $this->render( + 'paypal/payment-information.html', + $templateData + ) + ); + } + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderEditJs(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + + if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($event->getArgument('order_id'))) { + $event->add( + $this->render( + 'paypal/order-edit-js.html', + $templateData + ) + ); + } + } +} diff --git a/domokits/local/modules/PayPal/Hook/FrontHookManager.php b/domokits/local/modules/PayPal/Hook/FrontHookManager.php new file mode 100644 index 0000000..421a41b --- /dev/null +++ b/domokits/local/modules/PayPal/Hook/FrontHookManager.php @@ -0,0 +1,208 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Hook; + +use PayPal\Model\PaypalCartQuery; +use PayPal\PayPal; +use PayPal\Service\Base\PayPalBaseService; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Core\HttpFoundation\Session\Session; + + +/** + * Class FrontHookManager + * @package PayPal\Hook + */ +class FrontHookManager extends BaseHook +{ + /** @var RequestStack */ + protected $requestStack; + + /** @var ContainerInterface */ + protected $container; + + /** + * FrontHookManager constructor. + * @param RequestStack $requestStack + * @param ContainerInterface $container + */ + public function __construct(RequestStack $requestStack, ContainerInterface $container) + { + $this->requestStack = $requestStack; + $this->container = $container; + } + + /** + * @param HookRenderEvent $event + */ + public function onLoginMainBottom(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + $templateData['paypal_appid'] = PayPalBaseService::getLogin(); + $templateData['paypal_authend'] = PayPalBaseService::getMode(); + + $event->add( + $this->render( + 'paypal/login-bottom.html', + $templateData + ) + ); + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderInvoicePaymentExtra(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + $templateData['method_paypal_with_in_context'] = PayPal::getConfigValue('method_paypal_with_in_context'); + $event->add( + $this->render( + 'paypal/order-invoice-payment-extra.html', + $templateData + ) + ); + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderInvoiceBottom(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + $templateData['paypal_mode'] = PayPalBaseService::getMode(); + $templateData['paypal_merchantid'] = PayPalBaseService::getMerchantId(); + + $event->add( + $this->render( + 'paypal/order-invoice-bottom.html', + $templateData + ) + ); + } + + public function onOrderInvoiceJavascriptInitialization(HookRenderEvent $event) + { + $render = $this->render( + 'paypal/order-invoice-js.html', + [ + 'module_id' => PayPal::getModuleId(), + ] + ); + + $event->add($render); + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderPlacedAdditionalPaymentInfo(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + $event->add( + $this->render( + 'paypal/order-placed-additional-payment-info.html', + $templateData + ) + ); + } + + /** + * @param HookRenderEvent $event + */ + public function onCartBottom(HookRenderEvent $event) + { + $payPal = new PayPal(); + $payPal->setContainer($this->container); + + if (PayPal::getConfigValue('method_express_checkout') == 1 && $payPal->isValidPayment()) { + $templateData = $event->getArguments(); + $templateData['paypal_mode'] = PayPalBaseService::getMode(); + $templateData['paypal_merchantid'] = PayPalBaseService::getMerchantId(); + $event->add( + $this->render( + 'paypal/cart-bottom.html', + $templateData + ) + ); + } + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderDeliveryFormBottom(HookRenderEvent $event) + { + if ($this->isValidExpressCheckout()) { + $templateData = $event->getArguments(); + $event->add( + $this->render( + 'paypal/order-delivery-bottom.html', + $templateData + ) + ); + } + } + + /** + * @param HookRenderEvent $event + */ + public function onOrderAfterJavascriptInclude(HookRenderEvent $event) + { + if ($this->isValidExpressCheckout()) { + $templateData = $event->getArguments(); + $event->add( + $this->render( + 'paypal/order-delivery-bottom-js.html', + $templateData + ) + ); + } + } + + protected function isValidExpressCheckout() + { + $isValid = false; + + /** @var Session $session */ + $session = $this->requestStack->getCurrentRequest()->getSession(); + $cart = $session->getSessionCart($this->dispatcher); + + $payPal = new PayPal(); + $payPal->setContainer($this->container); + + if (PayPal::getConfigValue('method_express_checkout') == 1 && $payPal->isValidPayment()) { + if (null !== $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) { + if ($payPalCart->getExpressPaymentId() && $payPalCart->getExpressPayerId() && $payPalCart->getExpressToken()) { + $isValid = true; + } + } + } + + return $isValid; + } +} diff --git a/domokits/local/modules/PayPal/Hook/PdfHookManager.php b/domokits/local/modules/PayPal/Hook/PdfHookManager.php new file mode 100644 index 0000000..18f9b35 --- /dev/null +++ b/domokits/local/modules/PayPal/Hook/PdfHookManager.php @@ -0,0 +1,45 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +class PdfHookManager extends BaseHook +{ + /** + * @param HookRenderEvent $event + */ + public function onAfterPaymentModule(HookRenderEvent $event) + { + $templateData = $event->getArguments(); + + $event->add( + $this->render( + 'paypal/after-payment-module.html', + $templateData + ) + ); + } +} diff --git a/domokits/local/modules/PayPal/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/PayPal/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..62e1d8f --- /dev/null +++ b/domokits/local/modules/PayPal/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,92 @@ + 'Accept payments', + 'Account Information' => 'Account Information', + 'Add Webhook' => 'Cliquer sur Add Webhook', + 'Add a planified payment' => 'Ajouter un paiement planifié', + 'Address Information' => 'Address Information', + 'Allow the customers who haven\'t yet confirmed their email address with PayPal, to log in to your app' => 'Allow the customers who haven\'t yet confirmed their email address with PayPal, to log in to your app', + 'And configure it like the SandBox' => 'Et remplissez le formulaire comme pour la SandBox', + 'Automatic PayPal logs' => 'Logs automatiques de PayPal', + 'Billing agreements' => 'Billing agreements', + 'Check' => 'Cocher', + 'Click on Create App' => ' Cliquer sur Create App ', + 'Click on the Live Button' => 'Cliquer sur le button "Live"', + 'Configuration' => 'Configuration', + 'Copy & Paste the Client ID in the form below' => 'Copier & Coller le Client ID dans le formulaire ci-dessous', + 'Copy & Paste the Client SECRET in the form below' => 'Copier & Coller le Client SECRET dans le formulaire ci-dessous', + 'Create REST API apps here' => 'Créer une REST API apps ici ', + 'Create a new planified payment' => 'Créer un nouveau paiement récurrent', + 'Create this planified payment' => 'Créer ce paiement récurrent', + 'critical_100' => 'DEBUG', + 'critical_200' => 'INFO', + 'critical_250' => 'NOTICE', + 'critical_300' => 'WARNING', + 'critical_400' => 'ERROR', + 'critical_500' => 'CRITICAL', + 'critical_550' => 'ALERT', + 'critical_600' => 'EMERGENCY', + 'Customer ID' => 'Client ID', + 'Cycle' => 'Cycle', + 'Date' => 'Date', + 'Delete planified payment' => 'Supprimer paiement récurrent', + 'Delete this planified payment' => 'Supprimer ce paiement récurrent', + 'Details' => 'Détails', + 'Do you really want to delete this planified payment ?' => 'Voulez-vous vraiment supprimer ce paiement récurrent ?', + 'Edit planified payment' => 'Modifier un paiement récurrent', + 'Edit planified payment %title' => 'Modifier du paiement récurrent "%title" ', + 'Edit this customer' => 'Modifier ce client', + 'Edit this planified payment' => 'Modifier ce paiement récurrent', + 'Editing planified payment "%title"' => 'Modification du paiement récurrent "%title" ', + 'Fill the fields : App Name & Sandbox developer account' => 'Remplir les champs : App Name & Sandbox developer account ', + 'Frequency' => 'Fréquence', + 'Frequency interval' => 'Interval de la fréquence', + 'Future Payments' => 'Future Payments', + 'General configuration' => 'Configuration générale', + 'General description' => 'Description générale', + 'Global informations of this planified payment' => 'Informations générales de ce paiement récurrent', + 'Help' => 'Aide', + 'Home' => 'Accueil', + 'How to configure Plannified payment' => 'Comment configurer un paiement récurrent', + 'In SANDBOX APP SETTINGS' => 'Dans la section SANDBOX APP SETTINGS ', + 'In SANDBOX WEBHOOKS' => 'Dans la section SANDBOX WEBHOOKS', + 'In your PayPal page API configuration' => 'Dans votre page de configuration de votre API', + 'Invoicing' => 'Invoicing', + 'Level' => 'Niveau', + 'List of planified payments' => 'Liste des paiements récurrents', + 'Log' => 'Log', + 'Log In on developer.paypal.com' => 'Se connecter sur https://developer.paypal.com ', + 'Log In with PayPal' => 'Log In with PayPal', + 'Max amount' => 'Montant maximum', + 'Min amount' => 'Montant minium', + 'New recursive invoice from order %id' => 'Nouvelle commande récursive créée à partir de la commande %id', + 'No planified payment has been created yet. Click the + button to create one.' => 'Aucun paiement récurrent trouvé. Cliquer sur le bouton + ci-dessu pour en créer un', + 'None' => 'Aucun', + 'Order ID' => 'Commande ID', + 'PayPal Here' => 'PayPal Here', + 'Payment configuration' => 'Configuration paiement', + 'Payouts' => 'Payouts', + 'Personal Information' => 'Personal Information', + 'Planified payment' => 'Paiement récurrent', + 'Planified payment configuration' => 'Configuration paiement récurrent', + 'Planified payment created on %date_create. Last modification: %date_change' => 'Paiement récurrent créé le %date_create. Dernière modification : %date_change ', + 'Planified payments' => 'Paiements récurrents', + 'Production configuration' => 'Configuration mode Production', + 'Return URL' => ' Return URL ', + 'SandBox configuration' => 'Configuration mode Bac à Sable', + 'See webhook details' => 'Voir détails du webhook', + 'That\'s it !' => 'Et voilà !', + 'These planned payments will appear in step 4 of the purchase tunnel when selecting the payment method.' => 'Ces paiements récurrents apparaitront à l\'étape 4 du tunnel d\'achat lors de la sélection du moyen de paiement.', + 'This feature uses PayPal\'s Billing Plan and Agreement. It allows debiting a client recursively directly from PayPal.' => 'Cette fonctionnalité se sert des Billing Plan et Agreement de PayPal. Elle permet de débiter un client de manière récursive directement depuis PayPal.', + 'This informations can be found directly in concerned order details.' => 'Ces informations peuvent se retrouver directement sur les détails des commandes concernées.', + 'This is where we log all the transactions made with PayPal. PayPal webhooks also automatically feed these logs.' => 'C\'est ici que nous loggons l\'ensemble des transactions réalisées avec PayPal. Les webhooks de PayPal viennent aussi alimenter automatiquement ces logs.', + 'This method use PayPal webhooks and works only in HTTPS !' => 'Cette méthode utilise les WEBHOOKs de PayPal et ne fonctionne donc QUE ET UNIQUEMENT QUE en HTTPS !', + 'This method works only with PayPal PRO UK account. Please contact PayPal to upgrade your account if you need this service. For more informations, go here' => 'Ce moyen de paiement ne fonctionne QUE ET UNIQUEMENT QUE si vous avez un compte PayPal PRO UK. Merci de contacter PayPal pour mettre à jour votre compte si vous avez besoin de ce service. Pour plus d\'informations, rendez-vous ici', + 'This urls can take 3 hours to be taken in consideration' => ' Ces urls peuvent mettre 3 heures pour être prises en considération', + 'Title' => 'Titre', + 'Use Seamless Checkout' => 'Use Seamless Checkout', + 'You can edit the payment confirmation email sent to the customer after a successful payment.' => 'Vous pouvez modifier l\'email de confirmation de paiement envoyé au client après un paiement réalisé avec succès.', + 'You can add some planified payment here.' => 'Vous pouvez ajouter des paiements récurrents ici. ', + 'critical_{$log->getLevel()}' => 'critical_{$log->getLevel()}', +); diff --git a/domokits/local/modules/PayPal/I18n/en_US.php b/domokits/local/modules/PayPal/I18n/en_US.php new file mode 100644 index 0000000..0b4fa14 --- /dev/null +++ b/domokits/local/modules/PayPal/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/domokits/local/modules/PayPal/I18n/fr_FR.php b/domokits/local/modules/PayPal/I18n/fr_FR.php new file mode 100644 index 0000000..fa5515d --- /dev/null +++ b/domokits/local/modules/PayPal/I18n/fr_FR.php @@ -0,0 +1,76 @@ + 'Activer le paiement : "PAYPAL EXPRESS"', + 'Activate payment with PayPal account' => 'Activer le paiement par : "PAYPAL"', + 'Activate payment with credit card' => 'Activer le paiement par : "CARTE BANCAIRE"', + 'Activate payment with planified payment' => 'Activer le paiement par : "PAIEMENT RECURRENT"', + 'Activate sandbox mode' => 'Activer le mode Bac à Sable', + 'Allowed IPs in test mode' => 'IP autorisées pour le mode Bac à sable', + 'CVV' => 'Code secret (3 chiffres)', + 'Card number' => 'Numéro de la carte', + 'Card type' => 'Type de carte', + 'Credit card is invalid' => 'Carte bancaire invalide', + 'Cycle' => 'Cycle', + 'Expire month' => 'Mois d\'expiration', + 'Expire year' => 'Année d\'expiration', + 'Express checkout begin with cart %id' => 'Début du paiement EXPRESS CHECKOUT avec la panier : %id', + 'Express checkout failed in expressCheckoutOkAction() function' => 'Echec de la méthode Express Checkout de PayPal dans la function expressCheckoutOkAction()', + 'Express Checkout login failed' => 'Echec de la connexion avec EXPRESS CHECKOUT depuis le panier', + 'Frequency' => 'Fréquence', + 'Frequency interval' => 'Interval de la fréquence', + 'If checked, a payment confirmation e-mail is sent to the customer after each PayPal transaction.' => 'Si cochée, un mail de confirmation de paiement sera envoyés grâce aux webhook directement rattachés à PayPal', + 'If checked, a payment confirmation e-mail is sent to the customer.' => 'Si cochée, le client sera informé dès que sa commande passera en payée.', + 'If checked, a PayPal popup will be used to execute the payment.' => 'Si cochée, le paiement se déroulera via une popup PayPal pour rester sur le site marchand.', + 'If checked, the order can be paid by PayPal account.' => 'Si cochée, la commande pourra être payée par un simple compte PayPal', + 'If checked, the order can be paid by credit card.' => 'Si cochée, la commande pourra être payée par carte bancaire (PayPal se chargera de vérifier sa validité)', + 'If checked, the order can be paid by planified payement.' => 'Si cochée, la commande pourra être payée par paiement récurrent (PayPal agreement)', + 'If checked, the order can be paid directly from cart.' => 'Si cochée, la commande pourra être payée directement depuis le panier', + 'If checked, the order confirmation message is sent to the customer only when the payment is successful. The order notification is always sent to the shop administrator' => 'Si cochée, le mail de confirmation de commande ne sera pas envoyé au client dès que celui-ci cliquera sur l\'une des méthodes de paiement de PayPal', + 'Invalid charge type send to create charge model' => 'Paramètre "type" invalide pour générer un "Charge Model"', + 'Invalid fail action send to create merchant preference' => 'Paramètre "fail action" invalide pour générer un "Merchant Preference"', + 'Invalid number of charge models send to create payment definition' => 'Nombre de "Charge Models" insuffisant pour générer un "Payment Definition"', + 'Invalid number of payment definition send to generate billing plan' => 'Nombre de "Payment definition" insuffisant pour générer un "Billing Plan"', + 'Invalid payment frequency send to create payment definition' => 'Paramètre "frequency" invalide pour générer un "Payment Definition"', + 'Invalid payment type send to create payment definition' => 'Paramètre "type" invalide pour générer un "Payment Definition"', + 'Invalid planified payment id : %id' => 'ID du paiement récurrent incorrect : %id', + 'Invalid type send to generate billing plan' => 'Paramètre "type" invalide pour générer un "Billing Plan"', + 'Let value to 0 if you don\'t want a maximum' => 'Laisser 0 si vous ne voulez pas de maximum', + 'Let value to 0 if you don\'t want a minimum' => 'Laisser 0 si vous ne voulez pas de minimum', + 'List of IP addresses allowed to use this payment on the front-office when in test mode (your current IP is %ip). One address per line' => 'Liste des adresses IP autorisées pour payer en Front lorsque le mmode Bac à Sable est activé (votre adresse IP actuelle est %ip). Une adresse IP par ligne.', + 'Max amount' => 'Montant maximum', + 'Maximum items in cart' => 'Nombre d\'articles maximum dans le panier', + 'Maximum number of items in the customer cart for which this payment method is available.' => 'Nombre maximum d\'articles dans le panier pour que le moyen de paiement soit valide.', + 'Maximum order total' => 'Montant maximum de la commande', + 'Maximum order total in the default currency for which this payment method is available. Enter 0 for no maximum' => 'Montant maximum de la commande dans la devise courante pour autoriser le paiement. Mettre 0 pour ne pas avoir de maximum.', + 'Merchant ID' => 'Identifiant du marchand', + 'Method agreementOkAction => One of this parameter is invalid : $token = %token, $orderId = %order_id' => 'Method agreementOkAction => L\'un de ces paramètres est incorrecte : $token = %token, $orderId = %order_id', + 'Method okAction => One of this parameter is invalid : $payerId = %payer_id, $orderId = %order_id' => 'Method okAction => L\'un de ces paramètres est incorrecte : $payerId = %payer_id, $orderId = %order_id', + 'Min amount' => 'Montant minium', + 'Minimum order total' => 'Montant minimum de la commande', + 'Minimum order total in the default currency for which this payment method is available. Enter 0 for no minimum' => ' Montant minimum de la commande dans la devise courante pour autoriser le paiement. Mettre 0 pour ne pas avoir de minimum.', + 'Order address no found to generate PayPal shipping address' => 'Adresse de la commande non trouvée pour générer l\'adresse de livraison PayPal', + 'Order created with success in PayPal with method : %method' => 'Commande créée avec succès success via PayPal avec la méthode : %method ', + 'Order failed with method : %method' => 'Echec du paiement avec la méthode : %method', + 'Order payed with success in PayPal with method : %method' => 'Commande créée avec succès avec PayPal avec la méthode : %method ', + 'Order payed with success with method : %method' => 'Paiement réalisé avec succès avec la méthode : %method', + 'PayPal method' => 'Méthode PayPal', + 'Paypal configuration' => 'Configuration PayPal', + 'Position' => 'Position', + 'Send a payment confirmation e-mail' => 'Envoyer le mail de confirmation de paiement', + 'Send a recursive payment confirmation e-mail' => 'Envoyer le mail de confirmation de paiement pour les commandes récursives', + 'Send order confirmation on payment success' => 'Bloquer le mail de confirmation de commande (mail envoyé dès qu\'une commande est créée même si elle n\'est pas payée)', + 'The Paypal identity merchant account' => 'L\'indentifiant PayPal unique du compte marchand ', + 'The delivery module is not valid.' => 'Le module de transport n\'est pas valide.', + 'The description of the planified payment' => 'La description du paiement récurrent', + 'The locale of the planified payment' => 'La locale du paiement récurrent', + 'The title of the planified payment' => 'Le titre du paiement récurrent', + 'This value should not be blank' => 'Cette valeur ne doit pas être vide', + 'Use InContext mode for classic PayPal payment' => 'Utiliser le mode InContext pour le payment classic PayPal', + 'Your Paypal login' => 'Client ID', + 'Your Paypal password' => 'Client SECRET', + 'Your Paypal sandbox login' => 'Client ID', + 'Your Paypal sandbox password' => 'Client SECRET', + 'login' => 'Client ID', + 'password' => 'Client SECRET', +); diff --git a/domokits/local/modules/PayPal/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/PayPal/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..82d6a7f --- /dev/null +++ b/domokits/local/modules/PayPal/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,12 @@ + 'jours', + 'MONTH' => 'Mois', + 'Finish payment with PayPal' => 'Terminer le paiement avec PayPal', + 'Payment in %x times every %frequency_interval %frequency' => 'Paiement en %x fois, tout les %frequency_interval %frequency', + 'Planified payment' => 'Paiement récurrent', + 'planified_payment' => 'Paiement récurrent', + 'WEEK' => 'Semaines', + 'YEAR' => 'Années', +); diff --git a/domokits/local/modules/PayPal/I18n/pdf/default/fr_FR.php b/domokits/local/modules/PayPal/I18n/pdf/default/fr_FR.php new file mode 100644 index 0000000..630b4f0 --- /dev/null +++ b/domokits/local/modules/PayPal/I18n/pdf/default/fr_FR.php @@ -0,0 +1,10 @@ + 'Jours', + 'MONTH' => 'Mois', + 'Payment in %x times every %frequency_interval %frequency' => 'Paiement en %x fois, tout les %frequency_interval %frequency', + 'Planified payment' => 'Paiement récurrent', + 'WEEK' => 'Semaines', + 'YEAR' => 'Années', +); diff --git a/domokits/local/modules/PayPal/Loop/PayPalLogLoop.php b/domokits/local/modules/PayPal/Loop/PayPalLogLoop.php new file mode 100644 index 0000000..8509345 --- /dev/null +++ b/domokits/local/modules/PayPal/Loop/PayPalLogLoop.php @@ -0,0 +1,154 @@ +getResultDataCollection() as $model) { + + $row = new LoopResultRow($model); + + $row->set('log', $model); + + $this->addOutputFields($row, $model); + + $loopResult->addRow($row); + } + + return $loopResult; + } + + /** + * @return PaypalLogQuery + */ + public function buildModelCriteria() + { + $query = new PaypalLogQuery(); + + if (null != $orderId = $this->getOrderId()) { + $query->filterByOrderId($orderId); + } + + if (null != $customerId = $this->getCustomerId()) { + $query->filterByCustomerId($customerId); + } + + if (null != $channel = $this->getChannel()) { + $query->filterByChannel($channel); + } + + if (null != $level = $this->getLevel()) { + $query->filterByLevel($level); + } + + $this->buildModelCriteriaOrder($query); + $query->groupById(); + + return $query; + } + + /** + * @param PaypalLogQuery $query + */ + protected function buildModelCriteriaOrder(PaypalLogQuery $query) + { + foreach ($this->getOrder() as $order) { + switch ($order) { + case 'id': + $query->orderById(); + break; + case 'id-reverse': + $query->orderById(Criteria::DESC); + break; + case 'order-id': + $query->orderById(); + break; + case 'order-id-reverse': + $query->orderById(Criteria::DESC); + break; + case 'customer-id': + $query->addAscendingOrderByColumn('i18n_TITLE'); + break; + case 'customer-id-reverse': + $query->addDescendingOrderByColumn('i18n_TITLE'); + break; + case 'date': + $query->orderByCreatedAt(); + break; + case 'date-reverse': + $query->orderByCreatedAt(Criteria::DESC); + break; + default: + $query->orderById(); + break; + } + } + } + + /** + * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('order_id'), + Argument::createIntTypeArgument('customer_id'), + Argument::createAnyTypeArgument('channel'), + Argument::createIntTypeArgument('level'), + Argument::createEnumListTypeArgument( + 'order', + [ + 'id', + 'id-reverse', + 'order-id', + 'order-id-reverse', + 'customer-id', + 'customer-id-reverse', + 'date', + 'date-reverse', + ], + 'id' + ) + ); + } +} diff --git a/domokits/local/modules/PayPal/Loop/PayPalOrderLoop.php b/domokits/local/modules/PayPal/Loop/PayPalOrderLoop.php new file mode 100644 index 0000000..ed07f81 --- /dev/null +++ b/domokits/local/modules/PayPal/Loop/PayPalOrderLoop.php @@ -0,0 +1,109 @@ +getResultDataCollection() as $model) { + $row = new LoopResultRow($model); + + $row->set('paypal_order', $model); + + $this->addOutputFields($row, $model); + + $loopResult->addRow($row); + } + + return $loopResult; + } + + /** + * @return PaypalOrderQuery + */ + public function buildModelCriteria() + { + $query = new PaypalOrderQuery(); + + if (null != $id = $this->getId()) { + $query->filterById($id); + } + + $this->buildModelCriteriaOrder($query); + + return $query; + } + + /** + * @param PaypalOrderQuery $query + */ + protected function buildModelCriteriaOrder(PaypalOrderQuery $query) + { + foreach ($this->getOrder() as $order) { + switch ($order) { + case 'id': + $query->orderById(); + break; + case 'id-reverse': + $query->orderById(Criteria::DESC); + break; + default: + break; + } + } + } + + /** + * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntListTypeArgument('id'), + Argument::createEnumListTypeArgument( + 'order', + [ + 'id', + 'id-reverse' + ], + 'id' + ) + ); + } +} diff --git a/domokits/local/modules/PayPal/Loop/PayPalPlanifiedPaymentLoop.php b/domokits/local/modules/PayPal/Loop/PayPalPlanifiedPaymentLoop.php new file mode 100644 index 0000000..c488183 --- /dev/null +++ b/domokits/local/modules/PayPal/Loop/PayPalPlanifiedPaymentLoop.php @@ -0,0 +1,133 @@ +getCurrentRequest()->getSession()->get('thelia.current.lang'); + + /** + * @var PaypalPlanifiedPayment $model + */ + foreach ($loopResult->getResultDataCollection() as $model) { + $model->getTranslation($lang->getLocale()); + $row = new LoopResultRow($model); + + $row->set('planifiedPayment', $model); + + $this->addOutputFields($row, $model); + + $loopResult->addRow($row); + } + + return $loopResult; + } + + /** + * @return PaypalPlanifiedPaymentQuery + */ + public function buildModelCriteria() + { + $query = new PaypalPlanifiedPaymentQuery(); + + if (null != $id = $this->getId()) { + $query->filterById($id); + } + + /* manage translations */ + $this->configureI18nProcessing( + $query, + array( + 'TITLE', + 'DESCRIPTION' + ) + ); + + $this->buildModelCriteriaOrder($query); + $query->groupById(); + + return $query; + } + + /** + * @param PaypalPlanifiedPaymentQuery $query + */ + protected function buildModelCriteriaOrder(PaypalPlanifiedPaymentQuery $query) + { + foreach ($this->getOrder() as $order) { + switch ($order) { + case 'id': + $query->orderById(); + break; + case 'id-reverse': + $query->orderById(Criteria::DESC); + break; + case 'position': + $query->orderById(); + break; + case 'position-reverse': + $query->orderById(Criteria::DESC); + break; + case 'title': + $query->addAscendingOrderByColumn('i18n_TITLE'); + break; + case 'title-reverse': + $query->addDescendingOrderByColumn('i18n_TITLE'); + break; + default: + $query->orderById(); + break; + } + } + } + + /** + * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntListTypeArgument('id'), + Argument::createEnumListTypeArgument( + 'order', + [ + 'id', + 'id-reverse', + 'position', + 'position-reverse', + 'title', + 'title-reverse', + ], + 'id' + ) + ); + } +} diff --git a/domokits/local/modules/PayPal/Model/PaypalCart.php b/domokits/local/modules/PayPal/Model/PaypalCart.php new file mode 100644 index 0000000..4603a7c --- /dev/null +++ b/domokits/local/modules/PayPal/Model/PaypalCart.php @@ -0,0 +1,48 @@ +aCart === null && ($this->id !== null)) { + $this->aCart = CartQuery::create()->findPk($this->id, $con); + } + + return $this->aCart; + } + + /** + * Declares an association between this object and a ChildCart object. + * + * @param Cart $cart + * @return \PayPal\Model\PaypalCart The current object (for fluent API support) + * @throws PropelException + */ + public function setCart(Cart $cart = null) + { + if ($cart === null) { + $this->setId(NULL); + } else { + $this->setId($cart->getId()); + } + + $this->aCart = $cart; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Model/PaypalCartQuery.php b/domokits/local/modules/PayPal/Model/PaypalCartQuery.php new file mode 100644 index 0000000..a73f9fe --- /dev/null +++ b/domokits/local/modules/PayPal/Model/PaypalCartQuery.php @@ -0,0 +1,21 @@ +aCustomer === null && ($this->id !== null)) { + $this->aCustomer = CustomerQuery::create()->findPk($this->id, $con); + } + + return $this->aCustomer; + } + + /** + * Declares an association between this object and a ChildCustomer object. + * + * @param Customer $customer + * @return \PayPal\Model\PaypalCustomer The current object (for fluent API support) + * @throws PropelException + */ + public function setCustomer(Customer $customer = null) + { + if ($customer === null) { + $this->setId(NULL); + } else { + $this->setId($customer->getId()); + } + + $this->aCustomer = $customer; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Model/PaypalCustomerQuery.php b/domokits/local/modules/PayPal/Model/PaypalCustomerQuery.php new file mode 100644 index 0000000..cad81bc --- /dev/null +++ b/domokits/local/modules/PayPal/Model/PaypalCustomerQuery.php @@ -0,0 +1,21 @@ +aOrder === null && ($this->id !== null)) { + $this->aOrder = OrderQuery::create()->findPk($this->id, $con); + } + + return $this->aOrder; + } + + /** + * Declares an association between this object and a ChildOrder object. + * + * @param Order $order + * @return \PayPal\Model\PaypalOrder The current object (for fluent API support) + * @throws PropelException + */ + public function setOrder(Order $order = null) + { + if ($order === null) { + $this->setId(NULL); + } else { + $this->setId($order->getId()); + } + + $this->aOrder = $order; + + return $this; + } +} diff --git a/domokits/local/modules/PayPal/Model/PaypalOrderQuery.php b/domokits/local/modules/PayPal/Model/PaypalOrderQuery.php new file mode 100644 index 0000000..0f70b7a --- /dev/null +++ b/domokits/local/modules/PayPal/Model/PaypalOrderQuery.php @@ -0,0 +1,21 @@ +beginTransaction(); + + try { + /** @var PayPalPaymentService $payPalService */ + $payPalService = $this->getContainer()->get(self::PAYPAL_PAYMENT_SERVICE_ID); + /** @var PayPalAgreementService $payPalAgreementService */ + $payPalAgreementService = $this->getContainer()->get(self::PAYPAL_AGREEMENT_SERVICE_ID); + + if (null !== $payPalCart = PaypalCartQuery::create()->findOneById($order->getCartId())) { + + if (null !== $payPalCart->getCreditCardId()) { + $payment = $payPalService->makePayment($order, $payPalCart->getCreditCardId()); + + //This payment method does not have a callback URL... So we have to check the payment status + if ($payment->getState() === PayPal::PAYMENT_STATE_APPROVED) { + $event = new OrderEvent($order); + $event->setStatus(OrderStatusQuery::getPaidStatus()->getId()); + $this->getDispatcher()->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + $response = new RedirectResponse(URL::getInstance()->absoluteUrl('/order/placed/' . $order->getId())); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order payed with success with method : %method', + [ + '%method' => self::PAYPAL_METHOD_CREDIT_CARD + ], + self::DOMAIN_NAME + ), + [ + 'order_id' => $order->getId(), + 'customer_id' => $order->getCustomerId() + ], + Logger::INFO + ); + } else { + $response = new RedirectResponse(URL::getInstance()->absoluteUrl('/module/paypal/cancel/' . $order->getId())); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order failed with method : %method', + [ + '%method' => self::PAYPAL_METHOD_CREDIT_CARD + ], + self::DOMAIN_NAME + ), + [ + 'order_id' => $order->getId(), + 'customer_id' => $order->getCustomerId() + ], + Logger::CRITICAL + ); + } + } elseif (null !== $planifiedPayment = PaypalPlanifiedPaymentQuery::create()->findOneById($payPalCart->getPlanifiedPaymentId())) { + //Agreement Payment + $agreement = $payPalAgreementService->makeAgreement($order, $planifiedPayment); + $response = new RedirectResponse($agreement->getApprovalLink()); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order created with success in PayPal with method : %method', + [ + '%method' => self::PAYPAL_METHOD_PLANIFIED_PAYMENT + ], + self::DOMAIN_NAME + ), + [ + 'order_id' => $order->getId(), + 'customer_id' => $order->getCustomerId() + ], + Logger::INFO + ); + } else { + //Classic Payment + $payment = $payPalService->makePayment($order); + $response = new RedirectResponse($payment->getApprovalLink()); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order created with success in PayPal with method : %method', + [ + '%method' => self::PAYPAL_METHOD_PAYPAL + ], + self::DOMAIN_NAME + ), + [ + 'order_id' => $order->getId(), + 'customer_id' => $order->getCustomerId() + ], + Logger::INFO + ); + } + + } else { + //Classic Payment + $payment = $payPalService->makePayment($order); + $response = new RedirectResponse($payment->getApprovalLink()); + PayPalLoggerService::log( + Translator::getInstance()->trans( + 'Order created with success in PayPal with method : %method', + [ + '%method' => self::PAYPAL_METHOD_PAYPAL + ], + self::DOMAIN_NAME + ), + [ + 'order_id' => $order->getId(), + 'customer_id' => $order->getCustomerId() + ], + Logger::INFO + ); + + //Future Payment NOT OPERATIONNEL IN PAYPAL API REST YET ! + //$payment = $payPalService->makePayment($order, null, null, true); + //$response = new RedirectResponse($payment->getApprovalLink()); + } + + $con->commit(); + + return $response; + } catch (PayPalConnectionException $e) { + $con->rollBack(); + + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } catch(\Exception $e) { + $con->rollBack(); + + + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } + } + + /** + * + * This method is call on Payment loop. + * + * If you return true, the payment method will de display + * If you return false, the payment method will not be display + * + * @return boolean + */ + public function isValidPayment() + { + $isValid = false; + + // Check if total order amount is within the module's limits + $order_total = $this->getCurrentOrderTotalAmount(); + + $min_amount = Paypal::getConfigValue('minimum_amount', 0); + $max_amount = Paypal::getConfigValue('maximum_amount', 0); + + if ( + ($order_total > 0) + && + ($min_amount <= 0 || $order_total >= $min_amount) + && + ($max_amount <= 0 || $order_total <= $max_amount) + ) { + // Check cart item count + $cartItemCount = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->countCartItems(); + + if ($cartItemCount <= Paypal::getConfigValue('cart_item_count', 9)) { + $isValid = true; + + if (PayPalBaseService::isSandboxMode()) { + // In sandbox mode, check the current IP + $raw_ips = explode("\n", Paypal::getConfigValue('allowed_ip_list', '')); + + $allowed_client_ips = array(); + + foreach ($raw_ips as $ip) { + $allowed_client_ips[] = trim($ip); + } + + $client_ip = $this->getRequest()->getClientIp(); + + $isValid = in_array($client_ip, $allowed_client_ips); + } + } + } + + return $isValid; + } + + /** + * if you want, you can manage stock in your module instead of order process. + * Return false to decrease the stock when order status switch to pay + * + * @return bool + */ + public function manageStockOnCreation() + { + return false; + } + + /** + * @param \Propel\Runtime\Connection\ConnectionInterface $con + */ + public function postActivation(ConnectionInterface $con = null): void + { + $database = new Database($con); + $database->insertSql(null, array(__DIR__ . "/Config/create.sql")); + + // Setup some default values at first install + if (null === self::getConfigValue('minimum_amount', null)) { + self::setConfigValue('minimum_amount', 0); + self::setConfigValue('maximum_amount', 0); + self::setConfigValue('send_payment_confirmation_message', 1); + self::setConfigValue('cart_item_count', 999); + } + + if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) { + $message = new Message(); + + $message + ->setName(self::CONFIRMATION_MESSAGE_NAME) + ->setHtmlTemplateFileName('paypal-payment-confirmation.html') + ->setTextTemplateFileName('paypal-payment-confirmation.txt') + ->setLocale('en_US') + ->setTitle('Paypal payment confirmation') + ->setSubject('Payment of order {$order_ref}') + ->setLocale('fr_FR') + ->setTitle('Confirmation de paiement par Paypal') + ->setSubject('Confirmation du paiement de votre commande {$order_ref}') + ->save() + ; + } + + if (null === MessageQuery::create()->findOneByName(self::RECURSIVE_MESSAGE_NAME)) { + $message = new Message(); + + $message + ->setName(self::RECURSIVE_MESSAGE_NAME) + ->setHtmlTemplateFileName('paypal-recursive-payment-confirmation.html') + ->setTextTemplateFileName('paypal-recursive-payment-confirmation.txt') + ->setLocale('en_US') + ->setTitle('Paypal payment confirmation') + ->setSubject('Payment of order {$order_ref}') + ->setLocale('fr_FR') + ->setTitle('Confirmation de paiement par Paypal') + ->setSubject('Confirmation du paiement de votre commande {$order_ref}') + ->save() + ; + } + + /* Deploy the module's image */ + $module = $this->getModuleModel(); + + if (ModuleImageQuery::create()->filterByModule($module)->count() == 0) { + $this->deployImageFolder($module, sprintf('%s/images', __DIR__), $con); + } + } + + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + $finder = (new Finder()) + ->files() + ->name('#.*?\.sql#') + ->sortByName() + ->in(__DIR__ . DS . 'Config' . DS . 'Update') + ; + + $database = new Database($con); + + /** @var \Symfony\Component\Finder\SplFileInfo $updateSQLFile */ + foreach ($finder as $updateSQLFile) { + if (version_compare($currentVersion, str_replace('.sql', '', $updateSQLFile->getFilename()), '<')) { + $database->insertSql( + null, + [ + $updateSQLFile->getPathname() + ] + ); + } + } + } + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/PayPal/README.md b/domokits/local/modules/PayPal/README.md new file mode 100644 index 0000000..1f7d9f8 --- /dev/null +++ b/domokits/local/modules/PayPal/README.md @@ -0,0 +1,56 @@ +# PayPal + +* I) Install notes +* II) Configure your PayPal account +* III) Module options payments + +## I) Installation + +### Composer + +> **WARNING** : A console access is required to update dependencies. If you don't have a console access, please get the latest 2.x version of the module here : https://github.com/thelia-modules/Paypal/tree/2.x + +To install the module with Composer, open a console, navigate to the Thelia diorectory and type the following command to add the dependency to Thelia composer.json file. + +``` +composer require thelia/paypal-module:~4.0.0 +``` + +## II) Configure your PayPal account + +- Log In on [developer.paypal.com] (https://developer.paypal.com "developer.paypal.com") +- Create REST API apps [here] (https://developer.paypal.com/developer/applications/ "here") +- Click on Create App +- Fill the fields : App Name & Sandbox developer account +- Click on Create App +- Note the Client ID to use it later in the module configuration +- Note the Client SECRET to use it later in the module configuration + +#### In SANDBOX WEBHOOKS +- To fill this part, go to your module configuration page to see the urls to implement + +#### In SANDBOX APP SETTINGS +- To fill this part, go to your module configuration page to see the urls to implement + + +## III) Module options payments + +#### Classic PayPal payment +![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_classic.png?raw=true) +- This method will redirect to the PayPal platform to proceed payment + +#### InContext Classic PayPal payment +![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_classic_incontext.png?raw=true) +- This method will allow the customer to pay from a PayPal inContext popup directly from your website (no redirection to the PayPal plateform) + +#### Credit card +![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_credit_card.png?raw=true) +- This method allow the customer to pay directly by a credit card without a PayPal account. 'The merchant must have a Pro PayPal account UK and the website must be in HTTPS' + +#### Recursive payment +![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_recursive.png?raw=true) +- This method use the 'PayPal AGRREMENTS' and allow you to use recursive payments on your website. If you want to log all PayPal actions, you need to configure the PayPal webhooks and to have a wabsite in HTTPS + +#### Express checkout +![alt classic paypal payment](https://github.com/thelia-modules/Paypal/blob/master/images/payment_express_checkout.png?raw=true) +- This method allow the customer to proceed the payment directly from the cart from a PayPal inContext popup. diff --git a/domokits/local/modules/PayPal/Service/Base/PayPalBaseService.php b/domokits/local/modules/PayPal/Service/Base/PayPalBaseService.php new file mode 100644 index 0000000..a623c0d --- /dev/null +++ b/domokits/local/modules/PayPal/Service/Base/PayPalBaseService.php @@ -0,0 +1,414 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Service\Base; + +use Exception; +use Monolog\Logger; +use PayPal\Api\Amount; +use PayPal\Api\FuturePayment; +use PayPal\Api\Payer; +use PayPal\Api\PayerInfo; +use PayPal\Api\ShippingAddress; +use PayPal\Api\Transaction; +use PayPal\Auth\OAuthTokenCredential; +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalOrderEvent; +use PayPal\Model\PaypalCart; +use PayPal\Model\PaypalCartQuery; +use PayPal\Model\PaypalOrder; +use PayPal\Model\PaypalPlanifiedPayment; +use PayPal\PayPal; +use PayPal\Rest\ApiContext; +use PayPal\Service\PayPalLoggerService; +use Propel\Runtime\Exception\PropelException; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\RouterInterface; +use Thelia\Core\Event\Cart\CartRestoreEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Core\Translation\Translator; +use Thelia\Model\Cart; +use Thelia\Model\Country; +use Thelia\Model\Currency; +use Thelia\Model\Lang; +use Thelia\Model\Order; +use Thelia\Model\OrderAddressQuery; + +class PayPalBaseService +{ + /** @var EventDispatcherInterface */ + protected EventDispatcherInterface $dispatcher; + + /** @var RequestStack */ + protected RequestStack $requestStack; + + /** @var RouterInterface */ + protected RouterInterface $router; + + /** @var OAuthTokenCredential */ + protected OAuthTokenCredential $authTokenCredential; + + /** + * PayPalBaseService constructor. + * @param EventDispatcherInterface $dispatcher + * @param RequestStack $requestStack + * @param RouterInterface $router + */ + public function __construct(EventDispatcherInterface $dispatcher, RequestStack $requestStack, RouterInterface $router) + { + $this->dispatcher = $dispatcher; + $this->requestStack = $requestStack; + $this->router = $router; + + $this->authTokenCredential = new OAuthTokenCredential(self::getLogin(), self::getPassword()); + } + + /** + * @param Order $order + * @param null $creditCardId + * @param PaypalPlanifiedPayment|null $planifiedPayment + * @return PayPalOrderEvent + * @throws PropelException + */ + public function generatePayPalOrder(Order $order, $creditCardId = null, PaypalPlanifiedPayment $planifiedPayment = null) + { + $payPalOrder = new PaypalOrder(); + $payPalOrder + ->setId($order->getId()) + ->setAmount($order->getTotalAmount()) + ; + + if (null !== $creditCardId) { + $payPalOrder->setCreditCardId($creditCardId); + } + + if (null !== $planifiedPayment) { + /** @var Lang $lang */ + $lang = $this->requestStack->getCurrentRequest()->getSession()->get('thelia.current.lang'); + $planifiedPayment->getTranslation($lang->getLocale()); + + $payPalOrder + ->setPlanifiedTitle($planifiedPayment->getTitle()) + ->setPlanifiedDescription($planifiedPayment->getDescription()) + ->setPlanifiedFrequency($planifiedPayment->getFrequency()) + ->setPlanifiedFrequencyInterval($planifiedPayment->getFrequencyInterval()) + ->setPlanifiedCycle($planifiedPayment->getCycle()) + ->setPlanifiedMinAmount($planifiedPayment->getMinAmount()) + ->setPlanifiedMaxAmount($planifiedPayment->getMaxAmount()) + ; + } + + $payPalOrderEvent = new PayPalOrderEvent($payPalOrder); + $this->dispatcher->dispatch($payPalOrderEvent, PayPalEvents::PAYPAL_ORDER_CREATE); + + return $payPalOrderEvent; + } + + /** + * @param PaypalOrder $payPalOrder + * @param $state + * @param string|null $paymentId + * @param string|null $agreementId + * @return PayPalOrderEvent + */ + public function updatePayPalOrder(PaypalOrder $payPalOrder, $state, string $paymentId = null, string $agreementId = null) + { + $payPalOrder->setState($state); + + if (null !== $paymentId) { + $payPalOrder->setPaymentId($paymentId); + } + + if (null !== $agreementId) { + $payPalOrder->setAgreementId($agreementId); + } + + $payPalOrderEvent = new PayPalOrderEvent($payPalOrder); + $this->dispatcher->dispatch($payPalOrderEvent, PayPalEvents::PAYPAL_ORDER_UPDATE); + + return $payPalOrderEvent; + } + + /** + * @return PaypalCart + */ + public function getCurrentPayPalCart() + { + /** @var Session $session */ + $session = $this->requestStack->getCurrentRequest()->getSession(); + $cart = $session->getSessionCart($this->dispatcher); + + if (null === $cart) { + $cartEvent = new CartRestoreEvent(); + $this->dispatcher->dispatch($cartEvent, TheliaEvents::CART_RESTORE_CURRENT); + + $cart = $cartEvent->getCart(); + } + + if (null === $payPalCart = PaypalCartQuery::create()->findOneById($cart->getId())) { + $payPalCart = new PaypalCart(); + $payPalCart->setId($cart->getId()); + } + + return $payPalCart; + } + + /** + * @param string $method + * @param array $fundingInstruments + * @param PayerInfo|null $payerInfo + * @return Payer + */ + public static function generatePayer(string $method = PayPal::PAYPAL_METHOD_PAYPAL, array $fundingInstruments = [], PayerInfo $payerInfo = null) + { + $payer = new Payer(); + $payer->setPaymentMethod($method); + + // Never set empty instruments when communicating with PayPal + if (count($fundingInstruments) > 0) { + $payer->setFundingInstruments($fundingInstruments); + } + + if (null !== $payerInfo) { + $payer->setPayerInfo($payerInfo); + } + + return $payer; + } + + public static function generatePayerInfo($data = []) + { + return new PayerInfo($data); + } + + /** + * @throws PropelException + * @throws Exception + */ + public static function generateShippingAddress(Order $order) + { + if (null !== $orderAddress = OrderAddressQuery::create()->findOneById($order->getDeliveryOrderAddressId())) { + $shippingAddress = new ShippingAddress(); + + if (null !== $state = $orderAddress->getState()) { + $payPalState = $state->getIsocode(); + } else { + $payPalState = 'CA'; + } + + $shippingAddress + ->setLine1($orderAddress->getAddress1()) + ->setCity($orderAddress->getCity()) + ->setPostalCode($orderAddress->getZipcode()) + ->setCountryCode($orderAddress->getCountry()->getIsoalpha2()) + ->setState($payPalState) + ; + + if (null !== $orderAddress->getAddress2()) { + + if (null !== $orderAddress->getAddress3()) { + $shippingAddress->setLine2($orderAddress->getAddress2() . ' ' . $orderAddress->getAddress3()); + } else { + $shippingAddress->setLine2($orderAddress->getAddress2()); + } + } elseif (null !== $orderAddress->getAddress3()) { + $shippingAddress->setLine2($orderAddress->getAddress3()); + } + + return $shippingAddress; + } + + $message = Translator::getInstance()->trans( + 'Order address no found to generate PayPal shipping address', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + /** + * @param Order $order + * @param Currency $currency + * @return Amount + * @throws PropelException + */ + public function generateAmount(Order $order, Currency $currency) + { + // Specify the payment amount. + $amount = new Amount(); + $amount->setCurrency($currency->getCode()); + $amount->setTotal($order->getTotalAmount()); + + return $amount; + } + + /** + * @param Cart $cart + * @param Currency $currency + * @return Amount + * @throws PropelException + */ + public function generateAmountFromCart(Cart $cart, Currency $currency) + { + // Specify the payment amount. + $amount = new Amount(); + $amount->setCurrency($currency->getCode()); + $amount->setTotal($cart->getTaxedAmount(Country::getDefaultCountry())); + + return $amount; + } + + /** + * @param Amount $amount + * @param string|null $description + * @return Transaction + */ + public function generateTransaction(Amount $amount, ?string $description = '') + { + // ###Transaction + // A transaction defines the contract of a + // payment - what is the payment for and who + // is fulfilling it. Transaction is created with + // a `Payee` and `Amount` types + $transaction = new Transaction(); + $transaction->setAmount($amount); + $transaction->setDescription($description); + + return $transaction; + } + + public function getAccessToken() + { + $config = self::getApiContext()->getConfig(); + $accessToken = $this->authTokenCredential->getAccessToken($config); + + return $accessToken; + } + + public function getRefreshToken() + { + $refreshToken = FuturePayment::getRefreshToken($this->getAccessToken(), self::getApiContext()); + + return $refreshToken; + } + + /** + * SDK Configuration + * + *@return ApiContext + */ + public static function getApiContext() + { + $apiContext = new ApiContext(); + + // Alternatively pass in the configuration via a hashmap. + // The hashmap can contain any key that is allowed in + // sdk_config.ini + $apiContext->setConfig([ + 'acct1.ClientId' => self::getLogin(), + 'acct1.ClientSecret' => self::getPassword(), + 'http.ConnectionTimeOut' => 30, + 'http.Retry' => 1, + 'mode' => self::getMode(), + 'log.LogEnabled' => true, + 'log.FileName' => '../var/log/PayPal.log', + 'log.LogLevel' => 'INFO', + 'cache.enabled' => true, + 'cache.FileName' => '../var/cache/prod/PayPal.cache', + 'http.headers.PayPal-Partner-Attribution-Id' => 'Thelia_Cart', + ]); + + return $apiContext; + } + + /** + * @return string + */ + public static function getLogin() + { + if ((bool)PayPal::getConfigValue('sandbox') === true) { + $login = PayPal::getConfigValue('sandbox_login'); + } else { + $login = PayPal::getConfigValue('login'); + } + + return $login; + } + + /** + * @return string + */ + public static function getPassword() + { + if ((bool)PayPal::getConfigValue('sandbox') === true) { + $password = PayPal::getConfigValue('sandbox_password'); + } else { + $password = PayPal::getConfigValue('password'); + } + + return $password; + } + + /** + * @return string + */ + public static function getMerchantId() + { + if ((bool)PayPal::getConfigValue('sandbox') === true) { + $login = PayPal::getConfigValue('sandbox_merchant_id'); + } else { + $login = PayPal::getConfigValue('merchant_id'); + } + + return $login; + } + + /** + * @return string + */ + public static function getMode() + { + if ((bool)PayPal::getConfigValue('sandbox') === true) { + $mode = 'sandbox'; + } else { + $mode = 'live'; + } + + return $mode; + } + + public static function isSandboxMode(): bool + { + return self::getMode() === 'sandbox'; + } +} diff --git a/domokits/local/modules/PayPal/Service/MyOwnSQLHandler.php b/domokits/local/modules/PayPal/Service/MyOwnSQLHandler.php new file mode 100644 index 0000000..b555091 --- /dev/null +++ b/domokits/local/modules/PayPal/Service/MyOwnSQLHandler.php @@ -0,0 +1,30 @@ + + * Projet: parquets-et-lambris-de-vallereuil.com + * Date: 16/03/2023 + */ +class MyOwnSQLHandler extends MySQLHandler +{ + public function __construct(PDO|ConnectionInterface $pdo = null, string $table, array $additionalFields = [], bool|int $level = Logger::DEBUG, bool $bubble = true) + { + $this->pdo = $pdo; + + parent::__construct(null, $table, $additionalFields, $level, $bubble); + } +} diff --git a/domokits/local/modules/PayPal/Service/PayPalAgreementService.php b/domokits/local/modules/PayPal/Service/PayPalAgreementService.php new file mode 100644 index 0000000..1b8569b --- /dev/null +++ b/domokits/local/modules/PayPal/Service/PayPalAgreementService.php @@ -0,0 +1,953 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Service; + +use Datetime; +use Exception; +use Monolog\Logger; +use PayPal\Api\Agreement; +use PayPal\Api\AgreementStateDescriptor; +use PayPal\Api\AgreementTransactions; +use PayPal\Api\ChargeModel; +use PayPal\Api\CreditCard; +use PayPal\Api\CreditCardToken; +use PayPal\Api\Currency; +use PayPal\Api\FundingInstrument; +use PayPal\Api\MerchantPreferences; +use PayPal\Api\Patch; +use PayPal\Api\PatchRequest; +use PayPal\Api\Payer; +use PayPal\Api\PaymentDefinition; +use PayPal\Api\Plan; +use PayPal\Api\PlanList; +use PayPal\Common\PayPalModel; +use PayPal\Event\PayPalEvents; +use PayPal\Event\PayPalOrderEvent; +use PayPal\Event\PayPalPlanEvent; +use PayPal\Exception\PayPalConnectionException; +use PayPal\Model\PaypalOrder; +use PayPal\Model\PaypalOrderQuery; +use PayPal\Model\PaypalPlan; +use PayPal\Model\PaypalPlanifiedPayment; +use PayPal\Model\PaypalPlanQuery; +use PayPal\PayPal; +use PayPal\Service\Base\PayPalBaseService; +use Propel\Runtime\Exception\PropelException; +use Symfony\Component\Routing\Router; +use Thelia\Core\Translation\Translator; +use Thelia\Model\CurrencyQuery; +use Thelia\Model\Order; +use Thelia\Model\OrderProduct; +use Thelia\Model\OrderProductQuery; +use Thelia\Model\OrderProductTax; +use Thelia\Model\OrderProductTaxQuery; +use Thelia\Tools\URL; + +class PayPalAgreementService extends PayPalBaseService +{ + public const PLAN_TYPE_FIXED = 'FIXED'; + public const PLAN_TYPE_INFINITE = 'INFINITE'; + + public const PAYMENT_TYPE_REGULAR = 'REGULAR'; + public const PAYMENT_TYPE_TRIAL = 'TRIAL'; + + public const CHARGE_TYPE_SHIPPING = 'SHIPPING'; + public const CHARGE_TYPE_TAX = 'TAX'; + + public const PAYMENT_FREQUENCY_DAY = 'DAY'; + public const PAYMENT_FREQUENCY_WEEK = 'WEEK'; + public const PAYMENT_FREQUENCY_MONTH = 'MONTH'; + public const PAYMENT_FREQUENCY_YEAR = 'YEAR'; + + public const FAIL_AMOUNT_ACTION_CONTINUE = 'CONTINUE'; + public const FAIL_AMOUNT_ACTION_CANCEL = 'CANCEL'; + + public const MAX_API_LENGHT = 128; + + /** + * @param Order $order + * @param PaypalPlanifiedPayment $planifiedPayment + * @param string|null $description + * @return Agreement + * @throws PayPalConnectionException + * @throws Exception + */ + public function makeAgreement(Order $order, PaypalPlanifiedPayment $planifiedPayment, string $description = null) + { + //Sadly, this description can NOT be null + if (null === $description) { + $description = 'Thelia order ' . $order->getId(); + } + + $payPalOrderEvent = $this->generatePayPalOrder($order, null, $planifiedPayment); + + $merchantPreferences = $this->createMerchantPreferences($order); + $chargeModel = $this->createChargeModel($order); + + $totalAmount = $order->getTotalAmount(); + $cycleAmount = round($totalAmount / $planifiedPayment->getCycle(), 2); + + $paymentDefinition = $this->createPaymentDefinition( + $order, + 'payment definition for order ' . $order->getId(), + [$chargeModel], + $cycleAmount, + self::PAYMENT_TYPE_REGULAR, + $planifiedPayment->getFrequency(), + $planifiedPayment->getFrequencyInterval(), + $planifiedPayment->getCycle() + ); + + $plan = $this->generateBillingPlan($order, 'plan for order ' . $order->getId(), $merchantPreferences, [$paymentDefinition]); + $plan = $this->createBillingPlan($order, $plan); + $plan = $this->activateBillingPlan($order, $plan); + + $newPlan = new Plan(); + $newPlan->setId($plan->getId()); + + // There is no Billing agreement possible with credit card + $agreement = $this->createBillingAgreementWithPayPal($order, $newPlan, 'agreement ' . $order->getId(), $description); + + //We must update concerned order_product price... order discount... order postage... PayPal will create one invoice each cycle + $this->updateTheliaOrderForCycle($order, $planifiedPayment->getCycle(), $cycleAmount); + + $this->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $agreement->getState(), null, $agreement->getId()); + + return $agreement; + } + + /** + * @throws PropelException + */ + public function updateTheliaOrderForCycle(Order $order, $cycle, $cycleAmount) + { + //Be sure that there is no rounding price lost with this method + $moneyLeft = $cycleAmount; + + $newPostage = round($order->getPostage() / $cycle, 2); + $newPostageTax = round($order->getPostageTax() / $cycle, 2); + $newDiscount = round($order->getDiscount() / $cycle, 2); + + $moneyLeft -= ($newPostage + $newPostageTax + $newDiscount); + $orderProducts = OrderProductQuery::create()->filterByOrderId($order->getId())->find(); + + /** @var OrderProduct $orderProduct */ + foreach ($orderProducts as $orderProduct) { + $newPrice = round($orderProduct->getPrice() / $cycle, 2); + $newPromoPrice = round($orderProduct->getPrice() / $cycle, 2); + + if ($orderProduct->getWasInPromo()) { + $moneyLeft -= $newPromoPrice; + } else { + $moneyLeft -= $newPrice; + } + + $orderProduct + ->setPrice($newPrice) + ->setPromoPrice($newPromoPrice) + ->save() + ; + $taxes = OrderProductTaxQuery::create()->filterByOrderProductId($orderProduct->getId())->find(); + + /** @var OrderProductTax $tax */ + foreach ($taxes as $tax) { + $newAmount = round($tax->getAmount() / $cycle, 2); + $newPromoAmount = round($tax->getPromoAmount() / $cycle, 2); + + if ($orderProduct->getWasInPromo()) { + $moneyLeft -= $newPromoAmount; + } else { + $moneyLeft -= $newAmount; + } + + $tax + ->setAmount($newAmount) + ->setPromoAmount($newPromoAmount) + ->save() + ; + } + } + + //Normally, $moneyLeft == 0 here. But in case of rouding price, adjust the rounding in the postage column + $newPostage += $moneyLeft; + + $order + ->setPostage($newPostage) + ->setPostageTax($newPostageTax) + ->setDiscount($newDiscount) + ->save() + ; + + return $order; + } + + /** + * @param $billingPlanId + * @return Plan + */ + public function getBillingPlan($billingPlanId) + { + $plan = Plan::get($billingPlanId, self::getApiContext()); + + return $plan; + } + + /** + * @param Order $order + * @param Plan $plan + * @return Plan + */ + public function activateBillingPlan(Order $order, Plan $plan) + { + $patch = new Patch(); + + $value = new PayPalModel('{ + "state":"ACTIVE" + }'); + + $patch + ->setOp('replace') + ->setPath('/') + ->setValue($value) + ; + + $patchRequest = new PatchRequest(); + $patchRequest->addPatch($patch); + + $plan->update($patchRequest, self::getApiContext()); + $plan = $this->getBillingPlan($plan->getId()); + + $this->setAndDispatchPaypalPlanEvent($order, $plan, 'update'); + + return $plan; + } + + /** + * This function construct and dispatch a PayPalPlan based on $eventName + * @param Order $order + * @param Plan $plan + * @param string $eventName ("create" | "update") + * @return void + */ + private function setAndDispatchPaypalPlanEvent(Order $order, Plan $plan, string $eventName) { + if (null === $payPalPlan = PaypalPlanQuery::create() + ->filterByPaypalOrderId($order->getId()) + ->filterByPlanId($plan->getId()) + ->findOne()) { + $payPalPlan = new PaypalPlan(); + $payPalPlan + ->setPaypalOrderId($order->getId()) + ->setPlanId($plan->getId()) + ; + } + + $payPalPlan->setState($plan->getState()); + $payPalPlanEvent = new PayPalPlanEvent($payPalPlan); + if ($eventName === "create") { + $this->dispatcher->dispatch($payPalPlanEvent, PayPalEvents::PAYPAL_PLAN_CREATE); + } else { + $this->dispatcher->dispatch($payPalPlanEvent, PayPalEvents::PAYPAL_PLAN_UPDATE); + } + } + + /** + * @param $token + * @param null $orderId + * @return Agreement + * @throws PayPalConnectionException + * @throws Exception + */ + public function activateBillingAgreementByToken($token, $orderId = null) + { + $agreement = new Agreement(); + + try { + $agreement->execute($token, self::getApiContext()); + + return $this->getBillingAgreement($agreement->getId()); + } catch (PayPalConnectionException $e) { + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $orderId + ], + Logger::CRITICAL + ); + throw $e; + } catch (Exception $e) { + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $orderId + ], + Logger::CRITICAL + ); + throw $e; + } + } + + /** + * @param Order $order + * @param $name + * @param $merchantPreferences + * @param array $paymentDefinitions + * @param string|null $description + * @param string $type + * @return Plan + * @throws Exception + */ + public function generateBillingPlan(Order $order, $name, $merchantPreferences, array $paymentDefinitions = [], ?string $description = '', string $type = self::PLAN_TYPE_FIXED) + { + if (!in_array($type, self::getAllowedPlanType())) { + $message = Translator::getInstance()->trans( + 'Invalid type send to generate billing plan', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + if (!is_array($paymentDefinitions) || count($paymentDefinitions) <= 0) { + $message = Translator::getInstance()->trans( + 'Invalid number of payment definition send to generate billing plan', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + $plan = new Plan(); + $plan + ->setName(substr($name, 0, self::MAX_API_LENGHT)) + ->setDescription(substr($description, 0, self::MAX_API_LENGHT)) + ->setType($type) + ->setPaymentDefinitions($paymentDefinitions) + ->setMerchantPreferences($merchantPreferences) + ; + + return $plan; + } + + /** + * @param Plan $plan + * @return bool + */ + public function deleteBillingPlan(Plan $plan) + { + $isDeleted = $plan->delete(self::getApiContext()); + + return $isDeleted; + } + + /** + * @param int $pageSize + * @return PlanList + */ + public function listBillingPlans(int $pageSize = 2) + { + $planList = Plan::all(['page_size' => $pageSize], self::getApiContext()); + + return $planList; + } + + /** + * @param Order $order + * @param Plan $plan + * @return Plan + * @throws PayPalConnectionException + * @throws Exception + */ + public function createBillingPlan(Order $order, Plan $plan) + { + try { + $plan = $plan->create(self::getApiContext()); + $this->setAndDispatchPaypalPlanEvent($order, $plan, 'create'); + + return $plan; + + } catch (PayPalConnectionException $e) { + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } catch (Exception $e) { + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } + } + + /** + * @param Order $order + * @param Plan $plan + * @param $creditCardId + * @param $name + * @param $description + * @return Agreement + * @throws PropelException + * @throws Exception + */ + public function createBillingAgreementWithCreditCard(Order $order, Plan $plan, $creditCardId, $name, $description) + { + $creditCardToken = new CreditCardToken(); + $creditCardToken->setCreditCardId($creditCardId); + + $fundingInstrument = new FundingInstrument(); + //$fundingInstrument->setCreditCardToken($creditCardToken); + + $card = new CreditCard(); + $card + ->setType('visa') + ->setNumber('4491759698858890') + ->setExpireMonth('12') + ->setExpireYear('2017') + ->setCvv2('128') + ; + $fundingInstrument->setCreditCard($card); + + $payer = self::generatePayer( + PayPal::PAYPAL_METHOD_CREDIT_CARD, + [$fundingInstrument], + self::generatePayerInfo(['email' => $order->getCustomer()->getEmail()]) + ); + + $agreement = $this->generateAgreement($order, $plan, $payer, $name, $description); + + $agreement = $agreement->create(self::getApiContext()); + + return $agreement; + } + + /** + * @param Order $order + * @param Plan $plan + * @param $name + * @param $description + * @return Agreement + * @throws Exception + */ + public function createBillingAgreementWithPayPal(Order $order, Plan $plan, $name, $description) + { + $payer = self::generatePayer(PayPal::PAYPAL_METHOD_PAYPAL); + + $agreement = $this->generateAgreement($order, $plan, $payer, $name, $description); + + $agreement = $agreement->create(self::getApiContext()); + + return $agreement; + } + + /** + * @param $agreementId + * @return Agreement + */ + public function getBillingAgreement($agreementId) + { + $agreement = Agreement::get($agreementId, self::getApiContext()); + + return $agreement; + } + + /** + * @param $agreementId + * @param array $params + * @return AgreementTransactions + */ + public function getBillingAgreementTransactions($agreementId, array $params = []) + { + if (is_array($params) || count($params) === 0) { + $params = [ + 'start_date' => date('Y-m-d', strtotime('-15 years')), + 'end_date' => date('Y-m-d', strtotime('+5 days')) + ]; + } + + $agreementTransactions = Agreement::searchTransactions($agreementId, $params, self::getApiContext()); + + return $agreementTransactions; + } + + /** + * @param Agreement $agreement + * @param string $note + * @return Agreement + */ + public function suspendBillingAgreement(Agreement $agreement, string $note = 'Suspending the agreement') + { + //Create an Agreement State Descriptor, explaining the reason to suspend. + $agreementStateDescriptor = new AgreementStateDescriptor(); + $agreementStateDescriptor->setNote($note); + + $agreement->suspend($agreementStateDescriptor, self::getApiContext()); + + $agreement = $this->getBillingAgreement($agreement->getId()); + + return $agreement; + } + + /** + * @param Agreement $agreement + * @param string $note + * @return Agreement + */ + public function reActivateBillingAgreement(Agreement $agreement, string $note = 'Reactivating the agreement') + { + //Create an Agreement State Descriptor, explaining the reason to re activate. + $agreementStateDescriptor = new AgreementStateDescriptor(); + $agreementStateDescriptor->setNote($note); + + $agreement->reActivate($agreementStateDescriptor, self::getApiContext()); + + $agreement = $this->getBillingAgreement($agreement->getId()); + + return $agreement; + } + + /** + * @param Order $order + * @param $name + * @param array $chargeModels + * @param null $cycleAmount + * @param string $type + * @param string $frequency + * @param int $frequencyInterval + * @param int $cycles + * @return PaymentDefinition + * @throws Exception + */ + public function createPaymentDefinition(Order $order, $name, array $chargeModels = [], $cycleAmount = null, string $type = self::PAYMENT_TYPE_REGULAR, string $frequency = self::PAYMENT_FREQUENCY_DAY, int $frequencyInterval = 1, int $cycles = 1) + { + if (!in_array($type, self::getAllowedPaymentType())) { + $message = Translator::getInstance()->trans( + 'Invalid payment type send to create payment definition', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + if (!in_array($frequency, self::getAllowedPaymentFrequency())) { + $message = Translator::getInstance()->trans( + 'Invalid payment frequency send to create payment definition', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + if (!is_array($chargeModels) || count($chargeModels) <= 0) { + $message = Translator::getInstance()->trans( + 'Invalid number of charge models send to create payment definition', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + $paymentDefinition = new PaymentDefinition(); + + if (null === $cycleAmount) { + $totalAmount = $order->getTotalAmount(); + $cycleAmount = round($totalAmount / $cycles, 2); + } + + $paymentDefinition + ->setName(substr($name, 0, self::MAX_API_LENGHT)) + ->setType($type) + ->setFrequency($frequency) + ->setFrequencyInterval($frequencyInterval) + ->setCycles($cycles) + ->setAmount(new Currency(['value' => $cycleAmount, 'currency' => self::getOrderCurrencyCode($order)])) + ->setChargeModels($chargeModels) + ; + + return $paymentDefinition; + } + + /** + * @param Order $order + * @param int $chargeAmount + * @param string $type + * @return ChargeModel + * @throws Exception + */ + public function createChargeModel(Order $order, int $chargeAmount = 0, string $type = self::CHARGE_TYPE_SHIPPING) + { + if (!in_array($type, self::getAllowedChargeType())) { + $message = Translator::getInstance()->trans( + 'Invalid charge type send to create charge model', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + $chargeModel = new ChargeModel(); + $chargeModel + ->setType($type) + ->setAmount(new Currency(['value' => $chargeAmount, 'currency' => self::getOrderCurrencyCode($order)])) + ; + + return $chargeModel; + } + + /** + * @param Order $order + * @param bool $autoBillAmount + * @param string $failAction + * @param int $maxFailAttempts + * @param int $feeAmount + * @return MerchantPreferences + * @throws Exception + */ + public function createMerchantPreferences(Order $order, bool $autoBillAmount = false, string $failAction = self::FAIL_AMOUNT_ACTION_CONTINUE, int $maxFailAttempts = 0, int $feeAmount = 0) + { + if (!in_array($failAction, self::getAllowedFailedAction())) { + $message = Translator::getInstance()->trans( + 'Invalid fail action send to create merchant preference', + [], + PayPal::DOMAIN_NAME + ); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::ERROR + ); + throw new Exception($message); + } + + $merchantPreferences = new MerchantPreferences(); + + $urlOk = URL::getInstance()->absoluteUrl( + $this->router->generate( + "paypal.agreement.ok", + [ + 'orderId' => $order->getId() + ], + Router::ABSOLUTE_URL + ) + ); + $urlKo = URL::getInstance()->absoluteUrl( + $this->router->generate( + "paypal.agreement.ko", + [ + 'orderId' => $order->getId() + ], + Router::ABSOLUTE_URL + ) + ); + + if ($autoBillAmount) { + $autoBillAmountStr = 'YES'; + } else { + $autoBillAmountStr = 'NO'; + } + + $merchantPreferences + ->setReturnUrl($urlOk) + ->setCancelUrl($urlKo) + ->setAutoBillAmount($autoBillAmountStr) + ->setInitialFailAmountAction($failAction) + ->setMaxFailAttempts($maxFailAttempts) + ->setSetupFee(new Currency(['value' => $feeAmount, 'currency' => self::getOrderCurrencyCode($order)])) + ; + + return $merchantPreferences; + } + + /** + * @param Order $order + * @return Order + * @throws Exception + * @throws PropelException + */ + public function duplicateOrder(Order $order) + { + $today = new Datetime; + $newOrder = new Order(); + $newOrder + ->setCustomerId($order->getCustomerId()) + ->setInvoiceOrderAddressId($order->getInvoiceOrderAddressId()) + ->setDeliveryOrderAddressId($order->getDeliveryOrderAddressId()) + ->setInvoiceDate($today->format('Y-m-d H:i:s')) + ->setCurrencyId($order->getCurrencyId()) + ->setCurrencyRate($order->getCurrencyRate()) + ->setDeliveryRef($order->getDeliveryRef()) + ->setInvoiceRef($order->getInvoiceRef()) + ->setDiscount($order->getDiscount()) + ->setPostage($order->getPostage()) + ->setPostageTax($order->getPostageTax()) + ->setPostageTaxRuleTitle($order->getPostageTaxRuleTitle()) + ->setPaymentModuleId($order->getPaymentModuleId()) + ->setDeliveryModuleId($order->getDeliveryModuleId()) + ->setStatusId($order->getStatusId()) + ->setLangId($order->getLangId()) + ->setCartId($order->getCartId()) + ->save() + ; + + $orderProducts = OrderProductQuery::create()->filterByOrderId($order->getId())->find(); + + /** @var OrderProduct $orderProduct */ + foreach ($orderProducts as $orderProduct) { + $newOrderProduct = new OrderProduct(); + $newOrderProduct + ->setOrderId($newOrder->getId()) + ->setProductRef($orderProduct->getProductRef()) + ->setProductSaleElementsRef($orderProduct->getProductSaleElementsRef()) + ->setProductSaleElementsId($orderProduct->getProductSaleElementsId()) + ->setTitle($orderProduct->getTitle()) + ->setChapo($orderProduct->getChapo()) + ->setDescription($orderProduct->getDescription()) + ->setPostscriptum($orderProduct->getPostscriptum()) + ->setQuantity($orderProduct->getQuantity()) + ->setPrice($orderProduct->getPrice()) + ->setPromoPrice($orderProduct->getPromoPrice()) + ->setWasNew($orderProduct->getWasNew()) + ->setWasInPromo($orderProduct->getWasInPromo()) + ->setWeight($orderProduct->getWeight()) + ->setEanCode($orderProduct->getEanCode()) + ->setTaxRuleTitle($orderProduct->getTaxRuleTitle()) + ->setTaxRuleDescription($orderProduct->getTaxRuleDescription()) + ->setParent($orderProduct->getParent()) + ->setVirtual($orderProduct->getVirtual()) + ->setVirtualDocument($orderProduct->getVirtualDocument()) + ->save() + ; + + $orderProductTaxes = OrderProductTaxQuery::create()->filterByOrderProductId($orderProduct->getId())->find(); + + /** @var OrderProductTax $orderProductTax */ + foreach ($orderProductTaxes as $orderProductTax) { + + $newOrderProductTax = new OrderProductTax(); + $newOrderProductTax + ->setOrderProductId($newOrderProduct->getId()) + ->setTitle($orderProductTax->getTitle()) + ->setDescription($orderProductTax->getDescription()) + ->setAmount($orderProductTax->getAmount()) + ->setPromoAmount($orderProductTax->getPromoAmount()) + ->save() + ; + } + } + + if (null !== $payPalOrder = PaypalOrderQuery::create()->findOneById($order->getId())) { + $newPayPalOrder = new PaypalOrder(); + $newPayPalOrder + ->setId($newOrder->getId()) + ->setPaymentId($payPalOrder->getPaymentId()) + ->setAgreementId($payPalOrder->getAgreementId()) + ->setCreditCardId($payPalOrder->getCreditCardId()) + ->setState($payPalOrder->getState()) + ->setAmount($payPalOrder->getAmount()) + ->setDescription($payPalOrder->getDescription()) + ->setPayerId($payPalOrder->getPayerId()) + ->setToken($payPalOrder->getToken()) + ; + $newPayPalOrderEvent = new PayPalOrderEvent($newPayPalOrder); + $this->dispatcher->dispatch($newPayPalOrderEvent, PayPalEvents::PAYPAL_ORDER_CREATE); + + $payPalPlans = PaypalPlanQuery::create()->filterByPaypalOrderId($payPalOrder->getId()); + + /** @var PaypalPlan $payPalPlan */ + foreach ($payPalPlans as $payPalPlan) { + + $newPayPalPlan = new PaypalPlan(); + $newPayPalPlan + ->setPaypalOrderId($newPayPalOrderEvent->getPayPalOrder()->getId()) + ->setPlanId($payPalPlan->getPlanId()) + ->setState($payPalPlan->getState()) + ; + + $newPayPalPlanEvent = new PayPalPlanEvent($newPayPalPlan); + $this->dispatcher->dispatch($newPayPalPlanEvent, PayPalEvents::PAYPAL_PLAN_CREATE); + } + } + + return $newOrder; + } + + /** + * @param Order $order + * @param Plan $plan + * @param Payer $payer + * @param $name + * @param string $description + * @return Agreement + * @throws Exception + */ + public function generateAgreement(Order $order, Plan $plan, Payer $payer, $name, string $description = '') + { + $agreement = new Agreement(); + $agreement + ->setName($name) + ->setDescription($description) + ->setStartDate((new Datetime)->format('Y-m-d\TG:i:s\Z')) + ->setPlan($plan) + ; + + //Add Payer to Agreement + $agreement + ->setPayer($payer) + ->setShippingAddress(self::generateShippingAddress($order)) + ; + + return $agreement; + } + + /** + * @param Order $order + * @return string + */ + public static function getOrderCurrencyCode(Order $order) + { + if (null === $currency = CurrencyQuery::create()->findOneById($order->getCurrencyId())) { + $currency = \Thelia\Model\Currency::getDefaultCurrency(); + } + + return $currency->getCode(); + } + + /** + * @return array + */ + public static function getAllowedPlanType() + { + return [ + self::PLAN_TYPE_FIXED, + self::PLAN_TYPE_INFINITE + ]; + } + + /** + * @return array + */ + public static function getAllowedPaymentType() + { + return [ + self::PAYMENT_TYPE_REGULAR, + self::PAYMENT_TYPE_TRIAL + ]; + } + + /** + * @return array + */ + public static function getAllowedChargeType() + { + return [ + self::CHARGE_TYPE_SHIPPING, + self::CHARGE_TYPE_TAX + ]; + } + + /** + * @return array + */ + public static function getAllowedPaymentFrequency() + { + return [ + self::PAYMENT_FREQUENCY_DAY => self::PAYMENT_FREQUENCY_DAY, + self::PAYMENT_FREQUENCY_WEEK => self::PAYMENT_FREQUENCY_WEEK, + self::PAYMENT_FREQUENCY_MONTH => self::PAYMENT_FREQUENCY_MONTH, + self::PAYMENT_FREQUENCY_YEAR => self::PAYMENT_FREQUENCY_YEAR + ]; + } + + /** + * @return array + */ + public static function getAllowedFailedAction() + { + return [ + self::FAIL_AMOUNT_ACTION_CANCEL, + self::FAIL_AMOUNT_ACTION_CONTINUE + ]; + } +} diff --git a/domokits/local/modules/PayPal/Service/PayPalCustomerService.php b/domokits/local/modules/PayPal/Service/PayPalCustomerService.php new file mode 100644 index 0000000..d3707b4 --- /dev/null +++ b/domokits/local/modules/PayPal/Service/PayPalCustomerService.php @@ -0,0 +1,164 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Service; + +use Monolog\Logger; +use PayPal\Api\OpenIdSession; +use PayPal\Api\OpenIdTokeninfo; +use PayPal\Api\OpenIdUserinfo; +use PayPal\Model\PaypalCustomer; +use PayPal\Model\PaypalCustomerQuery; +use PayPal\Service\Base\PayPalBaseService; +use Thelia\Core\Security\SecurityContext; + +/** + * Class PayPalCustomerService + * @package PayPal\Service + */ +class PayPalCustomerService +{ + /** @var SecurityContext */ + protected $securityContext; + + /** + * PayPalService constructor. + * @param SecurityContext $securityContext + */ + public function __construct(SecurityContext $securityContext) + { + $this->securityContext = $securityContext; + } + + /** + * @param $authorizationCode + * @return OpenIdUserinfo + * @throws \Exception + */ + public function getUserInfoWithAuthorizationCode($authorizationCode) + { + try { + $accessToken = OpenIdTokeninfo::createFromAuthorizationCode( + ['code' => $authorizationCode], + null, + null, + PayPalBaseService::getApiContext() + ); + + return $this->getUserInfo($accessToken->getAccessToken()); + } catch (\Exception $ex) { + PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR); + throw $ex; + } + } + + /** + * @param $accessToken + * @return OpenIdUserinfo + */ + public function getUserInfo($accessToken) + { + $params = array('access_token' => $accessToken); + $userInfo = OpenIdUserinfo::getUserinfo($params, PayPalBaseService::getApiContext()); + + return $userInfo; + } + + /** + * @return PaypalCustomer + */ + public function getCurrentPayPalCustomer() + { + $payPalCustomer = new PaypalCustomer(); + + if (null !== $customer = $this->securityContext->getCustomerUser()) { + + $payPalCustomer = PaypalCustomerQuery::create()->findOneById($customer->getId()); + + } + + return $payPalCustomer; + } + + /** + * @param $refreshToken + * @return OpenIdTokeninfo + * @throws \Exception + */ + public function generateAccessTokenFromRefreshToken($refreshToken) + { + try { + $tokenInfo = new OpenIdTokeninfo(); + $tokenInfo = $tokenInfo->createFromRefreshToken(['refresh_token' => $refreshToken], PayPalBaseService::getApiContext()); + + return $tokenInfo; + } catch (\Exception $ex) { + PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR); + throw $ex; + } + } + + /** + * @param $refreshToken + * @return OpenIdUserinfo + * @throws \Exception + */ + public function getUserInfoWithRefreshToken($refreshToken) + { + try { + $tokenInfo = $this->generateAccessTokenFromRefreshToken($refreshToken); + + return $this->getUserInfo($tokenInfo->getAccessToken()); + } catch (\Exception $ex) { + PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR); + throw $ex; + } + } + + /** + * @return string + */ + public function getUrlToRefreshToken() + { + //Get Authorization URL returns the redirect URL that could be used to get user's consent + $redirectUrl = OpenIdSession::getAuthorizationUrl( + 'http://25b3ee89.ngrok.io/', + [ + 'openid', + 'profile', + 'address', + 'email', + 'phone', + 'https://uri.paypal.com/services/paypalattributes', + 'https://uri.paypal.com/services/expresscheckout', + 'https://uri.paypal.com/services/invoicing' + ], + null, + null, + null, + PayPalBaseService::getApiContext() + ); + + return $redirectUrl; + } +} diff --git a/domokits/local/modules/PayPal/Service/PayPalLoggerService.php b/domokits/local/modules/PayPal/Service/PayPalLoggerService.php new file mode 100644 index 0000000..3a3556b --- /dev/null +++ b/domokits/local/modules/PayPal/Service/PayPalLoggerService.php @@ -0,0 +1,128 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Service; + +use Datetime; +use Monolog\Logger; +use MySQLHandler\MySQLHandler; +use PayPal\Model\Map\PaypalLogTableMap; +use PayPal\Model\PaypalLogQuery; +use PayPal\PayPal; +use Propel\Runtime\Exception\PropelException; +use Propel\Runtime\Propel; +use Thelia\Install\Database; + +/** + * Class PayPalLoggerService + * @package PayPal\Service + */ +class PayPalLoggerService +{ + /** + * @param $message + * @param array $params + * @param int $level + * @throws PropelException + */ + public static function log($message, array $params = [], int $level = Logger::DEBUG) + { + $staticParams = self::getStaticParams(); + + $logger = new Logger(PayPal::getModuleCode()); + + //Create MysqlHandler + $mySQLHandler = new MyOwnSQLHandler( + Propel::getConnection()->getWrappedConnection(), + PaypalLogTableMap::TABLE_NAME, + array_keys($staticParams), + $level + ); + + $logger->pushHandler($mySQLHandler); + + //Now you can use the logger, and further attach additional information + switch ($level) { + case Logger::INFO: + $logger->addRecord(LOG_INFO,$message, array_merge($staticParams, $params)); + break; + + case Logger::NOTICE: + $logger->addRecord(LOG_NOTICE,$message, array_merge($staticParams, $params)); + break; + + case Logger::WARNING: + $logger->addRecord(LOG_WARNING,$message, array_merge($staticParams, $params)); + break; + + case Logger::ERROR: + $logger->addRecord(LOG_ERR,$message, array_merge($staticParams, $params)); + break; + + case Logger::CRITICAL: + $logger->addRecord(LOG_CRIT,$message, array_merge($staticParams, $params)); + break; + + case Logger::ALERT: + $logger->addRecord(LOG_ALERT,$message, array_merge($staticParams, $params)); + break; + + case Logger::EMERGENCY: + $logger->addRecord(LOG_EMERG,$message, array_merge($staticParams, $params)); + break; + + default: + $logger->addRecord(LOG_DEBUG,$message, array_merge($staticParams, $params)); + break; + } + + } + + /** + * @return array + * @throws \Propel\Runtime\Exception\PropelException + */ + public static function getStaticParams() + { + $psr3Fields = ['channel', 'level', 'message', 'time']; + $payPalLogFields = PaypalLogTableMap::getFieldNames(PaypalLogTableMap::TYPE_FIELDNAME); + $readableDate = new Datetime(); + + $staticParams = []; + foreach ($payPalLogFields as $fieldName) { + + // Do not interpret psr3 fields + if (in_array($fieldName, $psr3Fields)) { + continue; + } + + if (in_array($fieldName, ['created_at', 'updated_at'])) { + $staticParams[$fieldName] = $readableDate->format('Y-m-d H:i:s'); + } else { + $staticParams[$fieldName] = null; + } + } + + return $staticParams; + } +} diff --git a/domokits/local/modules/PayPal/Service/PayPalPaymentService.php b/domokits/local/modules/PayPal/Service/PayPalPaymentService.php new file mode 100644 index 0000000..90dfdc3 --- /dev/null +++ b/domokits/local/modules/PayPal/Service/PayPalPaymentService.php @@ -0,0 +1,417 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace PayPal\Service; + +use Exception; +use Monolog\Logger; +use PayPal\Api\Amount; +use PayPal\Api\CreditCard; +use PayPal\Api\CreditCardToken; +use PayPal\Api\Details; +use PayPal\Api\FundingInstrument; +use PayPal\Api\FuturePayment; +use PayPal\Api\OpenIdTokeninfo; +use PayPal\Api\Payer; +use PayPal\Api\Payment; +use PayPal\Api\PaymentExecution; +use PayPal\Api\RedirectUrls; +use PayPal\Api\Transaction; +use PayPal\Exception\PayPalConnectionException; +use PayPal\PayPal; +use PayPal\Service\Base\PayPalBaseService; +use Propel\Runtime\Exception\PropelException; +use Thelia\Core\Translation\Translator; +use Thelia\Model\Cart; +use Thelia\Model\Currency; +use Thelia\Model\CurrencyQuery; +use Thelia\Model\Order; +use Thelia\Tools\URL; + + +/** + * Class PayPalPaymentService + * @package PayPal\Service + */ +class PayPalPaymentService extends PayPalBaseService +{ + /** + * Create a payment using a previously obtained + * credit card id. The corresponding credit + * card is used as the funding instrument. + * + * @param Order $order + * @param bool $future + * @param string|null $creditCardId + * @param string|null $description + * @return Payment + * @throws PropelException|PayPalConnectionException + */ + public function makePayment(Order $order, ?string $creditCardId = null, ?string $description = null, bool $future = false) + { + $payPalOrderEvent = $this->generatePayPalOrder($order); + + if (null !== $creditCardId) { + $creditCardToken = new CreditCardToken(); + $creditCardToken->setCreditCardId($creditCardId); + + $fundingInstrument = new FundingInstrument(); + $fundingInstrument->setCreditCardToken($creditCardToken); + + $payer = self::generatePayer(PayPal::PAYPAL_METHOD_CREDIT_CARD, [$fundingInstrument]); + } else { + $payer = self::generatePayer(); + } + + // Specify the payment amount. + if (null === $currency = CurrencyQuery::create()->findOneById($order->getCurrencyId())) { + $currency = Currency::getDefaultCurrency(); + } + + $amount = $this->generateAmount($order, $currency); + + $transaction = $this->generateTransaction($amount, $description); + + $payment = $this->generatePayment($order, $payer, $transaction, $future); + + $this->updatePayPalOrder($payPalOrderEvent->getPayPalOrder(), $payment->getState(), $payment->getId()); + + return $payment; + } + + /** + * @throws PayPalConnectionException + * @throws PropelException + */ + public function makePaymentFromCart(Cart $cart, $description = null, $future = false, $fromCartView = true) + { + $payer = self::generatePayer(); + + // Specify the payment amount. + if (null === $currency = CurrencyQuery::create()->findOneById($cart->getCurrencyId())) { + $currency = Currency::getDefaultCurrency(); + } + + $amount = $this->generateAmountFromCart($cart, $currency); + + $transaction = $this->generateTransaction($amount, $description); + + $payment = $this->generatePaymentFromCart($cart, $payer, $transaction, $future, $fromCartView); + + return $payment; + } + + /** + * Completes the payment once buyer approval has been + * obtained. Used only when the payment method is 'paypal' + * + * @param string $paymentId id of a previously created + * payment that has its payment method set to 'paypal' + * and has been approved by the buyer. + * + * @param string $payerId PayerId as returned by PayPal post + * buyer approval. + * + * @return Payment + */ + public function executePayment(string $paymentId, string $payerId, Details $details = null) + { + $payment = $this->getPaymentDetails($paymentId); + $paymentExecution = new PaymentExecution(); + $paymentExecution->setPayerId($payerId); + + if (null !== $details) { + $amount = new Amount(); + $totalDetails = (float)$details->getShipping() + (float)$details->getTax() + (float)$details->getSubtotal(); + $amount + ->setCurrency('EUR') + ->setTotal($totalDetails) + ->setDetails($details) + ; + + $transaction = new Transaction(); + $transaction->setAmount($amount); + + $paymentExecution->addTransaction($transaction); + } + + $payment = $payment->execute($paymentExecution, self::getApiContext()); + + return $payment; + } + + public function createDetails($shipping = 0, $shippingTax = 0, $subTotal = 0) + { + $details = new Details(); + $details + ->setShipping($shipping) + ->setTax($shippingTax) + ->setSubtotal($subTotal) + ; + + return $details; + } + + /** + * Retrieves the payment information based on PaymentID from Paypal APIs + * + * @param $paymentId + * + * @return Payment + */ + public function getPaymentDetails($paymentId) + { + $payment = Payment::get($paymentId, self::getApiContext()); + + return $payment; + } + + /** + * @param $authorizationCode + * @return OpenIdTokeninfo + * @throws PayPalConnectionException + */ + public function generateAccessToken($authorizationCode) + { + try { + // Obtain Authorization Code from Code, Client ID and Client Secret + $accessToken = OpenIdTokeninfo::createFromAuthorizationCode( + ['code' => $authorizationCode], + null, + null, + self::getApiContext() + ); + + return $accessToken; + } catch (PayPalConnectionException $ex) { + PayPalLoggerService::log($ex->getMessage(), [], Logger::ERROR); + throw $ex; + } + } + + /** + * @param $type + * @param $number + * @param $expireMonth + * @param $expireYear + * @param $cvv2 + * @return string + * @throws Exception + */ + public function getPayPalCreditCardId($type, $number, $expireMonth, $expireYear, $cvv2) + { + try { + $card = new CreditCard(); + $card->setType($type); + $card->setNumber((int)$number); + $card->setExpireMonth((int)$expireMonth); + $card->setExpireYear((int)$expireYear); + $card->setCvv2($cvv2); + + $card->create(self::getApiContext()); + + return $card->getId(); + } catch (Exception $e) { + PayPalLoggerService::log($e->getMessage(), [], Logger::ERROR); + throw new Exception(Translator::getInstance()->trans('Credit card is invalid', [], PayPal::DOMAIN_NAME)); + } + } + + /** + * @param Order $order + * @param Payer $payer + * @param Transaction $transaction + * @param bool $future + * @return FuturePayment|Payment + * @throws PayPalConnectionException + * @throws Exception + */ + public function generatePayment(Order $order, Payer $payer, Transaction $transaction, $future = false) + { + if ($future) { + $payment = new FuturePayment(); + $payment->setIntent('authorize'); + } else { + $payment = new Payment(); + $payment->setIntent('sale'); + } + + $payment + ->setRedirectUrls($this->getRedirectUrls($order)) + ->setPayer($payer) + ->setTransactions([$transaction]) + ; + + $clientMetadataId = '123123456'; + + try { + + if ($future) { + + //$authorizationCode = self::getAuthorizationCode(); + $refreshToken = $this->getRefreshToken(); + //$refreshToken = FuturePayment::getRefreshToken($this->getAuthorizationCode(), self::getApiContext()); + $payment->updateAccessToken($refreshToken, self::getApiContext()); + $payment->create(self::getApiContext(), $clientMetadataId); + + } else { + $payment->create(self::getApiContext()); + } + + return $payment; + + } catch (PayPalConnectionException $e) { + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } catch (Exception $e) { + PayPalLoggerService::log( + $e->getMessage(), + [ + 'customer_id' => $order->getCustomerId(), + 'order_id' => $order->getId() + ], + Logger::CRITICAL + ); + throw $e; + } + } + + /** + * @param Cart $cart + * @param Payer $payer + * @param Transaction $transaction + * @param bool $future + * @param bool $fromCartView + * @return FuturePayment|Payment + * @throws PayPalConnectionException + * @throws Exception + */ + public function generatePaymentFromCart(Cart $cart, Payer $payer, Transaction $transaction, bool $future = false, bool $fromCartView = true) + { + if ($future) { + $payment = new FuturePayment(); + $payment->setIntent('authorize'); + } else { + $payment = new Payment(); + $payment->setIntent('sale'); + } + + if ($fromCartView) { + $payment->setRedirectUrls($this->getRedirectCartUrls($cart)); + } else { + $payment->setRedirectUrls($this->getRedirectInvoiceUrls($cart)); + } + $payment + ->setPayer($payer) + ->setTransactions([$transaction]) + ; + + $clientMetadataId = '123123456'; + + try { + + if ($future) { + + //$authorizationCode = self::getAuthorizationCode(); + $refreshToken = $this->getRefreshToken(); + //$refreshToken = FuturePayment::getRefreshToken($this->getAuthorizationCode(), self::getApiContext()); + $payment->updateAccessToken($refreshToken, self::getApiContext()); + $payment->create(self::getApiContext(), $clientMetadataId); + + } else { + $payment->create(self::getApiContext()); + } + + return $payment; + + } catch (PayPalConnectionException $e) { + $message = sprintf('url : %s. data : %s. message : %s', $e->getUrl(), $e->getData(), $e->getMessage()); + PayPalLoggerService::log( + $message, + [], + Logger::CRITICAL + ); + throw $e; + } catch (Exception $e) { + PayPalLoggerService::log( + $e->getMessage(), + [], + Logger::CRITICAL + ); + throw $e; + } + } + + /** + * @param Order $order + * @return RedirectUrls + */ + public function getRedirectUrls(Order $order) + { + $redirectUrls = new RedirectUrls(); + $urlOk = URL::getInstance()->absoluteUrl('/module/paypal/ok/' . $order->getId()); + $urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/cancel/' . $order->getId()); + $redirectUrls->setReturnUrl($urlOk); + $redirectUrls->setCancelUrl($urlCancel); + + return $redirectUrls; + } + + /** + * @param Cart $cart + * @return RedirectUrls + */ + public function getRedirectCartUrls(Cart $cart) + { + $redirectUrls = new RedirectUrls(); + $urlOk = URL::getInstance()->absoluteUrl('/module/paypal/express/checkout/ok/' . $cart->getId()); + $urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/express/checkout/ko/' . $cart->getId()); + $redirectUrls->setReturnUrl($urlOk); + $redirectUrls->setCancelUrl($urlCancel); + + return $redirectUrls; + } + + /** + * @param Cart $cart + * @return RedirectUrls + */ + public function getRedirectInvoiceUrls(Cart $cart) + { + $redirectUrls = new RedirectUrls(); + $urlOk = URL::getInstance()->absoluteUrl('/module/paypal/invoice/express/checkout/ok/' . $cart->getId()); + $urlCancel = URL::getInstance()->absoluteUrl('/module/paypal/invoice/express/checkout/ko/' . $cart->getId()); + $redirectUrls->setReturnUrl($urlOk); + $redirectUrls->setCancelUrl($urlCancel); + + return $redirectUrls; + } +} diff --git a/domokits/local/modules/PayPal/composer.json b/domokits/local/modules/PayPal/composer.json new file mode 100644 index 0000000..1201cc9 --- /dev/null +++ b/domokits/local/modules/PayPal/composer.json @@ -0,0 +1,14 @@ +{ + "name": "thelia/paypal-module", + "description": "PayPal module for Thelia ecommerce solution ", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1", + "cqfdev/paypal-rest-api-sdk-php": "1.*", + "wazaari/monolog-mysql": "1.0.5" + }, + "extra": { + "installer-name": "PayPal" + } +} diff --git a/domokits/local/modules/PayPal/images/logo.png b/domokits/local/modules/PayPal/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1fe1879f418eef9825666c9eaacd02c6945c7356 GIT binary patch literal 4196 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 IM6N<$f)S)~fB*mh literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/images/payment_credit_card.png b/domokits/local/modules/PayPal/images/payment_credit_card.png new file mode 100644 index 0000000000000000000000000000000000000000..142d268c7be01eb50ce20c9a2ae43e6d5f2b86d8 GIT binary patch literal 41931 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/images/payment_express_checkout.png b/domokits/local/modules/PayPal/images/payment_express_checkout.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f4237e45c85144903cae1b96f4073d3e824c81 GIT binary patch literal 117713 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

bIf_n22-t+YHo}*R65;D_2X;knX|QF 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 NQa|Ly%0=}3{tqywac}?t literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/images/payment_recursive.png b/domokits/local/modules/PayPal/images/payment_recursive.png new file mode 100644 index 0000000000000000000000000000000000000000..2f62d0ae7f4d969062cdd91b1bad7b99816be810 GIT binary patch literal 21604 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 H_JI69xbDzm literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf1.png b/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf1.png new file mode 100644 index 0000000000000000000000000000000000000000..7904991fdbb7d9209838abb66e7b7e868a7996e9 GIT binary patch literal 17985 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 IM6N<$f)v#_mH+?% literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf2.png b/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_conf2.png new file mode 100644 index 0000000000000000000000000000000000000000..47dad7a159f1b4575dcd0222566c39ee22693111 GIT binary patch literal 26728 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 & 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

mE2 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_webhook.png b/domokits/local/modules/PayPal/templates/backOffice/default/assets/paypal_webhook.png new file mode 100644 index 0000000000000000000000000000000000000000..419d33c75fd8634136a9707342d45c302730006f GIT binary patch literal 17997 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/form/create-or-update-planified-payment-form.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/form/create-or-update-planified-payment-form.html new file mode 100644 index 0000000..454fa4f --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/form/create-or-update-planified-payment-form.html @@ -0,0 +1,38 @@ +{render_form_field field="locale"} +

+
+ {intl l="Global informations of this planified payment" d="paypal.bo.default"} +
+
+
+
+ {render_form_field field="title"} +
+
+
+
+ {render_form_field field="description"} +
+
+
+
+ {render_form_field field="frequency_interval"} +
+
+ {render_form_field field="frequency"} +
+
+ {render_form_field field="cycle"} +
+
+ +
+
+ {render_form_field field="min_amount"} +
+
+ {render_form_field field="max_amount"} +
+
+
+
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row-js.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row-js.html new file mode 100644 index 0000000..c4fef9f --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row-js.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row.html new file mode 100644 index 0000000..7d7acd7 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/includes/paypal-log-row.html @@ -0,0 +1,20 @@ +getHook()} style="cursor: pointer;"{/if}> + + {format_date date=$CREATE_DATE} + + {if $log->getHook()} + {$log->getHook()} ({intl l="See webhook details" d="paypal.bo.default"}) + + {else} + {$log->getMessage() nofilter} + {/if} + +
{$log->getCustomerId()} + getOrderId()}">{$log->getOrderId()} + + {$log->getHook()} + + {intl l="critical_{$log->getLevel()}" d="paypal.bo.default"} + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/menu/menu.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/menu/menu.html new file mode 100644 index 0000000..213691f --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/menu/menu.html @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/module-configuration.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/module-configuration.html new file mode 100644 index 0000000..781815a --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/module-configuration.html @@ -0,0 +1,236 @@ +
+
+
+ + {include file="paypal/menu/menu.html" selectedMenu="general"} + +
+ +
+ + {form name="paypal_form_configure"} + + {if $form_error|default:null} +
{$form_error_message}
+ {elseif $general_error|default:null} +
+ {$general_error} +
+ {/if} + + + {form_hidden_fields form=$form} +
+
+ {include file = "includes/inner-form-toolbar.html" + hide_flags = true + page_url = "{url path='/admin/module/Paypal'}" + close_url = "{url path='/admin/modules'}" + } +
+
+
+
+
+

+ 1 + {intl l="SandBox configuration" d="paypal.bo.default"} + +

+
+
+
+ Payment configuration +
+
+
+
+ + {custom_render_form_field form=$form field="sandbox"} + + {$label} + {/custom_render_form_field} + + {render_form_field form=$form field="sandbox_login" value=$sandbox_login|default:null} + {render_form_field form=$form field="sandbox_password" value=$sandbox_password|default:null} + {render_form_field form=$form field="sandbox_merchant_id" value=$sandbox_merchant_id|default:null} + + {render_form_field form=$form field="allowed_ip_list" value={$allowed_ip_list|default:null}} +
+
+
+
+

+  {intl l="Help" d="paypal.bo.default"} : {intl l="Configuration" d="paypal.bo.default"} +

+ - {intl l="Log In on developer.paypal.com" d="paypal.bo.default"}
+ - {intl l="Create REST API apps here" d="paypal.bo.default"}
+ - {intl l="Click on Create App" d="paypal.bo.default"}
+ - {intl l="Fill the fields : App Name & Sandbox developer account" d="paypal.bo.default"}
+ - {intl l="Click on Create App" d="paypal.bo.default"}
+ - {intl l="Copy & Paste the Client ID in the form below" d="paypal.bo.default"}
+ - {intl l="Copy & Paste the Client SECRET in the form below" d="paypal.bo.default"}
+ - {intl l="In SANDBOX WEBHOOKS" d="paypal.bo.default"} :
+ -     {intl l="Add Webhook" d="paypal.bo.default"}
+ -         {url path="/module/paypal/webhook/all/events"}
+ -         {intl l="Check 'All events'" d="paypal.bo.default"}
+ - {intl l="In SANDBOX APP SETTINGS" d="paypal.bo.default"} :
+ -     {intl l="Return URL" d="paypal.bo.default"}
+ -         {navigate to="index"}
+ -         {url path="/module/paypal/login/ok"}
+ -         {url path="/module/paypal/agreement/ok"}
+ -         {url path="/module/paypal/agreement/ko"}
+ -
+ - {intl l="Check" d="paypal.bo.default"} {intl l="Accept payments" d="paypal.bo.default"} 
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Future Payments" d="paypal.bo.default"}
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Billing agreements" d="paypal.bo.default"}
+ - {intl l="Check" d="paypal.bo.default"} {intl l="Invoicing" d="paypal.bo.default"} 
+ - {intl l="Check" d="paypal.bo.default"} {intl l="Payouts" d="paypal.bo.default"} 
+ - {intl l="Check" d="paypal.bo.default"} {intl l="PayPal Here" d="paypal.bo.default"} 
+ - {intl l="Check" d="paypal.bo.default"} {intl l="Log In with PayPal" d="paypal.bo.default"} 
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Personal Information" d="paypal.bo.default"}
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Address Information" d="paypal.bo.default"}
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Account Information" d="paypal.bo.default"}
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Use Seamless Checkout" d="paypal.bo.default"}
+ -     {intl l="Check" d="paypal.bo.default"} {intl l="Allow the customers who haven't yet confirmed their email address with PayPal, to log in to your app" d="paypal.bo.default"}
+ - {intl l="That's it !" d="paypal.bo.default"}
+
+
+
+
+
+

+ 2 + {intl l="Production configuration" d="paypal.bo.default"} +

+
+
+
+ Payment configuration +
+
+
+
+ {render_form_field form=$form field="login" value=$login|default:null} + {render_form_field form=$form field="password" value=$password|default:null} + {render_form_field form=$form field="merchant_id" value=$merchant_id|default:null} +
+
+
+
+

+  {intl l="Help" d="paypal.bo.default"} : {intl l="Configuration" d="paypal.bo.default"} +

+ - {intl l="In your PayPal page API configuration" d="paypal.bo.default"}
+ - {intl l="Click on the Live Button" d="paypal.bo.default"}
+ Payment configuration
+ - {intl l="And configure it like the SandBox" d="paypal.bo.default"}
+
+
+
+
+

+ 3 + {intl l="Payment configuration" d="paypal.bo.default"} +

+ +
+
+ Payment configuration +
+
+ {custom_render_form_field form=$form field="method_paypal"} + + {$label} + {/custom_render_form_field} + + {custom_render_form_field form=$form field="method_paypal_with_in_context"} + + {$label} + {/custom_render_form_field} + + {custom_render_form_field form=$form field="method_express_checkout"} + + {$label} + {/custom_render_form_field} + + {custom_render_form_field form=$form field="method_credit_card"} + + {$label} + {/custom_render_form_field} + +
+ + {intl d='paypal.bo.default' l='This method works only with PayPal PRO UK account. Please contact PayPal to upgrade your account if you need this service. For more informations, go here'} +
+ + {custom_render_form_field form=$form field="method_planified_payment"} + + {$label} + {/custom_render_form_field} + +
+ + {intl d='paypal.bo.default' l='This method use PayPal webhooks and works only in HTTPS !'} +
+ +
+ + {intl d='paypal.bo.default' l='You can add some planified payment here.' url={url path="/admin/module/paypal/configure/planified"}} +
+ + {custom_render_form_field form=$form field="send_confirmation_message_only_if_paid"} + + {$label} + {/custom_render_form_field} + + {custom_render_form_field form=$form field="send_payment_confirmation_message"} + + {$label} + {/custom_render_form_field} + + {custom_render_form_field form=$form field="send_recursive_message"} + + {$label} + {/custom_render_form_field} + +
+ + {intl d='paypal.bo.default' l='You can edit the payment confirmation email sent to the customer after a successful payment.' url={url path="/admin/configuration/messages"}} +
+ + {custom_render_form_field form=$form field="minimum_amount"} +
+ + {currency attr='symbol'} +
+ {/custom_render_form_field} + + {custom_render_form_field form=$form field="maximum_amount"} +
+ + {currency attr='symbol'} +
+ {/custom_render_form_field} + + {render_form_field form=$form field="cart_item_count" value=$cart_item_count} +
+
+
+
+
+
+ {include file = "includes/inner-form-toolbar.html" + hide_flags = true + page_url = "{url path='/admin/module/Paypal'}" + close_url = "{url path='/admin/modules'}" + } +
+
+ + {/form} +
+
+
+
+
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/order-edit-js.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/order-edit-js.html new file mode 100644 index 0000000..3a1e2f3 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/order-edit-js.html @@ -0,0 +1 @@ +{include file = "paypal/includes/paypal-log-row-js.html"} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/payment-information.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/payment-information.html new file mode 100644 index 0000000..52fda46 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/payment-information.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + {loop name="paypal_log" type="paypal_log" backend_context=true order_id=$order_id order="date-reverse"} + {include file = "paypal/includes/paypal-log-row.html"} + {/loop} + +
{intl l='Date' d="paypal.bo.default"}{intl l='Details' d="paypal.bo.default"}{intl l="Customer ID" d="paypal.bo.default"}{intl l="Order ID" d="paypal.bo.default"}{intl l="Webhook" d="paypal.bo.default"}{intl l="Level" d="paypal.bo.default"}
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/paypal-log.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/paypal-log.html new file mode 100644 index 0000000..3285c43 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/paypal-log.html @@ -0,0 +1,105 @@ +{extends file="admin-layout.tpl"} + +{block name="main-content"} + +
+
+
+ + {include file="paypal/menu/menu.html" selectedMenu="log"} + +
+ +
+
+
+ +

+ 1 + {intl l="Automatic PayPal logs" d="paypal.bo.default"} +

+ +
+
+

+  {intl l="Help" d="paypal.bo.default"} : +

+
+ {intl l="This is where we log all the transactions made with PayPal. PayPal webhooks also automatically feed these logs." d="paypal.bo.default"} +
{intl l="This informations can be found directly in concerned order details." d="paypal.bo.default"} +
+
+
+
+ Payment configuration +
+
+
+ + + {$page = $smarty.get.page|default:1} + {$limit = $smarty.get.limit|default:100} + +
+
+
+ + + + + + + + + + + + + + {loop name="paypal_log" type="paypal_log" backend_context=true order="date-reverse" page=$page limit=$limit} + {include file = "paypal/includes/paypal-log-row.html"} + {/loop} + + + + + + +
{intl l='Date' d="paypal.bo.default"}{intl l='Details' d="paypal.bo.default"}{intl l="Customer ID" d="paypal.bo.default"}{intl l="Order ID" d="paypal.bo.default"}{intl l="Webhook" d="paypal.bo.default"}{intl l="Level" d="paypal.bo.default"}
+ {include + file = "includes/pagination.html" + loop_ref = "paypal_log" + max_page_count = $limit + page_url = {url path="/admin/module/paypal/configure/log"} + } +
+
+
+
+
+
+
+
+
+
+
+{/block} + +{block name="javascript-initialization"} + {include file = "paypal/includes/paypal-log-row-js.html"} +{/block} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment-edit.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment-edit.html new file mode 100644 index 0000000..9ecd9fa --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment-edit.html @@ -0,0 +1,86 @@ +{extends file="admin-layout.tpl"} + +{block name="no-return-functions"} +{$admin_current_location = 'module'} +{/block} + +{block name="page-title"}{intl l='Edit planified payment' d="paypal.bo.default"}{/block} + +{block name="main-content"} +
+
+ {loop name="paypal_planified_payment" type="paypal_planified_payment" id=$planifiedPaymentId backend_context=true} + + + +
+
+ +
+
+ {intl l='Edit planified payment %title' d="paypal.bo.default" title=$planifiedPayment->getTitle()} +
+
+ + + +
+ +
+ +
+ + {form name="paypal_planified_payment_update_form"} +
getId()}" {form_enctype} class="clearfix"> + + {include file="includes/inner-form-toolbar.html" hide_flags=true close_url={url path="/admin/module/paypal/configure/planified"}} + + + + {* Be sure to get the planified payment ID, even if the form could not be validated *} + + + {form_hidden_fields} + + {render_form_field field="id"} + + {render_form_field field="success_url" value={url path="/admin/module/paypal/configure/planified"}} + + {if $form_error} +
{$form_error_message}
+ {/if} + +
+ {include file = "paypal/form/create-or-update-planified-payment-form.html"} +
+ + {include + file="includes/inner-form-toolbar.html" + hide_submit_buttons = false + hide_flags = true + + close_url={url path="/admin/module/paypal/configure/planified"} + } + + {intl l='Planified payment created on %date_create. Last modification: %date_change' d="paypal.bo.default" date_create={format_date date=$CREATE_DATE} date_change={format_date date=$UPDATE_DATE} } +
+ {/form} +
+
+
+
+
+ {/loop} +
+
+{/block} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment.html b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment.html new file mode 100644 index 0000000..2bf98c4 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/backOffice/default/paypal/planified-payment.html @@ -0,0 +1,185 @@ +{extends file="admin-layout.tpl"} + +{block name="main-content"} + +
+
+
+ + {include file="paypal/menu/menu.html" selectedMenu="planifiedPayment"} + +
+ +
+
+
+

+ 1 + {intl l="Planified payment configuration" d="paypal.bo.default"} +

+ +
+
+

+  {intl l="Help" d="paypal.bo.default"} : +

+
+ {intl l="This feature uses PayPal's Billing Plan and Agreement. It allows debiting a client recursively directly from PayPal." d="paypal.bo.default"} +
{intl l="These planned payments will appear in step 4 of the purchase tunnel when selecting the payment method." d="paypal.bo.default"} +
+
+
+
+ Payment configuration +
+
+
+ +
+
+
+ + + + + + + + + + + + + + + {loop name="paypal_planified_payment" type="paypal_planified_payment" backend_context=true order=$order} + + + + + + + + {/loop} + {elseloop rel="paypal_planified_payment"} + + + + {/elseloop} + +
+ {intl l="List of planified payments" d="paypal.bo.default"} + + + +
+ {intl l='Title' d="paypal.bo.default"} + + {intl l='Details' d="paypal.bo.default"} +
+ {$planifiedPayment->getTitle()} ;
+ {$planifiedPayment->getDescription()} +
+ {intl l='Frequency interval' d="paypal.bo.default"} : {$planifiedPayment->getFrequencyInterval()}
+ {intl l='Frequency' d="paypal.bo.default"} : {$planifiedPayment->getFrequency()}
+ {intl l='Cycle' d="paypal.bo.default"} : {$planifiedPayment->getCycle()}
+ {intl l='Min amount' d="paypal.bo.default"} : {if $planifiedPayment->getMinAmount() > 0}{format_money number=$planifiedPayment->getMinAmount()}{else}{intl l='None' d="paypal.bo.default"}{/if}
+ {intl l='Max amount' d="paypal.bo.default"} : {if $planifiedPayment->getMaxAmount() > 0}{format_money number=$planifiedPayment->getMaxAmount()}{else}{intl l='None' d="paypal.bo.default"}{/if}
+
+ +
+
+ {intl l="No planified payment has been created yet. Click the + button to create one." d="paypal.bo.default"} +
+
+
+
+
+
+
+
+
+
+
+
+ + {* Adding a new planified payment *} + {form name="paypal_planified_payment_create_form"} + + {* Capture the dialog body, to pass it to the generic dialog *} + {capture "creation_dialog"} + {form_hidden_fields} + + {include file = "paypal/form/create-or-update-planified-payment-form.html"} + + {render_form_field field="success_url" value={url path='/admin/module/paypal/configure/planified'}} + {/capture} + + {include + file = "includes/generic-create-dialog.html" + + dialog_id = "creation_dialog" + dialog_title = {intl l="Create a new planified payment" d="paypal.bo.default"} + dialog_body = {$smarty.capture.creation_dialog nofilter} + + dialog_ok_label = {intl l="Create this planified payment" d="paypal.bo.default"} + + form_action = {url path='/admin/module/paypal/configure/planified/create'} + form_enctype = {form_enctype} + form_error_message = $form_error_message + } + {/form} + + {* Delete confirmation dialog *} + {capture "delete_dialog"} + + {/capture} + + {include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_dialog" + dialog_title = {intl l="Delete planified payment" d="paypal.bo.default"} + dialog_message = {intl l="Do you really want to delete this planified payment ?" d="paypal.bo.default"} + + form_action = {token_url path='/admin/module/paypal/configure/planified/create/delete'} + form_content = {$smarty.capture.delete_dialog nofilter} + } +{/block} + +{block name="javascript-initialization"} + +{/block} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.html b/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.html new file mode 100644 index 0000000..43c199b --- /dev/null +++ b/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.html @@ -0,0 +1,23 @@ +{extends file="email-layout.tpl"} + +{* Do not provide a "Open in browser" link *} +{block name="browser"}{/block} +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}{intl d='paypal.mail.default' l="Payment of your order %ref" ref={$order_ref}}{/block} + +{* Title *} +{block name="email-title"}{intl d='paypal.mail.default' l="The payment of your order %ref is confirmed" ref={$order_ref}}{/block} + +{* Content *} +{block name="email-content"} +

+ + {intl l="View this order in your account at %shop_name" shop_name={config key="store_name"}} + +

+

{intl d='paypal.email.default' l='Thank you again for your purchase.'}

+

{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}

+{/block} diff --git a/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.txt b/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.txt new file mode 100644 index 0000000..491fe8b --- /dev/null +++ b/domokits/local/modules/PayPal/templates/email/default/paypal-payment-confirmation.txt @@ -0,0 +1,9 @@ +{intl d='paypal.email.default' l='Dear customer'}, + +{intl d='paypal.email.default' l='This is a confirmation of the payment of your order %ref via Paypal on our shop.' ref=$order_ref} + +{intl d='paypal.email.default' l='Your invoice is now available in your customer account at %url.'} url={config key="url_site"}} + +{intl d='paypal.email.default' l='Thank you again for your purchase.'} + +{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.html b/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.html new file mode 100644 index 0000000..43c199b --- /dev/null +++ b/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.html @@ -0,0 +1,23 @@ +{extends file="email-layout.tpl"} + +{* Do not provide a "Open in browser" link *} +{block name="browser"}{/block} +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}{intl d='paypal.mail.default' l="Payment of your order %ref" ref={$order_ref}}{/block} + +{* Title *} +{block name="email-title"}{intl d='paypal.mail.default' l="The payment of your order %ref is confirmed" ref={$order_ref}}{/block} + +{* Content *} +{block name="email-content"} +

+ + {intl l="View this order in your account at %shop_name" shop_name={config key="store_name"}} + +

+

{intl d='paypal.email.default' l='Thank you again for your purchase.'}

+

{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}}

+{/block} diff --git a/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.txt b/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.txt new file mode 100644 index 0000000..491fe8b --- /dev/null +++ b/domokits/local/modules/PayPal/templates/email/default/paypal-recursive-payment-confirmation.txt @@ -0,0 +1,9 @@ +{intl d='paypal.email.default' l='Dear customer'}, + +{intl d='paypal.email.default' l='This is a confirmation of the payment of your order %ref via Paypal on our shop.' ref=$order_ref} + +{intl d='paypal.email.default' l='Your invoice is now available in your customer account at %url.'} url={config key="url_site"}} + +{intl d='paypal.email.default' l='Thank you again for your purchase.'} + +{intl d='paypal.email.default' l='The %store_name team.' store_name={config key="store_name"}} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/assets/cards-logo.jpg b/domokits/local/modules/PayPal/templates/frontOffice/default/assets/cards-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..962e7d36b6c16ac8ccf0def20b0578baca8aa7cc GIT binary patch literal 13435 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%0DTbQKppjO0M3$ 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 CE?n{e literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/assets/ntimes-cards-logo.png b/domokits/local/modules/PayPal/templates/frontOffice/default/assets/ntimes-cards-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..efef888129326f8fdb58d07564fdf10095014525 GIT binary patch literal 9334 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/assets/paypal-logo.png b/domokits/local/modules/PayPal/templates/frontOffice/default/assets/paypal-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aab877abb5a23081e072fafdf021112f48c7b524 GIT binary patch literal 4196 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/cart-bottom.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/cart-bottom.html new file mode 100644 index 0000000..7c8ef99 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/cart-bottom.html @@ -0,0 +1,11 @@ +
+ + diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-credit-card.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-credit-card.html new file mode 100644 index 0000000..edfd5bb --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-credit-card.html @@ -0,0 +1,85 @@ +
+ label}checked{/if}/> + + CB / VISA / Mastercard + + +
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-paypal.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-paypal.html new file mode 100644 index 0000000..9ef809a --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-paypal.html @@ -0,0 +1,17 @@ +
+ {if $method_paypal_with_in_context} + label}checked{/if}/> + + {else} + label}checked{/if}/> + + {/if} + + +
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-planified-payment.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-planified-payment.html new file mode 100644 index 0000000..dccbed5 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/form/extra-planified-payment.html @@ -0,0 +1,26 @@ +{assign var="methodName" value=$name} +{form_field field='paypal_planified_payment'} + {if count($choices) > 0} +
+ label}checked{/if}/> + + +
+ {/if} +{/form_field} + diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/login-bottom.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/login-bottom.html new file mode 100644 index 0000000..5710a61 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/login-bottom.html @@ -0,0 +1,16 @@ +
+ + + +
\ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom-js.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom-js.html new file mode 100644 index 0000000..cc14715 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom-js.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom.html new file mode 100644 index 0000000..00d5b4c --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-delivery-bottom.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-bottom.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-bottom.html new file mode 100644 index 0000000..e6b444a --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-bottom.html @@ -0,0 +1,11 @@ + + + diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-js.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-js.html new file mode 100644 index 0000000..98a4a49 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-js.html @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-payment-extra.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-payment-extra.html new file mode 100644 index 0000000..3e394be --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-invoice-payment-extra.html @@ -0,0 +1,21 @@ +{form name="thelia.order.payment"} + +{/form} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-placed-additional-payment-info.html b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-placed-additional-payment-info.html new file mode 100644 index 0000000..9ce0fb2 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/frontOffice/default/paypal/order-placed-additional-payment-info.html @@ -0,0 +1,6 @@ +{loop type="paypal_order" name="paypal_order" id=$placed_order_id limit=1} + {if $paypal_order->getPlanifiedCycle() > 0} + {intl l="Planified payment" d="paypal.fo.default"} :  + {intl l="Payment in %x times every %frequency_interval %frequency" x=$paypal_order->getPlanifiedCycle() frequency_interval=$paypal_order->getPlanifiedFrequencyInterval() frequency="{intl l=$paypal_order->getPlanifiedFrequency() d="paypal.fo.default"}" d="paypal.fo.default"} + {/if} +{/loop} \ No newline at end of file diff --git a/domokits/local/modules/PayPal/templates/pdf/default/paypal/after-payment-module.html b/domokits/local/modules/PayPal/templates/pdf/default/paypal/after-payment-module.html new file mode 100644 index 0000000..d08b5e8 --- /dev/null +++ b/domokits/local/modules/PayPal/templates/pdf/default/paypal/after-payment-module.html @@ -0,0 +1,6 @@ +{loop type="paypal_order" name="paypal_order" id=$order limit=1} + {if $paypal_order->getPlanifiedCycle() > 0} + {intl l="Planified payment" d="paypal.pdf.default"} :  + {intl l="Payment in %x times every %frequency_interval %frequency" x=$paypal_order->getPlanifiedCycle() frequency_interval=$paypal_order->getPlanifiedFrequencyInterval() frequency="{intl l=$paypal_order->getPlanifiedFrequency() d="paypal.pdf.default"}" d="paypal.pdf.default"} + {/if} +{/loop} \ No newline at end of file diff --git a/domokits/local/modules/ProductLoopAttributeFilter/CHANGELOG.md b/domokits/local/modules/ProductLoopAttributeFilter/CHANGELOG.md new file mode 100644 index 0000000..db9d280 --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/CHANGELOG.md @@ -0,0 +1,3 @@ +# 1.0.0 + +- First version \ No newline at end of file diff --git a/domokits/local/modules/ProductLoopAttributeFilter/Config/config.xml b/domokits/local/modules/ProductLoopAttributeFilter/Config/config.xml new file mode 100644 index 0000000..ea7c54c --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/Config/config.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/domokits/local/modules/ProductLoopAttributeFilter/Config/module.xml b/domokits/local/modules/ProductLoopAttributeFilter/Config/module.xml new file mode 100644 index 0000000..cb44301 --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/Config/module.xml @@ -0,0 +1,43 @@ + + + ProductLoopAttributeFilter\ProductLoopAttributeFilter + + Automatically generated module - please update module.xml file + + + + Module généré automatiquement - éditez le fichier module.xml + + + + + en_US + fr_FR + + 2.5.0 + + + Gilles Bourgeat + gbourgeat@openstudio.fr + + + classic + + 2.5.0 + beta + 0 + 0 + diff --git a/domokits/local/modules/ProductLoopAttributeFilter/LICENSE b/domokits/local/modules/ProductLoopAttributeFilter/LICENSE new file mode 100644 index 0000000..ab60297 --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/domokits/local/modules/ProductLoopAttributeFilter/Listener/LoopProductListener.php b/domokits/local/modules/ProductLoopAttributeFilter/Listener/LoopProductListener.php new file mode 100644 index 0000000..43f2b8f --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/Listener/LoopProductListener.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ProductLoopAttributeFilter\Listener; + +use Propel\Runtime\ActiveQuery\Criteria; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Core\Event\Loop\LoopExtendsArgDefinitionsEvent; +use Thelia\Core\Event\Loop\LoopExtendsBuildModelCriteriaEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Model\ProductQuery; + +class LoopProductListener implements EventSubscriberInterface +{ + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::getLoopExtendsEvent( + TheliaEvents::LOOP_EXTENDS_ARG_DEFINITIONS, + 'product' + ) => ['productArgDefinitions', 128], + TheliaEvents::getLoopExtendsEvent( + TheliaEvents::LOOP_EXTENDS_BUILD_MODEL_CRITERIA, + 'product' + ) => ['productBuildModelCriteria', 128], + ]; + } + + public function productArgDefinitions(LoopExtendsArgDefinitionsEvent $event): void + { + $argument = $event->getArgumentCollection(); + + $argument->addArgument(Argument::createBooleanTypeArgument('attribute_extend', false)); + + $argument->addArgument(Argument::createIntListTypeArgument('attribute_availability', null)); + + $argument->addArgument(Argument::createIntTypeArgument('attribute_min_stock', null)); + } + + public function productBuildModelCriteria(LoopExtendsBuildModelCriteriaEvent $event): void + { + if ($event->getLoop()->getAttributeExtend()) { + if (null !== $attributeAvailability = $event->getLoop()->getAttributeAvailability()) { + $this->manageAttributeAvailability($event, $attributeAvailability); + } + } + } + + protected function manageAttributeAvailability(LoopExtendsBuildModelCriteriaEvent $event, array $attributeAvailability): void + { + /** @var ProductQuery $query */ + $query = $event->getModelCriteria(); + + $useProductSaleElementsQuery = $query + ->useProductSaleElementsQuery('pse_attribute_extend', Criteria::INNER_JOIN); + + if (null !== $minStock = $event->getLoop()->getAttributeMinStock()) { + $useProductSaleElementsQuery->filterByQuantity($minStock, Criteria::GREATER_EQUAL); + } + + $useProductSaleElementsQuery->useAttributeCombinationQuery('attribute_extend', Criteria::INNER_JOIN) + ->filterByAttributeAvId($attributeAvailability, Criteria::IN) + ->endUse() + ->endUse(); + } +} diff --git a/domokits/local/modules/ProductLoopAttributeFilter/ProductLoopAttributeFilter.php b/domokits/local/modules/ProductLoopAttributeFilter/ProductLoopAttributeFilter.php new file mode 100644 index 0000000..e718c2e --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/ProductLoopAttributeFilter.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* Copyright (c) OpenStudio */ +/* email : dev@thelia.net */ +/* web : http://www.thelia.net */ + +/* For the full copyright and license information, please view the LICENSE.txt */ +/* file that was distributed with this source code. */ + +namespace ProductLoopAttributeFilter; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; + +class ProductLoopAttributeFilter extends BaseModule +{ + /** @var string */ + public const DOMAIN_NAME = 'productloopattributefilter'; + + /* + * You may now override BaseModuleInterface methods, such as: + * install, destroy, preActivation, postActivation, preDeactivation, postDeactivation + * + * Have fun ! + */ + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/ProductLoopAttributeFilter/Readme.md b/domokits/local/modules/ProductLoopAttributeFilter/Readme.md new file mode 100644 index 0000000..93830f9 --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/Readme.md @@ -0,0 +1,43 @@ +# Product Loop Attribute Filter + +Adds the possibility to filter by attribute on the product loop + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is ProductLoopAttributeFilter. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/product-loop-attribute-filter-module:~1.0.0 +``` + +## Loop + +### Loop Product + +### New input arguments + +|Argument |Type |Default value |Description | +|--- |--- |--- |--- | +|**attribute_extend** | boolean | false | make true for activate the filter | +|**attribute_availability** | int[] | | list of ids | +|**attribute_min_stock** | int | 0 | Minimum quantity | + +### Output arguments + +http://doc.thelia.net/en/documentation/loop/product.html + +### Exemple + +```smarty + +{loop attribute_extend=true attribute_availability="64" attribute_min_stock=1 name="product" type="product" visible="*"} + +{/loop} +``` diff --git a/domokits/local/modules/ProductLoopAttributeFilter/composer.json b/domokits/local/modules/ProductLoopAttributeFilter/composer.json new file mode 100644 index 0000000..f6c59dc --- /dev/null +++ b/domokits/local/modules/ProductLoopAttributeFilter/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/product-loop-attribute-filter-module", + "license": "MIT", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "ProductLoopAttributeFilter" + } +} \ No newline at end of file diff --git a/domokits/local/modules/ReCaptcha/Action/ReCaptchaAction.php b/domokits/local/modules/ReCaptcha/Action/ReCaptchaAction.php new file mode 100644 index 0000000..80cf08e --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Action/ReCaptchaAction.php @@ -0,0 +1,56 @@ +request = $requestStack->getCurrentRequest(); + } + + public function checkCaptcha(ReCaptchaCheckEvent $event) + { + $requestUrl = "https://www.google.com/recaptcha/api/siteverify"; + + $secretKey = ReCaptcha::getConfigValue('secret_key'); + $minScore = ReCaptcha::getConfigValue('min_score', 0.3); + $requestUrl .= "?secret=$secretKey"; + + $captchaResponse = $event->getCaptchaResponse(); + if (null == $captchaResponse) { + $captchaResponse = $this->request->request->get('g-recaptcha-response'); + } + + $requestUrl .= "&response=$captchaResponse"; + + $remoteIp = $event->getRemoteIp(); + if (null == $remoteIp) { + $remoteIp = $this->request->server->get('REMOTE_ADDR'); + } + + $requestUrl .= "&remoteip=$remoteIp"; + + $result = json_decode(file_get_contents($requestUrl), true); + if ($result['success'] == true && (!array_key_exists('score', $result) || $result['score'] > $minScore)) { + $event->setHuman(true); + } + } + + public static function getSubscribedEvents() + { + return [ + ReCaptchaEvents::CHECK_CAPTCHA_EVENT => ['checkCaptcha', 128], + ]; + } +} diff --git a/domokits/local/modules/ReCaptcha/Config/config.xml b/domokits/local/modules/ReCaptcha/Config/config.xml new file mode 100644 index 0000000..749b7cd --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Config/config.xml @@ -0,0 +1,42 @@ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/ReCaptcha/Config/module.xml b/domokits/local/modules/ReCaptcha/Config/module.xml new file mode 100644 index 0000000..fc87649 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Config/module.xml @@ -0,0 +1,41 @@ + + + ReCaptcha\ReCaptcha + + ReCaptcha + + + + ReCaptcha + + + + + en_US + fr_FR + + 3.0.1 + + + Vincent Lopes-Vicente + vlopes@openstudio.fr + + + classic + + 2.5.0 + other + diff --git a/domokits/local/modules/ReCaptcha/Config/routing.xml b/domokits/local/modules/ReCaptcha/Config/routing.xml new file mode 100644 index 0000000..adcae39 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Config/routing.xml @@ -0,0 +1,15 @@ + + + + + + ReCaptcha\Controller\ConfigurationController::viewAction + + + + ReCaptcha\Controller\ConfigurationController::saveAction + + + diff --git a/domokits/local/modules/ReCaptcha/Config/schema.xml b/domokits/local/modules/ReCaptcha/Config/schema.xml new file mode 100644 index 0000000..fdd67dd --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Config/schema.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/domokits/local/modules/ReCaptcha/Controller/ConfigurationController.php b/domokits/local/modules/ReCaptcha/Controller/ConfigurationController.php new file mode 100644 index 0000000..ad5e06d --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Controller/ConfigurationController.php @@ -0,0 +1,52 @@ +render( + "recaptcha/configuration" + ); + } + + public function saveAction() + { + if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'ReCaptcha', AccessManager::VIEW)) { + return $response; + } + + $form = $this->createForm(ConfigurationForm::getName()); + + try { + $data = $this->validateForm($form)->getData(); + + ReCaptcha::setConfigValue('site_key', $data['site_key']); + ReCaptcha::setConfigValue('secret_key', $data['secret_key']); + ReCaptcha::setConfigValue('min_score', $data['min_score']); + ReCaptcha::setConfigValue('captcha_style', $data['captcha_style']); + + } catch (\Exception $e) { + $this->setupFormErrorContext( + Translator::getInstance()->trans( + "Error", + [], + ReCaptcha::DOMAIN_NAME + ), + $e->getMessage(), + $form + ); + return $this->viewAction(); + } + + return $this->generateSuccessRedirect($form); + } +} diff --git a/domokits/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php b/domokits/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php new file mode 100644 index 0000000..42b30dd --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php @@ -0,0 +1,80 @@ +captchaResponse = $captchaResponse; + } + + if (null !== $remoteIp) { + $this->remoteIp = $remoteIp; + } + } + + /** + * @return null + */ + public function getCaptchaResponse() + { + return $this->captchaResponse; + } + + /** + * @param null $captchaResponse + * @return ReCaptchaCheckEvent + */ + public function setCaptchaResponse($captchaResponse) + { + $this->captchaResponse = $captchaResponse; + return $this; + } + + /** + * @return null + */ + public function getRemoteIp() + { + return $this->remoteIp; + } + + /** + * @param null $remoteIp + * @return ReCaptchaCheckEvent + */ + public function setRemoteIp($remoteIp) + { + $this->remoteIp = $remoteIp; + return $this; + } + + /** + * @return bool + */ + public function isHuman() + { + return $this->human; + } + + /** + * @param bool $human + * @return ReCaptchaCheckEvent + */ + public function setHuman($human) + { + $this->human = $human; + return $this; + } +} diff --git a/domokits/local/modules/ReCaptcha/Event/ReCaptchaEvents.php b/domokits/local/modules/ReCaptcha/Event/ReCaptchaEvents.php new file mode 100644 index 0000000..2e8b054 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Event/ReCaptchaEvents.php @@ -0,0 +1,8 @@ +formBuilder + ->add( + "site_key", + TextType::class, + [ + "data" => ReCaptcha::getConfigValue("site_key"), + "label"=>Translator::getInstance()->trans("Site key", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "site_key"], + "required" => true + ] + ) + ->add( + "secret_key", + TextType::class, + [ + "data" => ReCaptcha::getConfigValue("secret_key"), + "label"=>Translator::getInstance()->trans("Secret key", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "secret_key"], + "required" => true + ] + ) + ->add( + "min_score", + NumberType::class, + [ + "data" => ReCaptcha::getConfigValue("min_score"), + "label"=>Translator::getInstance()->trans("Captcha minimum score", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "min_score"], + "required" => true, + "attr" => [ + "min" => 0.1, + "max" => 1, + "step" => 0.1 + ] + ] + ) + ->add( + "captcha_style", + ChoiceType::class, + [ + "data" => ReCaptcha::getConfigValue("captcha_style"), + "label"=>Translator::getInstance()->trans("ReCaptcha style", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "captcha_style"], + "required" => true, + 'choices' => [ + 'Normal'=>'normal', + 'Compact'=>'compact', + 'Invisible'=>'invisible' + ] + ] + ); + } + + public static function getName() + { + return "recaptcha_configuration_form"; + } +} diff --git a/domokits/local/modules/ReCaptcha/Hook/FrontHook.php b/domokits/local/modules/ReCaptcha/Hook/FrontHook.php new file mode 100644 index 0000000..81e3569 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Hook/FrontHook.php @@ -0,0 +1,59 @@ +getArgument('id')) { + $captchaId = $event->getArgument('id'); + } + + $event->add("
"); + } + + public function loadRecaptcha(HookRenderEvent $event) + { + $siteKey = ReCaptcha::getConfigValue('site_key'); + $captchaStyle = ReCaptcha::getConfigValue('captcha_style'); + + if ($captchaStyle !== 'invisible') { + $event->add($this->render( + 'recaptcha-js.html', + [ + "siteKey" => $siteKey, + "captchaStyle" => $captchaStyle, + ] + )); + + return; + } + + $event->add($this->render( + 'recaptcha-js-invisible.html', + [ + "siteKey" => $siteKey, + "captchaStyle" => $captchaStyle, + ] + )); + } +} diff --git a/domokits/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..ca4e780 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,8 @@ + 'ReCaptcha configuration', + 'ReCaptcha module configuration' => 'ReCaptcha module configuration', + 'These infos are available here : ' => 'Ces infos sont disponibles ici : ', + 'reCAPTCHA access :' => 'reCAPTCHA accés :', +); diff --git a/domokits/local/modules/ReCaptcha/I18n/en_US.php b/domokits/local/modules/ReCaptcha/I18n/en_US.php new file mode 100644 index 0000000..0b4fa14 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/domokits/local/modules/ReCaptcha/I18n/fr_FR.php b/domokits/local/modules/ReCaptcha/I18n/fr_FR.php new file mode 100644 index 0000000..d0fba1e --- /dev/null +++ b/domokits/local/modules/ReCaptcha/I18n/fr_FR.php @@ -0,0 +1,7 @@ + 'Erreur', + 'Secret key' => 'Clé secrète', + 'Site key' => 'Clé du site', +); diff --git a/domokits/local/modules/ReCaptcha/LICENSE b/domokits/local/modules/ReCaptcha/LICENSE new file mode 100644 index 0000000..2152256 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 OpenStudio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/domokits/local/modules/ReCaptcha/ReCaptcha.php b/domokits/local/modules/ReCaptcha/ReCaptcha.php new file mode 100644 index 0000000..8c2507e --- /dev/null +++ b/domokits/local/modules/ReCaptcha/ReCaptcha.php @@ -0,0 +1,64 @@ + TemplateDefinition::FRONT_OFFICE, + "code" => "recaptcha.js", + "title" => [ + "en_US" => "reCaptcha js", + "fr_FR" => "Js pour recaptcha", + ], + "block" => false, + "active" => true, + ], + [ + "type" => TemplateDefinition::FRONT_OFFICE, + "code" => "recaptcha.check", + "title" => [ + "en_US" => "reCaptcha check hook", + "fr_FR" => "reCaptcha check hook", + ], + "block" => false, + "active" => true, + ], + ]; + } + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/ReCaptcha/Readme.md b/domokits/local/modules/ReCaptcha/Readme.md new file mode 100644 index 0000000..f479cc7 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/Readme.md @@ -0,0 +1,62 @@ +# Re Captcha + +This module allows you to add easily a reCAPTCHA to your form +## Installation + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/re-captcha-module:~2.0.0 +``` + +## Usage + +Before using this module you have to create google api key here http://www.google.com/recaptcha/admin +next configure your reCAPTCHA access here http://your_site.com`/admin/module/ReCaptcha` with keys you obtained in Google's page +and choose which style of captcha you want : + +- A standard captcha (or a compact version of this one) + + ![Checkbox captcha](https://developers.google.com/recaptcha/images/newCaptchaAnchor.gif) + +- An invisible captcha + + ![Invisible captcha](https://developers.google.com/recaptcha/images/invisible_badge.png) + + +Then you'll need help from a developer to add some hooks in template and dispatch the check events, see details below. + +### Hook + +First if you don't have `{hook name="main.head-top"}` hook in your template you have to put this hook `{hook name="recaptcha.js"}` in the top of your head +Then add this hook `{hook name="recaptcha.check"}` in every form where you want to check if the user is human, +be careful if you want to use the invisible captcha this hook must be placed directly in the form tag like this : +``` + + {hook name="recaptcha.check"} + // End of the form +
+``` + +### Event + +To check in server-side if the captcha is valid you have to dispatch the "CHECK_CAPTCHA_EVENT" like this : +``` +$checkCaptchaEvent = new ReCaptchaCheckEvent(); +$eventDispatcher->dispatch($checkCaptchaEvent, ReCaptchaEvents::CHECK_CAPTCHA_EVENT); +``` + +Then the result of check is available in `$checkCaptchaEvent->isHuman()`as boolean so you can do a test like this : +``` +if ($checkCaptchaEvent->isHuman() == false) { + throw new \Exception('Invalid captcha'); +} +``` + +Don't forget to add this use at the top of your class : +``` +use ReCaptcha\Event\ReCaptchaCheckEvent; +use ReCaptcha\Event\ReCaptchaEvents; +``` diff --git a/domokits/local/modules/ReCaptcha/composer.json b/domokits/local/modules/ReCaptcha/composer.json new file mode 100644 index 0000000..42d9d3a --- /dev/null +++ b/domokits/local/modules/ReCaptcha/composer.json @@ -0,0 +1,12 @@ +{ + "name": "thelia/re-captcha-module", + "description": "This module allows you to add easily a reCAPTCHA to your form", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "ReCaptcha" + } +} \ No newline at end of file diff --git a/domokits/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html b/domokits/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html new file mode 100644 index 0000000..f998bc9 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html @@ -0,0 +1,72 @@ +{extends file="admin-layout.tpl"} + +{block name="after-bootstrap-css"} + +{/block} + +{block name="no-return-functions"} + {$admin_current_location = 'module'} +{/block} + +{block name="page-title"}{intl l='ReCaptcha module configuration' d='recaptcha.bo.default'}{/block} + +{block name="check-resource"}admin.module{/block} +{block name="check-access"}view{/block} +{block name="check-module"}ReCaptcha{/block} + +{block name="main-content"} +
+
+
+

+ {intl l="ReCaptcha configuration" d='recaptcha.bo.default'} +

+
+ {form name="recaptcha_configuration_form"} +
+ {form_hidden_fields form=$form} + + {if $form_error} +
{$form_error_message}
+ {/if} + + {form_field form=$form field='success_url'} + + {/form_field} + +
+
+

{intl l="reCAPTCHA access :" d='recaptcha.bo.default'}

+
+ {render_form_field form=$form field="site_key" value={$data}} +
+
+ {render_form_field form=$form field="secret_key" value={$data}} +
+
+ {render_form_field form=$form field="captcha_style" value={$data}} +
+
+ {render_form_field form=$form field="min_score" value={$data}} +
+
+

{intl l="These infos are available here : " d='recaptcha.bo.default'}http://www.google.com/recaptcha/admin

+
+
+ +
+
+
+
+ {/form} +
+
+{/block} + +{block name="javascript-initialization"} + +{/block} diff --git a/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html b/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html new file mode 100644 index 0000000..4c54a7a --- /dev/null +++ b/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html @@ -0,0 +1,56 @@ + + + + + +{literal} + +{/literal} \ No newline at end of file diff --git a/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html b/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html new file mode 100644 index 0000000..f116da9 --- /dev/null +++ b/domokits/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html @@ -0,0 +1,23 @@ + + \ No newline at end of file diff --git a/domokits/local/modules/ResetPassword/Command/ResetAllPasswordCommand.php b/domokits/local/modules/ResetPassword/Command/ResetAllPasswordCommand.php new file mode 100644 index 0000000..acc3cee --- /dev/null +++ b/domokits/local/modules/ResetPassword/Command/ResetAllPasswordCommand.php @@ -0,0 +1,86 @@ +resetPasswordService = $resetPasswordService; + } + + protected function configure() + { + $this + ->setName("resetpassword:reset:all:password") + ->setDescription("Reset all password and send reset link") + ->addOption( + 'all', + null, + InputOption::VALUE_NONE, + 'Safeguard, if not set only first 5 customer will be reset' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->initRequest(); + + $customerQuery = CustomerQuery::create(); + + if (true !== $input->getOption('all')) { + $customerQuery->limit(5); + } + + $customers = $customerQuery->find(); + + foreach ($customers as $customer) { + try { + if (!$customer->getPassword()) { + continue; + } + $customerForbiddenPassword = CustomerForbiddenPasswordQuery::create() + ->filterByCustomerId($customer->getId()) + ->filterByPassword($customer->getPassword()) + ->findOne(); + + if (null === $customerForbiddenPassword) { + (new CustomerForbiddenPassword()) + ->setCustomerId($customer->getId()) + ->setPassword($customer->getPassword()) + ->save(); + } + + $this->resetPasswordService->sendResetLinkByEmail( + $customer->getEmail(), + ResetPassword::RESET_ALL_PASSWORD_MESSAGE_NAME, + ['customerId' => $customer->getId()], + -1 + ); + + $customer->erasePassword() + ->save(); + + $output->writeln("Password reset link for customer ".$customer->getId()." sent successfully"); + } catch (\Exception $exception) { + $output->writeln("".$exception->getMessage().""); + } + + } + + return 0; + } +} diff --git a/domokits/local/modules/ResetPassword/Config/TheliaMain.sql b/domokits/local/modules/ResetPassword/Config/TheliaMain.sql new file mode 100755 index 0000000..1713337 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/TheliaMain.sql @@ -0,0 +1,50 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- password_reset_token +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `password_reset_token`; + +CREATE TABLE `password_reset_token` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER NOT NULL, + `token` VARCHAR(255), + `end_of_life` DATETIME, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `fi_password_reset_token_customer_id` (`customer_id`), + CONSTRAINT `fk_password_reset_token_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- customer_forbidden_password +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `customer_forbidden_password`; + +CREATE TABLE `customer_forbidden_password` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER NOT NULL, + `password` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`), + INDEX `fi_customer_forbidden_password_customer_id` (`customer_id`), + CONSTRAINT `fk_customer_forbidden_password_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/ResetPassword/Config/config.xml b/domokits/local/modules/ResetPassword/Config/config.xml new file mode 100755 index 0000000..c9f3b36 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/config.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/ResetPassword/Config/module.xml b/domokits/local/modules/ResetPassword/Config/module.xml new file mode 100755 index 0000000..4d3efb1 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/module.xml @@ -0,0 +1,43 @@ + + + ResetPassword\ResetPassword + + Change Thelia lost password behaviour to be a reset link + + + + Remplace le comportement de base Thelia des mot de passes oubliés par un lien de réinitialisation + + + + + en_US + fr_FR + + 1.0.1 + + + + + + + classic + + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/ResetPassword/Config/routing.xml b/domokits/local/modules/ResetPassword/Config/routing.xml new file mode 100755 index 0000000..0c92f13 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/routing.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/domokits/local/modules/ResetPassword/Config/schema.xml b/domokits/local/modules/ResetPassword/Config/schema.xml new file mode 100755 index 0000000..6b1ea39 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/schema.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/ResetPassword/Config/sqldb.map b/domokits/local/modules/ResetPassword/Config/sqldb.map new file mode 100644 index 0000000..e69de29 diff --git a/domokits/local/modules/ResetPassword/Config/update/1.0.1.sql b/domokits/local/modules/ResetPassword/Config/update/1.0.1.sql new file mode 100644 index 0000000..e9a1c0c --- /dev/null +++ b/domokits/local/modules/ResetPassword/Config/update/1.0.1.sql @@ -0,0 +1,26 @@ +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- customer_forbidden_password +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `customer_forbidden_password`; + +CREATE TABLE `customer_forbidden_password` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `customer_id` INTEGER NOT NULL, + `password` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`), + INDEX `fi_customer_forbidden_password_customer_id` (`customer_id`), + CONSTRAINT `fk_customer_forbidden_password_customer_id` + FOREIGN KEY (`customer_id`) + REFERENCES `customer` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/ResetPassword/Controller/Front/ResetPasswordController.php b/domokits/local/modules/ResetPassword/Controller/Front/ResetPasswordController.php new file mode 100755 index 0000000..3c1fbdd --- /dev/null +++ b/domokits/local/modules/ResetPassword/Controller/Front/ResetPasswordController.php @@ -0,0 +1,52 @@ +render("resetPassword/reset_password"); + } + + /** + * @Route("", name="_action", methods="POST") + */ + public function resetPasswordAction( + ParserContext $parserContext, + ResetPasswordService $resetPasswordService + ) + { + $form = $this->createForm(ResetPasswordForm::class); + + try { + $data = $this->validateForm($form)->getData(); + + $resetPasswordService->checkTokenAndUpdatePassword($data['email'], $data['token'], $data['password']); + + return $this->generateSuccessRedirect($form); + } catch (\Exception $exception) { + $form->setErrorMessage($exception->getMessage()); + + $parserContext + ->addForm($form) + ->setGeneralError($exception->getMessage()); + + return $this->generateErrorRedirect($form); + } + } +} diff --git a/domokits/local/modules/ResetPassword/EventListener/LostPasswordListener.php b/domokits/local/modules/ResetPassword/EventListener/LostPasswordListener.php new file mode 100755 index 0000000..7ca6f0d --- /dev/null +++ b/domokits/local/modules/ResetPassword/EventListener/LostPasswordListener.php @@ -0,0 +1,39 @@ +resetPasswordService = $resetPasswordService; + } + + /** + * @throws \Propel\Runtime\Exception\PropelException + */ + public function sendResetLink(LostPasswordEvent $event): void + { + $this->resetPasswordService->sendResetLinkByEmail($event->getEmail()); + $event->stopPropagation(); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::LOST_PASSWORD => ['sendResetLink', 256], + ]; + } +} diff --git a/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordAskForm.php b/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordAskForm.php new file mode 100755 index 0000000..bb89eac --- /dev/null +++ b/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordAskForm.php @@ -0,0 +1,19 @@ +formBuilder; + $form + ->add( + 'email', + HiddenType::class + ); + } +} diff --git a/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordForm.php b/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordForm.php new file mode 100755 index 0000000..c8161d6 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Form/Front/ResetPasswordForm.php @@ -0,0 +1,59 @@ +formBuilder; + $form + ->add( + 'email', + HiddenType::class + ) + ->add( + 'token', + HiddenType::class + ) + ->add('password', PasswordType::class, [ + 'constraints' => [ + new Constraints\NotBlank(), + new Constraints\Length(['min' => ConfigQuery::read('password.length', 4)]), + ], + 'label' => Translator::getInstance()->trans('New Password'), + 'label_attr' => [ + 'for' => 'password', + ], + ]) + ->add('password_confirm', PasswordType::class, [ + 'constraints' => [ + new Constraints\NotBlank(), + new Constraints\Length(['min' => ConfigQuery::read('password.length', 4)]), + new Constraints\Callback([$this, 'verifyPasswordField']), + ], + 'label' => Translator::getInstance()->trans('Password confirmation'), + 'label_attr' => [ + 'for' => 'password_confirmation', + ], + ]); + ; + } + + public function verifyPasswordField($value, ExecutionContextInterface $context): void + { + $data = $context->getRoot()->getData(); + + if ($data['password'] != $data['password_confirm']) { + $context->addViolation(Translator::getInstance()->trans('password confirmation is not the same as password field')); + } + } +} diff --git a/domokits/local/modules/ResetPassword/I18n/email/default/fr_FR.php b/domokits/local/modules/ResetPassword/I18n/email/default/fr_FR.php new file mode 100644 index 0000000..70bd876 --- /dev/null +++ b/domokits/local/modules/ResetPassword/I18n/email/default/fr_FR.php @@ -0,0 +1,16 @@ + 'Pour des raisons de sécurité, nous vous invitons à renouveler votre mot de passe pour %store_name via le lien suivant : ', + 'Have a nice day' => 'Bonne journée.', + 'Hello %name,' => 'Bonjour %name,', + 'Hello,' => 'Bonjour,', + 'If you don\'t requested a new password, please ignore this message.' => 'Si vous n\'avez pas demandé de nouveau mot de passe, merci d\'ignorer ce message.', + 'Please click here to create a new password.' => ' Veuillez Cliquez ici pour créer un nouveau mot de passe', + 'Please click here to define a new password: %url . You will be prompted to enter a new password.' => 'Veuillez cliquer ici pour définir un nouveau mot de passe : %url . Vous serez invité à saisir un nouveau mot de passe. ', + 'Reset you password for %store' => 'Réinitialisez votre mot de passe pour %store', + 'Thank you and have a nice day.' => 'Merci et bonne journée.', + 'You can also paste the URL below in you browser\'s address bar : ' => 'Vous pouvez également coller l\'URL ci-dessous dans la barre d\'adresse de votre navigateur : ', + 'You have requested a new password for your account at %store_name' => 'Vous avez demandé la réinitialistaion de votre mot de passe sur %store_name', + 'Your password reset link for %store' => 'Votre lien de réinitialisation de mot de passe pour %store', +); diff --git a/domokits/local/modules/ResetPassword/I18n/en_US.php b/domokits/local/modules/ResetPassword/I18n/en_US.php new file mode 100755 index 0000000..d391ee9 --- /dev/null +++ b/domokits/local/modules/ResetPassword/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + // 'an english string' => 'The displayed english string', +]; diff --git a/domokits/local/modules/ResetPassword/I18n/fr_FR.php b/domokits/local/modules/ResetPassword/I18n/fr_FR.php new file mode 100755 index 0000000..3839979 --- /dev/null +++ b/domokits/local/modules/ResetPassword/I18n/fr_FR.php @@ -0,0 +1,15 @@ + 'Impossible de générer un jeton pour un client qui n\'existe pas. ', + 'Mail for resetting all passwords' => 'Mail pour la réinitialisation de tous les mots de passe', + 'New Password' => 'Nouveau mot de passe', + 'Password confirmation' => 'Confirmation du mot de passe ', + 'Password reset link' => 'Lien de réinitialisation du mot de passe ', + 'Please use a different password than the previous ones.' => 'Veuillez utiliser un mot de passe différent des précédents.', + 'Reset you password' => 'Réinitialiser votre mot de passe ', + 'This token has expired' => 'Ce jeton a expiré ', + 'This token is invalid or doesn\'t match your email' => 'Ce jeton n\'est pas valide ou ne correspond pas à votre adresse e-mail. ', + 'Your password reset link' => 'Votre lien de réinitialisation de mot de passe ', + 'password confirmation is not the same as password field' => 'la confirmation du mot de passe n\'est pas identique au mot de passe ', +); diff --git a/domokits/local/modules/ResetPassword/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/ResetPassword/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..db85d4a --- /dev/null +++ b/domokits/local/modules/ResetPassword/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,7 @@ + 'Choisissez votre nouveau mot de passe', + 'Reset password' => 'Réinitialisation du mot de passe', + 'missing or invalid data' => 'Données manquantes ou invalides', +); diff --git a/domokits/local/modules/ResetPassword/Model/CustomerForbiddenPassword.php b/domokits/local/modules/ResetPassword/Model/CustomerForbiddenPassword.php new file mode 100644 index 0000000..e2f7f0c --- /dev/null +++ b/domokits/local/modules/ResetPassword/Model/CustomerForbiddenPassword.php @@ -0,0 +1,19 @@ +getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, array(__DIR__ . '/Config/TheliaMain.sql')); + + $this->setConfigValue('is_initialized', true); + } + + $this->generateEmailMessage(); + } + + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + $finder = Finder::create() + ->name('*.sql') + ->depth(0) + ->sortByName() + ->in(__DIR__ . DS . 'Config' . DS . 'update'); + + $database = new Database($con); + + /** @var \SplFileInfo $file */ + foreach ($finder as $file) { + if (version_compare($currentVersion, $file->getBasename('.sql'), '<')) { + $database->insertSql(null, [$file->getPathname()]); + } + } + + $this->generateEmailMessage(); + } + + /** + * Defines how services are loaded in your modules + * + * @param ServicesConfigurator $servicesConfigurator + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } + + public static function getTokenLength() + { + return self::getConfigValue(self::TOKEN_LENGTH_CONFIG_KEY, 32); + } + + public static function getTokenTimeToLive() + { + return self::getConfigValue(self::TOKEN_TIME_TO_LIVE_KEY, 86400); + } + + protected function generateEmailMessage(): void + { + // In case translator has not been instancied + try { + Translator::getInstance(); + } catch (\Exception $e) { + new Translator($this->getContainer()->get('request_stack')); + } + + if (null === MessageQuery::create()->findOneByName(self::RESET_PASSWORD_MESSAGE_NAME)) { + $message = new Message(); + $message + ->setName(self::RESET_PASSWORD_MESSAGE_NAME) + ->setHtmlTemplateFileName(self::RESET_PASSWORD_MESSAGE_NAME . '.html') + ->setHtmlLayoutFileName('') + ->setTextTemplateFileName(self::RESET_PASSWORD_MESSAGE_NAME . '.txt') + ->setTextLayoutFileName('') + ->setSecured(0); + + $languages = LangQuery::create()->find(); + + foreach ($languages as $language) { + $locale = $language->getLocale(); + + $message->setLocale($locale); + + $message->setSubject( + Translator::getInstance()->trans('Your password reset link', [], ResetPassword::DOMAIN_NAME, $locale) + ); + $message->setTitle( + Translator::getInstance()->trans('Password reset link', [],ResetPassword::DOMAIN_NAME, $locale) + ); + } + + $message->save(); + } + + if (null === MessageQuery::create()->findOneByName(self::RESET_ALL_PASSWORD_MESSAGE_NAME)) { + $message = new Message(); + $message + ->setName(self::RESET_ALL_PASSWORD_MESSAGE_NAME) + ->setHtmlTemplateFileName(self::RESET_ALL_PASSWORD_MESSAGE_NAME . '.html') + ->setHtmlLayoutFileName('') + ->setSecured(0); + + $languages = LangQuery::create()->find(); + + foreach ($languages as $language) { + $locale = $language->getLocale(); + + $message->setLocale($locale); + + $message->setSubject( + Translator::getInstance()->trans('Reset you password', [], ResetPassword::DOMAIN_NAME, $locale) + ); + $message->setTitle( + Translator::getInstance()->trans('Mail for resetting all passwords', [],ResetPassword::DOMAIN_NAME, $locale) + ); + } + + $message->save(); + } + } +} diff --git a/domokits/local/modules/ResetPassword/Service/ResetPasswordService.php b/domokits/local/modules/ResetPassword/Service/ResetPasswordService.php new file mode 100755 index 0000000..ad9c465 --- /dev/null +++ b/domokits/local/modules/ResetPassword/Service/ResetPasswordService.php @@ -0,0 +1,136 @@ +mailer = $mailer; + } + + public function sendResetLinkByEmail( + $email, + $messageCode = null, + $additionalParameters = [], + $tokenTimeToLive = null + ) + { + $customer = CustomerQuery::create() + ->filterByEmail($email) + ->findOne(); + + if (null === $customer) { + throw new \Exception(Translator::getInstance()->trans("Can't generate a token for a customer that doesn't exist.", [], ResetPassword::DOMAIN_NAME)); + } + + if (null === $messageCode) { + $messageCode = ResetPassword::RESET_PASSWORD_MESSAGE_NAME; + } + + $tokenLink = $this->generateResetTokenLink($customer, $tokenTimeToLive); + $this->mailer->sendEmailToCustomer( + $messageCode, + $customer, + array_merge( + [ + 'customerId' => $customer->getId(), + 'tokenLink' => $tokenLink, + 'tokenTimeToLive' => ResetPassword::getTokenTimeToLive() + ], + $additionalParameters + ) + ); + } + + public function generateResetTokenLink(Customer $customer, $tokenTimeToLive = null) + { + $token = bin2hex(random_bytes(ResetPassword::getTokenLength())); + + if (null === $tokenTimeToLive) { + $tokenTimeToLive = ResetPassword::getTokenTimeToLive(); + } + + $endOfLife = $tokenTimeToLive > -1 ? (new \DateTime())->add((new \DateInterval("PT".ResetPassword::getTokenTimeToLive()."S"))) : null; + + $passwordResetToken = (new PasswordResetToken()) + ->setCustomerId($customer->getId()) + ->setToken($token) + ->setEndOfLife($endOfLife); + + $passwordResetToken->save(); + + return URL::getInstance()->absoluteUrl("/reset_password")."?token=$token&email=".urlencode($customer->getEmail()); + } + + public function checkTokenAndUpdatePassword($email, $token, $newPassword) + { + $customer = CustomerQuery::create() + ->filterByEmail($email) + ->findOne(); + + if (null === $customer) { + throw new \Exception(Translator::getInstance()->trans("This token is invalid or doesn't match your email", [], ResetPassword::DOMAIN_NAME)); + } + + $tokenModel = $this->checkToken($token, null, $customer); + + $passwordHash = password_hash($newPassword, \PASSWORD_BCRYPT); + + $forbiddenPassword = CustomerForbiddenPasswordQuery::create() + ->filterById($customer->getId()) + ->filterByPassword($passwordHash) + ->findOne(); + + if (null !== $forbiddenPassword) { + throw new \Exception(Translator::getInstance()->trans("Please use a different password than the previous ones.", [], ResetPassword::DOMAIN_NAME)); + } + + $customer->setPassword($newPassword) + ->save(); + + $tokenModel->delete(); + return $customer; + } + + public function checkToken($token, $email = null, Customer $customer = null): PasswordResetToken + { + if (null === $customer) { + $customer = CustomerQuery::create() + ->filterByEmail($email) + ->findOne(); + } + + if (null === $customer) { + throw new \Exception(Translator::getInstance()->trans("This token is invalid or doesn't match your email", [], ResetPassword::DOMAIN_NAME)); + } + + $passwordResetToken = PasswordResetTokenQuery::create() + ->filterByCustomerId($customer->getId()) + ->filterByToken($token) + ->findOne(); + + if (null === $passwordResetToken) { + throw new \Exception(Translator::getInstance()->trans("This token is invalid or doesn't match your email", [], ResetPassword::DOMAIN_NAME)); + } + + if (null !== $passwordResetToken->getEndOfLife() && (new \DateTime()) > $passwordResetToken->getEndOfLife()) { + throw new \Exception(Translator::getInstance()->trans("This token has expired", [], ResetPassword::DOMAIN_NAME)); + } + + + return $passwordResetToken; + } +} diff --git a/domokits/local/modules/ResetPassword/composer.json b/domokits/local/modules/ResetPassword/composer.json new file mode 100755 index 0000000..cfad46a --- /dev/null +++ b/domokits/local/modules/ResetPassword/composer.json @@ -0,0 +1,12 @@ +{ + "name": "thelia/reset-password-module", + "description": "Change Thelia lost password behaviour to be a reset link", + "license": "LGPL-3.0-or-later", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "ResetPassword" + } +} diff --git a/domokits/local/modules/ResetPassword/templates/email/default/reset_all_password_message.html b/domokits/local/modules/ResetPassword/templates/email/default/reset_all_password_message.html new file mode 100644 index 0000000..3bbcc18 --- /dev/null +++ b/domokits/local/modules/ResetPassword/templates/email/default/reset_all_password_message.html @@ -0,0 +1,30 @@ +{default_translation_domain domain='resetpassword.email.default'} +{extends file="email-layout.tpl"} + +{* Open in browser *} +{block name="browser"}{/block} + +{* No big image header *} +{block name="image-header"}{/block} + +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}{intl l="Reset you password for %store" store={config key="store_name"}}{/block} + +{* Title *} +{block name="email-title"}{/block} + +{* Content *} +{block name="email-content"} + + {loop name="customer" type="customer" id=$customerId current=false limit=1} + {$name=$FIRSTNAME} + {/loop} + + {intl l="Hello %name," name=$name}

+ {intl l="For security reasons we invite you to renew your password for %store_name via the following link: " store_name={config key="store_name"}}.

+ {$tokenLink}

+ {intl l='Thank you and have a nice day.'} +{/block} diff --git a/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.html b/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.html new file mode 100755 index 0000000..493d692 --- /dev/null +++ b/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.html @@ -0,0 +1,30 @@ +{default_translation_domain domain='resetpassword.email.default'} +{extends file="email-layout.tpl"} + +{* Open in browser *} +{block name="browser"}{/block} + +{* No big image header *} +{block name="image-header"}{/block} + +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}{intl l="Your password reset link for %store" store={config key="store_name"}}{/block} + +{* Title *} +{block name="email-title"}{/block} + +{* Content *} +{block name="email-content"} + {intl l="Hello,"}

+ {intl l="You have requested a new password for your account at %store_name" store_name={config key="store_name"}}.

+ {intl l='Please click here to create a new password.' url={$tokenLink}}

+ {intl l="You can also paste the URL below in you browser's address bar : "}

+ {$tokenLink} +

+

+ {intl l='If you don\'t requested a new password, please ignore this message.'}.

+ {intl l='Have a nice day'} +{/block} diff --git a/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.txt b/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.txt new file mode 100755 index 0000000..28cd534 --- /dev/null +++ b/domokits/local/modules/ResetPassword/templates/email/default/reset_password_message.txt @@ -0,0 +1,10 @@ +{default_translation_domain domain='resetpassword.email.default'} +{intl l="Hello,"} + +{intl l="You have requested a new password for your account at %store_name" store_name={config key="store_name"}}. + +{intl l="Please click here to define a new password: %url . You will be prompted to enter a new password." url={$tokenLink}} + +{intl l='If you don\'t requested a new password, please ignore this message.'}. + +{intl l='Have a nice day'} diff --git a/domokits/local/modules/ResetPassword/templates/frontOffice/default/resetPassword/reset_password.html b/domokits/local/modules/ResetPassword/templates/frontOffice/default/resetPassword/reset_password.html new file mode 100755 index 0000000..f5f1872 --- /dev/null +++ b/domokits/local/modules/ResetPassword/templates/frontOffice/default/resetPassword/reset_password.html @@ -0,0 +1,87 @@ +{extends file="layout.tpl"} + +{* Body Class *} +{block name="body-class"}page-login{/block} + +{* Breadcrumb *} +{block name='no-return-functions' append} + {$breadcrumbs = [ + ['title' => {intl l="Reset password" d="resetpassword.fo.default"}, 'url'=>{url path="/reset_password"}] + ]} +{/block} + + +{block name="main-content"} + + {* This page should not replace the current previous URL *} + {set_previous_url ignore_current="1"} + +
+
+

{intl l="Reset password" d="resetpassword.fo.default"}

+ {form name="resetpassword_form_front_reset_password_form"} +
+ {if $form_error}
{$form_error_message}
{/if} + + {form_field field='success_url'} + {* the url the user is redirected to on login success *} + {/form_field} + + {form_field field='error_url'} + + {/form_field} + + {form_field field='error_message'} + {* the url the user is redirected to on login success *} + {/form_field} + {form_hidden_fields} +
+ {form_field field="email"} + + {/form_field} + {form_field field="token"} + + {/form_field} + +
+
+ {intl l="Choose your new password" d="resetpassword.fo.default"} +
+ +
+ {form_field field="password"} +
+ +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {/if} +
+
+ {/form_field} + + {form_field field="password_confirm"} +
+ +
+ + {if $error } + {$message} + {assign var="error_focus" value="true"} + {/if} +
+
+ {/form_field} +
+
+
+
+ +
+
+ {/form} +
+
+{/block} diff --git a/domokits/local/modules/RewriteUrl/.github/workflows/release.yml b/domokits/local/modules/RewriteUrl/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit-js.html b/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit-js.html new file mode 100755 index 0000000..9469412 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit-js.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module-js.html" viewName='brand' altViewName='brand'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit.html b/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit.html new file mode 100755 index 0000000..6bdb055 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/brand-edit.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module.html" viewName='brand' altViewName='brand'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit-js.html b/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit-js.html new file mode 100755 index 0000000..c33264b --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit-js.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module-js.html" viewName='category' altViewName='categories'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit.html b/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit.html new file mode 100755 index 0000000..7d74e12 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/category-edit.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module.html" viewName='category' altViewName='categories'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit-js.html b/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit-js.html new file mode 100755 index 0000000..a07f810 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit-js.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module-js.html" viewName='content' altViewName='content'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit.html b/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit.html new file mode 100755 index 0000000..818780e --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/content-edit.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module.html" viewName='content' altViewName='content'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit-js.html b/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit-js.html new file mode 100755 index 0000000..ca64507 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit-js.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module-js.html" viewName='folder' altViewName='folders'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit.html b/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit.html new file mode 100755 index 0000000..4eb674a --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/folder-edit.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module.html" viewName='folder' altViewName='folders'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit-js.html b/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit-js.html new file mode 100755 index 0000000..241a6a7 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit-js.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module-js.html" viewName='product' altViewName='products'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit.html b/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit.html new file mode 100755 index 0000000..e91997b --- /dev/null +++ b/domokits/local/modules/RewriteUrl/AdminIncludes/product-edit.html @@ -0,0 +1 @@ +{include file="RewriteUrl/tab-module.html" viewName='product' altViewName='products'} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/Config/config.xml b/domokits/local/modules/RewriteUrl/Config/config.xml new file mode 100755 index 0000000..8f495b2 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/config.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/RewriteUrl/Config/module.xml b/domokits/local/modules/RewriteUrl/Config/module.xml new file mode 100755 index 0000000..be32ed4 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/module.xml @@ -0,0 +1,18 @@ + + + RewriteUrl\RewriteUrl + + Manage rewrite url + + + Gérer la réécriture d'url + + 2.1.8 + + Vincent Lopes, Gilles Bourgeat, Tom Pradat + vlopes@openstudio.fr, gbourgeat@openstudio.fr, tpradat@openstudio.fr + + classic + 2.5.0 + prod + diff --git a/domokits/local/modules/RewriteUrl/Config/routing.xml b/domokits/local/modules/RewriteUrl/Config/routing.xml new file mode 100755 index 0000000..e7ad916 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/routing.xml @@ -0,0 +1,51 @@ + + + + + + RewriteUrl\Controller\Admin\ModuleConfigController::getDatatableRules + + + RewriteUrl\Controller\Admin\ModuleConfigController::setRewritingEnableAction + + + RewriteUrl\Controller\Admin\ModuleConfigController::addRuleAction + + + RewriteUrl\Controller\Admin\ModuleConfigController::updateRuleAction + + + RewriteUrl\Controller\Admin\ModuleConfigController::removeRuleAction + + + RewriteUrl\Controller\Admin\ModuleConfigController::moveRulePositionAction + + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::deleteAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::searchAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::existAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::addAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::setDefaultAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::reassignAction + + + RewriteUrl\Controller\Admin\RewriteUrlAdminController::changeRedirectTypeAction + + + RewriteUrl\Controller\Admin\NotRewritenUrlsAdminController::defaultAction + + + diff --git a/domokits/local/modules/RewriteUrl/Config/schema.xml b/domokits/local/modules/RewriteUrl/Config/schema.xml new file mode 100644 index 0000000..83f3a36 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/schema.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + + +
+ + +
diff --git a/domokits/local/modules/RewriteUrl/Config/thelia.sql b/domokits/local/modules/RewriteUrl/Config/thelia.sql new file mode 100644 index 0000000..5dcfd32 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/thelia.sql @@ -0,0 +1,62 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- rewriting_redirect_type +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rewriting_redirect_type`; + +CREATE TABLE `rewriting_redirect_type` +( + `id` INTEGER NOT NULL, + `httpcode` INTEGER, + PRIMARY KEY (`id`), + CONSTRAINT `rewriting_redirect_type_FK_1` + FOREIGN KEY (`id`) + REFERENCES `rewriting_url` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- rewriteurl_rule +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rewriteurl_rule`; + +CREATE TABLE `rewriteurl_rule` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `rule_type` VARCHAR(64) NOT NULL, + `value` VARCHAR(255), + `only404` TINYINT(1) NOT NULL, + `redirect_url` VARCHAR(255) NOT NULL, + `position` INTEGER(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- rewriteurl_rule_param +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rewriteurl_rule_param`; + +CREATE TABLE `rewriteurl_rule_param` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `id_rule` INTEGER NOT NULL, + `param_name` VARCHAR(255) NOT NULL, + `param_condition` VARCHAR(64) NOT NULL, + `param_value` VARCHAR(255), + PRIMARY KEY (`id`), + INDEX `rewriteurl_rule_rule_param_FI_id` (`id_rule`), + CONSTRAINT `rewriteurl_rule_rule_param_FK_id` + FOREIGN KEY (`id_rule`) + REFERENCES `rewriteurl_rule` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/RewriteUrl/Config/update/1.4.8.sql b/domokits/local/modules/RewriteUrl/Config/update/1.4.8.sql new file mode 100644 index 0000000..f5cf4ec --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/update/1.4.8.sql @@ -0,0 +1,22 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- rewriting_redirect_type +-- --------------------------------------------------------------------- + +CREATE TABLE IF NOT EXISTS `rewriting_redirect_type` +( + `id` INTEGER NOT NULL, + `httpcode` INTEGER, + PRIMARY KEY (`id`), + CONSTRAINT `rewriting_redirect_type_FK_1` + FOREIGN KEY (`id`) + REFERENCES `rewriting_url` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/Config/update/1.5.0.sql b/domokits/local/modules/RewriteUrl/Config/update/1.5.0.sql new file mode 100644 index 0000000..00778a8 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Config/update/1.5.0.sql @@ -0,0 +1,45 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- rewriteurl_rule +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rewriteurl_rule`; + +CREATE TABLE `rewriteurl_rule` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `rule_type` VARCHAR(64) NOT NULL, + `value` VARCHAR(255), + `only404` TINYINT(1) NOT NULL, + `redirect_url` VARCHAR(255) NOT NULL, + `position` INTEGER(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- rewriteurl_rule_param +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rewriteurl_rule_param`; + +CREATE TABLE `rewriteurl_rule_param` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `id_rule` INTEGER NOT NULL, + `param_name` VARCHAR(255) NOT NULL, + `param_condition` VARCHAR(64) NOT NULL, + `param_value` VARCHAR(255), + PRIMARY KEY (`id`), + INDEX `rewriteurl_rule_rule_param_FI_id` (`id_rule`), + CONSTRAINT `rewriteurl_rule_rule_param_FK_id` + FOREIGN KEY (`id_rule`) + REFERENCES `rewriteurl_rule` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/Controller/Admin/ModuleConfigController.php b/domokits/local/modules/RewriteUrl/Controller/Admin/ModuleConfigController.php new file mode 100644 index 0000000..9f25b7d --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Controller/Admin/ModuleConfigController.php @@ -0,0 +1,321 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace RewriteUrl\Controller\Admin; + +use Propel\Runtime\ActiveQuery\Criteria; +use RewriteUrl\Model\RewriteurlRule; +use RewriteUrl\Model\RewriteurlRuleParam; +use RewriteUrl\Model\RewriteurlRuleQuery; +use RewriteUrl\RewriteUrl; +use Thelia\Controller\Admin\BaseAdminController; +use Thelia\Core\HttpFoundation\JsonResponse; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Response; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Core\Translation\Translator; +use Thelia\Exception\TheliaProcessException; +use Thelia\Model\ConfigQuery; + +class ModuleConfigController extends BaseAdminController +{ + public function viewConfigAction() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], 'RewriteUrl', AccessManager::VIEW)) { + return $response; + } + + $isRewritingEnabled = ConfigQuery::isRewritingEnable(); + + return $this->render( + 'RewriteUrl/module-configuration', + [ + 'isRewritingEnabled' => $isRewritingEnabled, + ] + ); + } + + public function getDatatableRules(Request $request) + { + $requestSearchValue = $request->get('search') ? '%' . $request->get('search')['value'] . '%' : ''; + $recordsTotal = RewriteurlRuleQuery::create()->count(); + $search = RewriteurlRuleQuery::create(); + if ('' !== $requestSearchValue) { + $search + ->filterByValue($requestSearchValue, Criteria::LIKE) + ->_or() + ->filterByRedirectUrl($requestSearchValue); + } + + $recordsFiltered = $search->count(); + + $orderColumn = $request->get('order')[0]['column']; + $orderDirection = $request->get('order')[0]['dir']; + switch ($orderColumn) { + case '0': + $search->orderByRuleType($orderDirection); + break; + case '1': + $search->orderByValue($orderDirection); + break; + case '2': + $search->orderByOnly404($orderDirection); + break; + case '3': + $search->orderByRedirectUrl($orderDirection); + break; + case '4': + $search->orderByPosition($orderDirection); + break; + default: + $search->orderByPosition(); + break; + } + + $search + ->offset($request->get('start')) + ->limit($request->get('length')); + $searchArray = $search->find()->toArray(); + + $resultsArray = []; + foreach ($searchArray as $row) { + $id = $row['Id']; + $isRegexSelected = $row['RuleType'] === RewriteurlRule::TYPE_REGEX ? 'selected' : ''; + $isParamsSelected = $row['RuleType'] === RewriteurlRule::TYPE_GET_PARAMS ? 'selected' : ''; + $isRegexParamsSelected = $row['RuleType'] === RewriteurlRule::TYPE_REGEX_GET_PARAMS ? 'selected' : ''; + $isTextParamsSelected = $row['RuleType'] === RewriteurlRule::TYPE_TEXT ? 'selected' : ''; + $isOnly404Checked = $row['Only404'] ? 'checked' : ''; + $rewriteUrlRuleParams = RewriteurlRuleQuery::create()->findPk($row['Id'])->getRewriteUrlParamCollection(); + $resultsArray[] = [ + 'Id' => $row['Id'], + 'RuleType' => '', + 'Value' => $this->renderRaw( + 'RewriteUrl/tab-value-render', + [ + 'ID' => $row['Id'], + 'REWRITE_URL_PARAMS' => $rewriteUrlRuleParams, + 'VALUE' => $row['Value'], + ] + ), + 'Only404' => '', + 'RedirectUrl' => '
+ +
', + 'Position' => ' + ' . $row['Position'] . ' + ', + 'Actions' => ' + +', + ]; + } + + return new JsonResponse([ + 'draw' => $request->get('draw'), + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $resultsArray, + ]); + } + + public function setRewritingEnableAction(Request $request): Response + { + $isRewritingEnable = $request->get('rewriting_enable', null); + + if ($isRewritingEnable !== null) { + ConfigQuery::write('rewriting_enable', $isRewritingEnable ? 1 : 0); + + return $this->jsonResponse(json_encode(['state' => 'Success']), 200); + } + + return $this->jsonResponse(Translator::getInstance()->trans( + 'Unable to change the configuration variable.', + [], + RewriteUrl::MODULE_DOMAIN + ), 500); + } + + public function addRuleAction(Request $request) + { + try { + $rule = new RewriteurlRule(); + + $this->fillRuleObjectFields($rule, $request); + } catch (\Exception $ex) { + return $this->jsonResponse($ex->getMessage(), 500); + } + + return $this->jsonResponse(json_encode(['state' => 'Success']), 200); + } + + public function updateRuleAction(Request $request) + { + try { + $rule = RewriteurlRuleQuery::create()->findOneById($request->get('id')); + + if ($rule === null) { + throw new \Exception(Translator::getInstance()->trans( + 'Unable to find rule to update.', + [], + RewriteUrl::MODULE_DOMAIN + )); + } + + $this->fillRuleObjectFields($rule, $request); + } catch (\Exception $ex) { + return $this->jsonResponse($ex->getMessage(), 500); + } + + return $this->jsonResponse(json_encode(['state' => 'Success']), 200); + } + + public function removeRuleAction(Request $request) + { + try { + $rule = RewriteurlRuleQuery::create()->findOneById($request->get('id')); + + if ($rule === null) { + throw new \Exception(Translator::getInstance()->trans( + 'Unable to find rule to remove.', + [], + RewriteUrl::MODULE_DOMAIN + )); + } + + $rule->delete(); + } catch (\Exception $ex) { + return $this->jsonResponse($ex->getMessage(), 500); + } + + return $this->jsonResponse(json_encode(['state' => 'Success']), 200); + } + + public function moveRulePositionAction(Request $request) + { + try { + $rule = RewriteurlRuleQuery::create()->findOneById($request->get('id')); + + if ($rule === null) { + throw new \Exception(Translator::getInstance()->trans( + 'Unable to find rule to change position.', + [], + RewriteUrl::MODULE_DOMAIN + )); + } + + $type = $request->get('type', null); + + if ($type === 'up') { + $rule->movePositionUp(); + } elseif ($type === 'down') { + $rule->movePositionDown(); + } elseif ($type === 'absolute') { + $position = $request->get('position', null); + if (!empty($position)) { + $rule->changeAbsolutePosition($position); + } + } + } catch (\Exception $ex) { + return $this->jsonResponse($ex->getMessage(), 500); + } + + return $this->jsonResponse(json_encode(['state' => 'Success']), 200); + } + + /** + * @throws \Propel\Runtime\Exception\PropelException + */ + protected function fillRuleObjectFields(RewriteurlRule $rule, Request $request): void + { + $ruleType = $request->get('ruleType', null); + + $isParamRule = $ruleType === RewriteurlRule::TYPE_GET_PARAMS || $ruleType === RewriteurlRule::TYPE_REGEX_GET_PARAMS; + $isRegexRule = $ruleType === RewriteurlRule::TYPE_REGEX || $ruleType === RewriteurlRule::TYPE_REGEX_GET_PARAMS; + $isTextRule = $ruleType === RewriteurlRule::TYPE_TEXT; + + if (!($isParamRule || $isRegexRule || $isTextRule)) { + throw new TheliaProcessException(Translator::getInstance()->trans('Unknown rule type.', [], RewriteUrl::MODULE_DOMAIN)); + } + + if ($isTextRule && !$textValue = $request->get('textValue', null)) { + throw new TheliaProcessException(Translator::getInstance()->trans('Text value cannot be empty.', [], RewriteUrl::MODULE_DOMAIN)); + } + + $regexValue = $request->get('value', null); + + if ($isRegexRule && empty($regexValue)) { + throw new TheliaProcessException(Translator::getInstance()->trans('Regex value cannot be empty.', [], RewriteUrl::MODULE_DOMAIN)); + } + + $redirectUrl = $request->get('redirectUrl', null); + + if (empty($redirectUrl)) { + throw new TheliaProcessException(Translator::getInstance()->trans('Redirect url cannot be empty.', [], RewriteUrl::MODULE_DOMAIN)); + } + + $value = $isTextRule ? $textValue : $regexValue; + + $paramRuleArray = []; + + if ($isParamRule) { + $paramRuleArray = $request->get('paramRules', null); + if (empty($paramRuleArray)) { + throw new TheliaProcessException(Translator::getInstance()->trans('At least one GET parameter is required.', [], RewriteUrl::MODULE_DOMAIN)); + } + } + + $rule->setRuleType($ruleType) + ->setValue($value) + ->setOnly404($request->get('only404', 1)) + ->setRedirectUrl($redirectUrl); + + if (empty($rule->getPosition())) { + $rule->setPosition($rule->getNextPosition()); + } + + $rule->deleteAllRelatedParam(); + + $rule->save(); + + if ($isParamRule) { + foreach ($paramRuleArray as $paramRule) { + if (!\array_key_exists('paramName', $paramRule) || empty($paramRule['paramName'])) { + throw new TheliaProcessException(Translator::getInstance()->trans( + 'Param name is empty.', + [], + RewriteUrl::MODULE_DOMAIN + )); + } + if (!\array_key_exists('condition', $paramRule) || empty($paramRule['condition'])) { + throw new TheliaProcessException(Translator::getInstance()->trans( + 'Param condition is empty.', + [], + RewriteUrl::MODULE_DOMAIN + )); + } + + (new RewriteurlRuleParam()) + ->setParamName($paramRule['paramName']) + ->setParamCondition($paramRule['condition']) + ->setParamValue($paramRule['paramValue']) + ->setIdRule($rule->getId()) + ->save(); + } + } + } +} diff --git a/domokits/local/modules/RewriteUrl/Controller/Admin/NotRewritenUrlsAdminController.php b/domokits/local/modules/RewriteUrl/Controller/Admin/NotRewritenUrlsAdminController.php new file mode 100644 index 0000000..4b6a80a --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Controller/Admin/NotRewritenUrlsAdminController.php @@ -0,0 +1,39 @@ + + */ +class NotRewritenUrlsAdminController extends AdminController +{ + public function defaultAction(Request $request) + { + return $this->render( + 'list-notrewritenurls', + array( + 'current_tab' => $request->get('current_tab', 'categories'), + 'page_category' => $request->get('page_category', 1), + 'page_product' => $request->get('page_product', 1), + 'page_brand' => $request->get('page_brand', 1), + 'page_folder' => $request->get('page_folder', 1), + 'page_content' => $request->get('page_content', 1), + ) + ); + } +} diff --git a/domokits/local/modules/RewriteUrl/Controller/Admin/RewriteUrlAdminController.php b/domokits/local/modules/RewriteUrl/Controller/Admin/RewriteUrlAdminController.php new file mode 100755 index 0000000..15c65b5 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Controller/Admin/RewriteUrlAdminController.php @@ -0,0 +1,480 @@ + + * @author Gilles Bourgeat + */ +class RewriteUrlAdminController extends BaseAdminController +{ + /** @var array */ + private $correspondence = array( + 'brand' => 'brand', + 'category' => 'categories', + 'content' => 'content', + 'folder' => 'folders', + 'product' => 'products' + ); + + /** + * @return mixed + */ + public function deleteAction( + Request $request, + EventDispatcherInterface $dispatcher + ) { + if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'RewriteUrl', AccessManager::DELETE)) { + return $response; + } + + $urlId = $request->request->get('id_url'); + $rewritingUrl = RewritingUrlQuery::create()->findOneById($urlId); + + if ($rewritingUrl !== null) { + $event = new RewriteUrlEvent($rewritingUrl); + $dispatcher->dispatch($event,RewriteUrlEvents::REWRITEURL_DELETE); + } + + return $this->generateRedirectFromRoute( + 'admin.'.$this->correspondence[$rewritingUrl->getView()].'.update', + [ + $rewritingUrl->getView().'_id'=>$rewritingUrl->getViewId(), + 'current_tab' => 'modules' + ], + [ + $rewritingUrl->getView().'_id'=>$rewritingUrl->getViewId() + ] + ); + } + + /** + * @return mixed + */ + public function addAction(EventDispatcherInterface $dispatcher, ParserContext $parserContext) + { + $message = null; + $exception = null; + + if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'RewriteUrl', AccessManager::CREATE)) { + return $response; + } + + $addForm = $this->createForm(AddUrlForm::getName()); + + try { + $form = $this->validateForm($addForm); + $data = $form->getData(); + + $findExist = RewritingUrlQuery::create()->findOneByUrl(($data['url'])); + + if ($findExist !== null && !in_array($findExist->getView(), RewriteUrl::getUnknownSources()) && $findExist->getView() !== '') { + $url = $this->generateUrlByRewritingUrl($findExist); + + throw new \Exception( + Translator::getInstance()->trans( + "This url is already used here %url.", + ['%url' => '' . $url . ''], + RewriteUrl::MODULE_DOMAIN + ) + ); + } + + $rewriting = $findExist !== null ? $findExist : new RewritingUrlOverride(); + $rewriting->setUrl($data['url']) + ->setView($data['view']) + ->setViewId($data['view-id']) + ->setViewLocale($data['locale']); + + $rewriteDefault = RewritingUrlQuery::create() + ->filterByView($rewriting->getView()) + ->filterByViewId($rewriting->getViewId()) + ->filterByViewLocale($rewriting->getViewLocale()) + ->findOneByRedirected(null); + + $redirectType = null; + + if ($data['default'] == 1) { + $rewriting->setRedirected(null); + } else { + if ($rewriteDefault !== null) { + $rewriting->setRedirected($rewriteDefault->getId()); + $redirectType = RewritingRedirectTypeQuery::create() + ->filterById($rewriting->getId()) + ->findOneOrCreate(); + $redirectType->setHttpcode($data['httpcode']); + } else { + $rewriting->setRedirected(null); + } + } + + $dispatcher->dispatch( + new RewriteUrlEvent($rewriting, $redirectType), + RewriteUrlEvents::REWRITEURL_ADD + ); + + return $this->generateSuccessRedirect($addForm); + } catch (FormValidationException $exception) { + $message = $this->createStandardFormValidationErrorMessage($exception); + } catch (\Exception $exception) { + $message = $exception->getMessage(); + } + + if ($message !== null && $exception !== null) { + Tlog::getInstance()->error(sprintf("Error during order delivery process : %s. Exception was %s", $message, $exception->getMessage())); + + $addForm->setErrorMessage($message); + + $parserContext + ->addForm($addForm) + ->setGeneralError($message); + } + + return $this->generateSuccessRedirect($addForm); + } + + /** + * @return mixed + */ + public function setDefaultAction(Request $request, EventDispatcherInterface $dispatcher) + { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'RewriteUrl', AccessManager::UPDATE)) { + return $response; + } + + $urlId = $request->request->get('id_url'); + $rewritingUrl = RewritingUrlQuery::create()->findOneById($urlId); + + if ($rewritingUrl !== null) { + $event = new RewriteUrlEvent($rewritingUrl); + $dispatcher->dispatch($event,RewriteUrlEvents::REWRITEURL_SET_DEFAULT); + } + + return $this->generateRedirectFromRoute( + 'admin.'.$this->correspondence[$rewritingUrl->getView()].'.update', + [ + $rewritingUrl->getView().'_id'=>$rewritingUrl->getViewId(), + 'current_tab' => 'modules' + ], + [ + $rewritingUrl->getView().'_id'=>$rewritingUrl->getViewId() + ] + ); + } + + + public function changeRedirectTypeAction(Request $request, EventDispatcherInterface $dispatcher) + { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'RewriteUrl', AccessManager::UPDATE)) { + return $response; + } + + $urlId = $request->get('id_url'); + $httpcode = $request->get('httpcode'); + $rewritingUrl = RewritingUrlQuery::create()->findOneById($urlId); + + if ($rewritingUrl !== null) { + $rewritingRedirectType = RewritingRedirectTypeQuery::create() + ->filterById($urlId) + ->findOneOrCreate(); + $rewritingRedirectType->setHttpcode($httpcode); + + $event = new RewriteUrlEvent($rewritingUrl, $rewritingRedirectType); + $dispatcher->dispatch($event,RewriteUrlEvents::REWRITEURL_UPDATE); + } + + return new Response("", Response::HTTP_OK); + } + + /** + * @return mixed + */ + public function reassignAction(EventDispatcherInterface $dispatcher, ParserContext $parserContext) + { + if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'RewriteUrl', AccessManager::UPDATE)) { + return $response; + } + + $reassignForm = $this->createForm(ReassignForm::getName()); + + try { + $form = $this->validateForm($reassignForm); + $data = $form->getData(); + + $all = $data['all']; + $newRewrite = explode('::', $data['select-reassign']); + $rewriteId = $data['rewrite-id']; + $newView = $newRewrite[1]; + $newViewId = $newRewrite[0]; + + if ($all === 1) { + self::allReassign($dispatcher, $rewriteId, $newView, $newViewId); + } else { + self::simpleReassign($dispatcher, $rewriteId, $newView, $newViewId); + } + + return $this->generateSuccessRedirect($reassignForm); + } catch (FormValidationException $e) { + $message = $this->createStandardFormValidationErrorMessage($e); + } catch (\Exception $e) { + $message = $e->getMessage(); + } + + $reassignForm->setErrorMessage($message); + + $parserContext + ->addForm($reassignForm) + ->setGeneralError($message) + ; + + return $this->generateSuccessRedirect($reassignForm); + } + + /** + * @return mixed|\Thelia\Core\HttpFoundation\Response + */ + public function existAction(Request $request) + { + if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'RewriteUrl', AccessManager::VIEW)) { + return $response; + } + + $search = $request->query->get('q'); + + $rewritingUrl = RewritingUrlQuery::create() + ->filterByView(RewriteUrl::getUnknownSources(), Criteria::NOT_IN) + ->findOneByUrl($search); + + if ($rewritingUrl !== null) { + if (!in_array($rewritingUrl->getView(), $this->correspondence)) { + return $this->jsonResponse(json_encode(false)); + } + + $rewritingUrlArray = ["reassignUrl" => $this->generateUrlByRewritingUrl($rewritingUrl)]; + + return $this->jsonResponse(json_encode($rewritingUrlArray)); + } else { + return $this->jsonResponse(json_encode(false)); + } + } + + /** + * @return mixed|\Thelia\Core\HttpFoundation\Response + * @throws \Propel\Runtime\Exception\PropelException + */ + public function searchAction(Request $request) + { + if (null !== $response = $this->checkAuth(array(AdminResources::MODULE), 'RewriteUrl', AccessManager::VIEW)) { + return $response; + } + + $search = '%'.$request->query->get('q').'%'; + + $resultArray = array(); + + $categoriesI18n = CategoryI18nQuery::create()->filterByTitle($search, Criteria::LIKE)->limit(10); + $contentsI18n = ContentI18nQuery::create()->filterByTitle($search, Criteria::LIKE)->limit(10); + $foldersI18n = FolderI18nQuery::create()->filterByTitle($search, Criteria::LIKE)->limit(10); + $brandsI18n = BrandI18nQuery::create()->filterByTitle($search, Criteria::LIKE)->limit(10); + + $productsI18n = ProductI18nQuery::create()->filterByTitle($search, Criteria::LIKE)->limit(10); + $productsRef = ProductQuery::create()->filterByRef($search, Criteria::LIKE)->limit(10); + + /** @var \Thelia\Model\CategoryI18n $categoryI18n */ + foreach ($categoriesI18n as $categoryI18n) { + $category = $categoryI18n->getCategory(); + $resultArray['category'][$category->getId()] = $categoryI18n->getTitle(); + } + + /** @var \Thelia\Model\ContentI18n $contentI18n */ + foreach ($contentsI18n as $contentI18n) { + $content = $contentI18n->getContent(); + $resultArray['content'][$content->getId()] = $contentI18n->getTitle(); + } + + /** @var \Thelia\Model\FolderI18n $folderI18n */ + foreach ($foldersI18n as $folderI18n) { + $folder = $folderI18n->getFolder(); + $resultArray['folder'][$folder->getId()] = $folderI18n->getTitle(); + } + + /** @var \Thelia\Model\BrandI18n $brandI18n */ + foreach ($brandsI18n as $brandI18n) { + $brand = $brandI18n->getBrand(); + $resultArray['brand'][$brand->getId()] = $brandI18n->getTitle(); + } + + /** @var \Thelia\Model\ProductI18n $productI18n */ + foreach ($productsI18n as $productI18n) { + $product = $productI18n->getProduct(); + $resultArray['product'][$product->getId()] = $product->getRef().' : '.$productI18n->getTitle(); + } + + /** @var \Thelia\Model\Product $product */ + foreach ($productsRef as $product) { + $productI18n = ProductI18nQuery::create()->filterByProduct($product)->findOne(); + $resultArray['product'][$product->getId()] = $productI18n->getTitle(); + } + + return $this->jsonResponse(json_encode($resultArray)); + } + + /** + * @param int $rewriteId + * @param string $newView + * @param int $newViewId + */ + protected function allReassign( + EventDispatcherInterface $dispatcher, + $rewriteId, + $newView, + $newViewId + ) { + $origin = RewritingUrlQuery::create()->findOneById($rewriteId); + + $rewrites = RewritingUrlQuery::create() + ->filterByView($origin->getView()) + ->filterByViewId($origin->getViewId()) + ->find(); + + /** @var RewritingUrl $rewrite */ + foreach ($rewrites as $rewrite) { + $destination = RewritingUrlQuery::create() + ->filterByView($newView) + ->filterByViewId($newViewId) + ->filterByViewLocale($rewrite->getViewLocale()) + ->filterByRedirected(null) + ->findOne(); + + $rewrite + ->setView($newView) + ->setViewId($newViewId) + ->setRedirected(($destination === null) ? null : $destination->getId()); + + $dispatcher->dispatch( + new RewriteUrlEvent($rewrite), + RewriteUrlEvents::REWRITEURL_UPDATE + ); + } + } + + /** + * @param int $rewriteId + * @param string $newView + * @param int $newViewId + */ + protected function simpleReassign( + EventDispatcherInterface $dispatcher, + $rewriteId, + $newView, + $newViewId + ) { + $rewrite = RewritingUrlQuery::create()->findOneById($rewriteId); + + // add new default url + if (null !== $newDefault = RewritingUrlQuery::create()->findOneByRedirected($rewrite->getId())) { + $dispatcher->dispatch( + new RewriteUrlEvent( + $newDefault->setRedirected(null) + ), + RewriteUrlEvents::REWRITEURL_UPDATE + ); + } + + //Update urls who redirected to updated URL + if (null !== $isRedirection = RewritingUrlQuery::create()->findByRedirected($rewrite->getId())) { + /** @var \Thelia\Model\RewritingUrl $redirected */ + foreach ($isRedirection as $redirected) { + $dispatcher->dispatch( + new RewriteUrlEvent( + $redirected->setRedirected( + ($newDefault !== null) ? $newDefault->getId() : $rewrite->getRedirected() + ) + ), + RewriteUrlEvents::REWRITEURL_UPDATE + ); + } + } + + $rewrite->setView($newView) + ->setViewId($newViewId); + + //Check if default url already exist for the view with the locale + $rewriteDefault = RewritingUrlQuery::create() + ->filterByView($newView) + ->filterByViewId($newViewId) + ->filterByViewLocale($rewrite->getViewLocale()) + ->findOneByRedirected(null); + + if ($rewriteDefault !== null) { + $rewrite->setRedirected($rewriteDefault->getId()); + } else { + $rewrite->setRedirected(null); + } + + $event = new RewriteUrlEvent($rewrite); + $dispatcher->dispatch($event,RewriteUrlEvents::REWRITEURL_UPDATE); + } + + /** + * @param RewritingUrl $rewritingUrl + * @return null|string url + */ + protected function generateUrlByRewritingUrl(RewritingUrl $rewritingUrl) + { + if (isset($this->correspondence[$rewritingUrl->getView()])) { + $route = $this->getRoute( + "admin.".$this->correspondence[$rewritingUrl->getView()] . ".update", + [$rewritingUrl->getView().'_id' => $rewritingUrl->getViewId()] + ); + return URL::getInstance()->absoluteUrl( + $route, + [$rewritingUrl->getView().'_id' => $rewritingUrl->getViewId(), 'current_tab' => 'modules'] + ); + } + + return null; + } +} diff --git a/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvent.php b/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvent.php new file mode 100755 index 0000000..c5e9543 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvent.php @@ -0,0 +1,211 @@ + + * @author Gilles Bourgeat + */ +class RewriteUrlEvent extends ActionEvent +{ + /** @var int|null */ + protected $id; + + /** @var string */ + protected $url; + + /** @var string */ + protected $view; + + /** @var string */ + protected $viewLocale; + + /** @var int|null */ + protected $redirected; + + /** @var RewritingUrl */ + private $rewritingUrl; + + /** @var RewritingRedirectType */ + private $redirectType; + + /** + * @param RewritingUrl $rewritingUrl + * @param RewritingRedirectType $redirectType + */ + public function __construct(RewritingUrl $rewritingUrl, RewritingRedirectType $redirectType = null) + { + $this->id = $rewritingUrl->getId(); + $this->url = $rewritingUrl->getUrl(); + $this->view = $rewritingUrl->getView(); + $this->viewLocale = $rewritingUrl->getViewLocale(); + $this->redirected = $rewritingUrl->getRedirected(); + $this->rewritingUrl = $rewritingUrl; + $this->redirectType = $redirectType; + } + + /** + * @return RewritingUrl + */ + public function getRewritingUrl() + { + return $this->rewritingUrl; + } + + /** + * @return RewritingRedirectType + */ + public function getRedirectType() + { + return $this->redirectType; + } + + /** + * @param int $id|null + * @return $this + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @param array $parameters + * @return $this + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + + return $this; + } + + /** + * @return array + */ + public function getParameters() + { + return $this->parameters; + } + + /** + * @param boolean $propagationStopped + * @return $this + */ + public function setPropagationStopped($propagationStopped) + { + $this->propagationStopped = boolval($propagationStopped); + + return $this; + } + + /** + * @return boolean + */ + public function getPropagationStopped() + { + return $this->propagationStopped; + } + + /** + * @param null|int $redirected + * @return $this + */ + public function setRedirected($redirected) + { + $this->redirected = $redirected; + + return $this; + } + + /** + * @return null|int + */ + public function getRedirected() + { + return $this->redirected; + } + + /** + * @param string $url + * @return $this + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * @return null|int + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param $view + * @return $this + */ + public function setView($view) + { + $this->view = $view; + + return $this; + } + + /** + * @return null + */ + public function getView() + { + return $this->view; + } + + /** + * @param string $view_locale + * @return $this + */ + public function setViewLocale($view_locale) + { + $this->viewLocale = $view_locale; + + return $this; + } + + /** + * @return null + */ + public function getViewLocale() + { + return $this->viewLocale; + } +} diff --git a/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvents.php b/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvents.php new file mode 100755 index 0000000..d009f8a --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Event/RewriteUrlEvents.php @@ -0,0 +1,26 @@ + + */ +class RewriteUrlEvents +{ + const REWRITEURL_ADD = 'rewriteurl.action.add'; + const REWRITEURL_DELETE = "rewriteurl.action.delete"; + const REWRITEURL_UPDATE = "rewriteurl.action.update"; + const REWRITEURL_SET_DEFAULT = "rewriteurl.action.setdefault"; +} diff --git a/domokits/local/modules/RewriteUrl/EventListeners/KernelExceptionListener.php b/domokits/local/modules/RewriteUrl/EventListeners/KernelExceptionListener.php new file mode 100644 index 0000000..af160d9 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/EventListeners/KernelExceptionListener.php @@ -0,0 +1,69 @@ +requestStack = $requestStack; + } + + + public static function getSubscribedEvents() + { + return [ + KernelEvents::EXCEPTION => ['onKernelHttpNotFoundException', 300], + ]; + } + + public function onKernelHttpNotFoundException(ExceptionEvent $event) + { + if ($event->getThrowable() instanceof NotFoundHttpException) { + $urlTool = URL::getInstance(); + + $request = $this->requestStack->getCurrentRequest(); + $pathInfo = $request instanceof TheliaRequest ? $request->getRealPathInfo() : $request->getPathInfo(); + + // Check RewriteUrl text rules + $textRule = RewriteurlRuleQuery::create() + ->filterByOnly404(0) + ->filterByValue(ltrim($pathInfo, '/')) + ->filterByRuleType('text') + ->orderByPosition() + ->findOne(); + + if ($textRule) { + $event->setThrowable(new RedirectException($urlTool->absoluteUrl($textRule->getRedirectUrl()), 301)); + } + + $ruleCollection = RewriteurlRuleQuery::create() + ->filterByOnly404(1) + ->orderByPosition() + ->find(); + + /** @var RewriteurlRule $rule */ + foreach ($ruleCollection as $rule) { + if ($rule->isMatching($pathInfo, $request->query->all())) { + $event->setThrowable(new RedirectException($urlTool->absoluteUrl($rule->getRedirectUrl()), 301)); + return; + } + } + } + } +} diff --git a/domokits/local/modules/RewriteUrl/EventListeners/RewriteUrlListener.php b/domokits/local/modules/RewriteUrl/EventListeners/RewriteUrlListener.php new file mode 100755 index 0000000..818a588 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/EventListeners/RewriteUrlListener.php @@ -0,0 +1,161 @@ + + */ +class RewriteUrlListener implements EventSubscriberInterface +{ + protected $dispatcher; + + /** + * RewriteUrlListener constructor. + * @param EventDispatcherInterface $dispatcher + */ + public function __construct(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + + /** + * @return array + */ + public static function getSubscribedEvents() + { + return [ + RewriteUrlEvents::REWRITEURL_DELETE =>['deleteRewrite'], + RewriteUrlEvents::REWRITEURL_UPDATE =>['updateRewrite'], + RewriteUrlEvents::REWRITEURL_ADD =>['addRewrite'], + RewriteUrlEvents::REWRITEURL_SET_DEFAULT =>['setDefaultRewrite'] + ]; + } + + /** + * @param RewriteUrlEvent $event + */ + public function deleteRewrite(RewriteUrlEvent $event) + { + $rewritingUrl = $event->getRewritingUrl(); + + $newDefault = null; + + // test if default url + if ($event->getRewritingUrl()->getRedirected() === null) { + // add new default url + if (null !== $newDefault = RewritingUrlQuery::create()->findOneByRedirected($rewritingUrl->getId())) { + $this->dispatcher->dispatch( + new RewriteUrlEvent( + $newDefault->setRedirected(null) + ), + RewriteUrlEvents::REWRITEURL_UPDATE + ); + } + } + + $isRedirection = RewritingUrlQuery::create()->findByRedirected($rewritingUrl->getId()); + + //Update urls who redirected to deleted URL + /** @var \Thelia\Model\RewritingUrl $redirected */ + foreach ($isRedirection as $redirected) { + $this->dispatcher->dispatch( + new RewriteUrlEvent( + $redirected->setRedirected( + ($newDefault !== null) ? $newDefault->getId() : $rewritingUrl->getRedirected() + ) + ), + RewriteUrlEvents::REWRITEURL_UPDATE + ); + } + + $rewritingUrl->delete(); + } + + /** + * @param RewriteUrlEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function addRewrite(RewriteUrlEvent $event) + { + $rewritingUrl = $event->getRewritingUrl(); + $rewritingUrl->save(); + + if ($rewritingUrl->getRedirected() === null) { + //check if the new redirect is set to default if yes redirect all to the new one + RewritingUrlQuery::create() + ->filterByView($rewritingUrl->getView()) + ->filterByViewId($rewritingUrl->getViewId()) + ->filterByViewLocale($rewritingUrl->getViewLocale()) + ->update(array( + "Redirected" => $rewritingUrl->getId() + )); + + //Re set new url to default + $rewritingDefault = RewritingUrlQuery::create()->findOneById($rewritingUrl->getId()); + $rewritingDefault->setRedirected(null); + $rewritingDefault->save(); + } else { + $redirectType = $event->getRedirectType(); + if ($redirectType !== null) { + $redirectType->setId($rewritingUrl->getId()); + $redirectType->save(); + } + } + } + + /** + * @param RewriteUrlEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function setDefaultRewrite(RewriteUrlEvent $event) + { + $rewritingUrl = $event->getRewritingUrl(); + + //redirect all url to the new one + RewritingUrlQuery::create() + ->filterByView($rewritingUrl->getView()) + ->filterByViewId($rewritingUrl->getViewId()) + ->filterByViewLocale($rewritingUrl->getViewLocale()) + ->update(array( + "Redirected" => $rewritingUrl->getId() + )); + + //Re set new url to default + $rewritingUrl->setRedirected(null); + $rewritingUrl->save(); + } + + /** + * @param RewriteUrlEvent $event + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + */ + public function updateRewrite(RewriteUrlEvent $event) + { + $event->getRewritingUrl()->save(); + $redirectType = $event->getRedirectType(); + if ($redirectType !== null) { + $redirectType->save(); + } + } +} diff --git a/domokits/local/modules/RewriteUrl/Form/AddUrlForm.php b/domokits/local/modules/RewriteUrl/Form/AddUrlForm.php new file mode 100755 index 0000000..0eef997 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Form/AddUrlForm.php @@ -0,0 +1,87 @@ + + */ +class AddUrlForm extends BaseForm +{ + /** + * @return string + */ + public static function getName() + { + return "rewriteurl_add_form"; + } + + public function buildForm() + { + $this->formBuilder + ->add( + 'view', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'view-id', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'url', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'default', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'locale', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'httpcode', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ; + } +} diff --git a/domokits/local/modules/RewriteUrl/Form/ReassignForm.php b/domokits/local/modules/RewriteUrl/Form/ReassignForm.php new file mode 100755 index 0000000..1d2b2e6 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Form/ReassignForm.php @@ -0,0 +1,62 @@ + + */ +class ReassignForm extends BaseForm +{ + /** + * @return string + */ + public static function getName() + { + return "rewriteurl_reassign_form"; + } + + protected function buildForm() + { + $this->formBuilder + ->add( + 'rewrite-id', + IntegerType::class, + array( + 'required' => true + ) + ) + ->add( + 'select-reassign', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ) + ->add( + 'all', + IntegerType::class, + array( + 'required' => true + ) + ) + ; + } +} diff --git a/domokits/local/modules/RewriteUrl/Form/SetDefaultForm.php b/domokits/local/modules/RewriteUrl/Form/SetDefaultForm.php new file mode 100755 index 0000000..b548f9c --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Form/SetDefaultForm.php @@ -0,0 +1,46 @@ + + */ +class SetDefaultForm extends BaseForm +{ + /** + * @return string + */ + public static function getName() + { + return "rewriteurl_setdefault_form"; + } + + protected function buildForm() + { + $this->formBuilder + ->add( + 'rewrite-id', + TextType::class, + array( + 'constraints' => array(new NotBlank()), + 'required' => true + ) + ); + } +} diff --git a/domokits/local/modules/RewriteUrl/Hook/ConfigurationHook.php b/domokits/local/modules/RewriteUrl/Hook/ConfigurationHook.php new file mode 100644 index 0000000..6bffeb0 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Hook/ConfigurationHook.php @@ -0,0 +1,72 @@ + + */ +class ConfigurationHook extends BaseHook +{ + public function onModuleConfiguration(HookRenderEvent $event) + { + $event->add( + $this->render( + 'RewriteUrl/module-configuration.html', + [ + "isRewritingEnabled" => ConfigQuery::isRewritingEnable() + ] + ) + ); + } + + public function onModuleConfigurationJavascript(HookRenderEvent $event) + { + $event->add( + $this->render( + 'RewriteUrl/module-configuration-js.html', + [ + "isRewritingEnabled" => ConfigQuery::isRewritingEnable() + ] + ) + ); + } + + public function onConfigurationCatalogTop(HookRenderEvent $event) + { + $event->add($this->render( + 'configuration-catalog.html' + )); + } + + public function onMainTopMenuTools(HookRenderBlockEvent $event) + { + $event->add( + [ + 'id' => 'tools_menu_rewriteutl', + 'class' => '', + 'url' => URL::getInstance()->absoluteUrl('/admin/module/RewriteUrl'), + 'title' => $this->trans('Global URL Rewriting', [], RewriteUrl::MODULE_DOMAIN), + ] + ); + } +} diff --git a/domokits/local/modules/RewriteUrl/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/RewriteUrl/I18n/backOffice/default/fr_FR.php new file mode 100755 index 0000000..14aca64 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,86 @@ + '404 uniquement', + 'Actions' => 'Actions', + 'All your brands have rewriten urls' => 'Toutes vos marques ont des urls réécrites', + 'All your categories have rewriten urls' => 'Toutes vos rubriques ont des urls réécrites', + 'All your contents have rewriten urls' => 'Tous vos contenus ont des urls réécrites', + 'All your folders have rewriten urls' => 'Tous vos dossiers ont des urls réécrites', + 'All your products have rewriten urls' => 'Tous vos produits ont des urls réécrites', + 'Brand' => 'Marque', + 'Brands' => 'Marques', + 'Categories' => 'Rubriques', + 'Category' => 'Catégorie', + 'Change this category' => 'Modifier cette rubrique', + 'Change this content' => 'Modifier ce contenu', + 'Change this folder' => 'Modifier ce dossier', + 'Change this product' => 'Modifier ce produit', + 'Close' => 'Fermer', + 'Condition' => 'Condition', + 'Configuration' => 'Configuration', + 'Contents' => 'Contenus', + 'Currently enabled rules' => 'Règles activées', + 'Default' => 'Url par défaut', + 'Default Url' => 'URL par défaut', + 'Default url' => 'Url par défaut', + 'Delete Url' => 'Supprimer une Url', + 'Delete this redirect' => 'Supprimer cette redirection', + 'Do you really want to delete the url %html ?' => 'Voulez-vous vraiment supprimer l\'url %html ?', + 'Do you really want to set the url %html as default ?' => 'Définir %html comme URL part défaut ?', + 'Edit information in %lng' => 'Modifier l\'information en %lng', + 'Enable URL rewriting' => 'Activer la réécriture d\'URL', + 'Enter a URL with a leading \'/\' and no domain name. Ex : for \'www.mysite.com/one/two\', enter \'/one/two\'.' => 'Saisissez une URL commençant par un \'/\' et sans nom de domaine. Ex : pour \'www.monsite.com/un/deux\', saisissez \'/un/deux\'.', + 'Enter new rule position' => 'Saisir une nouvelle position de règle', + 'Error this url already exist you can reassign by follow this ' => 'Erreur cette url existe déjà, vous pouvez la réassigner en suivant ce ', + 'Folder' => 'Dossier', + 'Folders' => 'Dossiers', + 'For questions or bug reporting, thank you to use %url.' => 'Pour toutes questions ou déclaration de bug, merci d\'utiliser %url', + 'For the regex, your input is compare to URL without the domain name and without any GET params. Ex : for \'www.mysite.com/one/two?three=four\', your regex will be compare to \'/one/two\'.' => 'Pour une regex, votre expression régulière sera comparée aux URLs sans nom de domaine et sans paramètres GET. Ex : pour \'www.monsite.com/un/deux?trois=quatre\', votre regex sera comparée à \'/un/deux\'.', + 'GET params' => 'Paramètres GET', + 'Global URL Rewriting' => 'Ré-écritures URL globales', + 'Home' => 'Accueil', + 'ID' => 'ID', + 'List of not rewriten urls' => 'Liste des urls non réécrites', + 'Name' => 'Nom', + 'New url' => 'Nouvelle url', + 'No redirected url.' => 'Pas de redirection', + 'No results found for your search.' => 'Aucun resultat trouvé pour votre recherche.', + 'Not rewriten urls' => 'Urls non réécrites', + 'Permanent redirect' => 'Redirection permanente', + 'Please wait ...' => 'Veuillez patienter ...', + 'Position' => 'Position', + 'Product' => 'Produit', + 'Products' => 'Produits', + 'Reassign all urls' => 'Ré-attribuer toutes les urls', + 'Reassign the url' => 'Ré-attribuer l\'url', + 'Reassign this redirect' => 'Réassigner cette redirection', + 'Redirect all urls' => 'Rediriger toutes les urls', + 'Redirect all urls on a (category, product, folder, content, brand).' => 'Rediriger toutes les urls sur un/une (catégorie, produit, dossier, contenu, marque).', + 'Redirect the url %html on :' => 'Rediriger l\'url %html sur :', + 'Redirect to' => 'Rediriger vers', + 'Redirect to default' => 'Rediriger sur l\'url par défaut', + 'Redirected' => 'Redirigé vers', + 'Reference' => 'Référence', + 'Regex' => 'Regex', + 'Regex and GET params' => 'Expr. régulière + Param. GET', + 'Rule management' => 'Gestion des règles de redirection', + 'Rule type' => 'Type de règle', + 'Search' => 'Rechercher', + 'Set the config variable \'rewriting_enable\'' => 'Définit la valeur de la variable \'rewriting_enable\'.', + 'Set this redirect to default' => 'Mettre cette url par défaut', + 'Temporary redirect' => 'Redirection temporaire', + 'This action is irreversible after confirmation.' => 'Cette action est irréversible après confirmation.', + 'Title, Ref ...' => 'Titre, Ref ...', + 'Type' => 'Type', + 'Url' => 'Url', + 'Url redirected' => 'Url de redirection', + 'Validate' => 'Valider', + 'View locale' => 'Langue', + 'content' => 'Contenu', + 'exists' => 'existe', + 'is empty' => 'est vide', + 'is missing' => 'est manquante', + 'is not empty' => 'n\'est pas vide', + 'link' => 'lien', +); diff --git a/domokits/local/modules/RewriteUrl/I18n/fr_FR.php b/domokits/local/modules/RewriteUrl/I18n/fr_FR.php new file mode 100644 index 0000000..f9a53ca --- /dev/null +++ b/domokits/local/modules/RewriteUrl/I18n/fr_FR.php @@ -0,0 +1,19 @@ + 'Au moins un paramètre GET est requis.', + 'Get Params' => 'Paramètres GET', + 'Global URL Rewriting' => 'Ré-écritures URL globales', + 'Param condition is empty.' => 'Une des conditions d\'un paramètre GET est vide.', + 'Param name is empty.' => 'Le nom d\'un paramètre GET est vide.', + 'Redirect url cannot be empty.' => 'L URL redirigée ne peut pas être vide.', + 'Regex' => 'Expression régulière', + 'Regex and Get Params' => 'Expr. régulière + Param. GET', + 'Regex value cannot be empty.' => 'La valeur de l\'expression régulière ne peut pas être vide.', + 'This url is already used here %url.' => 'L URL est déjà utilisée ici : %url', + 'Unable to change the configuration variable.' => 'Impossible de changer la variable de configuration.', + 'Unable to find rule to change position.' => 'Impossible de trouver la règle pour le changement de position.', + 'Unable to find rule to remove.' => 'La règle à supprimer n a pas pu être trouvée.', + 'Unable to find rule to update.' => 'La règle à modifier n a pas pu être trouvée.', + 'Unknown rule type.' => 'Type de règle inconnu.', +); diff --git a/domokits/local/modules/RewriteUrl/LICENSE.txt b/domokits/local/modules/RewriteUrl/LICENSE.txt new file mode 100755 index 0000000..65c5ca8 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/domokits/local/modules/RewriteUrl/Loop/NotRewritenUrlCategoryLoop.php b/domokits/local/modules/RewriteUrl/Loop/NotRewritenUrlCategoryLoop.php new file mode 100644 index 0000000..c86160c --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Loop/NotRewritenUrlCategoryLoop.php @@ -0,0 +1,106 @@ + + * @author Gilles Bourgeat + * + * @method string getView() + */ +class NotRewritenUrlCategoryLoop extends BaseI18nLoop implements PropelSearchLoopInterface +{ + protected static $cacheRewritingUrl = []; + + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createEnumListTypeArgument( + 'view', + ['product', 'category', 'folder', 'content', 'brand'] + ) + ); + } + + public function buildModelCriteria() + { + $view = $this->getView()[0]; + + $rewritingUrlQuery = RewritingUrlQuery::create(); + + $class = 'Thelia\Model\\' . ucfirst($view) . 'Query'; + /** @var CategoryQuery|ProductQuery|FolderQuery|ContentQuery|BrandQuery $objectQuery */ + $objectQuery = $class::create(); + + $localeSearch = LangQuery::create()->findByIdOrLocale($this->getLang()); + + $rewritingUrlQuery->filterByView($view)->filterByViewLocale( + $localeSearch !== null ? $localeSearch->getLocale() : 'en_US' + ); + + if (!isset(static::$cacheRewritingUrl[$view])) { + static::$cacheRewritingUrl[$view] = $rewritingUrlQuery + ->select([RewritingUrlTableMap::VIEW_ID]) + ->groupBy(RewritingUrlTableMap::VIEW_ID) + ->find(); + } + + $query = $objectQuery + ->filterById(static::$cacheRewritingUrl[$view]->getData(), Criteria::NOT_IN); + + /* manage translations */ + $this->configureI18nProcessing($query, ['TITLE']); + + return $query; + } + + public function parseResults(LoopResult $loopResult) + { + /** @var Category|Product|Folder|Content|Brand $category */ + foreach ($loopResult->getResultDataCollection() as $category) { + $loopResultRow = (new LoopResultRow($category)) + ->set('ID', $category->getId()) + ->set('NAME', $category->getVirtualColumn('i18n_TITLE')); + + if (property_exists($category, 'ref')) { + $loopResultRow->set('REF', $category->getRef()); + } + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } +} diff --git a/domokits/local/modules/RewriteUrl/Loop/RewriteUrlLoop.php b/domokits/local/modules/RewriteUrl/Loop/RewriteUrlLoop.php new file mode 100755 index 0000000..1760d2b --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Loop/RewriteUrlLoop.php @@ -0,0 +1,104 @@ + + * @author Gilles Bourgeat + */ +class RewriteUrlLoop extends BaseLoop implements PropelSearchLoopInterface +{ + /** + * @return ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('id'), + Argument::createAnyTypeArgument('view'), + Argument::createIntTypeArgument('view_id'), + Argument::createIntTypeArgument('redirect') + ); + } + + /** + * @return \Thelia\Model\RewritingUrlQuery + */ + public function buildModelCriteria() + { + $search = RewritingUrlQuery::create(); + + if (null !== $id = $this->getId()) { + $search->filterById($id); + } + + if (null !== $view_id = $this->getViewId()) { + $search->filterByViewId($view_id)->filterByView($this->getView())->find(); + } + + $redirect = $this->getRedirect(); + if ($redirect == 1) { + $search->filterByRedirected(null, Criteria::NOT_EQUAL)->find(); + } elseif ($redirect == 0) { + $search->filterByRedirected(null, Criteria::EQUAL)->find(); + } + + return $search; + } + + /** + * @param LoopResult $loopResult + * @return LoopResult + */ + public function parseResults(LoopResult $loopResult) + { + $redirectTypeSearch = RewritingRedirectTypeQuery::create(); + foreach ($loopResult->getResultDataCollection() as $rewriteURl) { + $loopResultRow = (new LoopResultRow($rewriteURl)) + ->set('ID_URL', $rewriteURl->getID()) + ->set('URL', $rewriteURl->getUrl()) + ->set('VIEW', $rewriteURl->getView()) + ->set('VIEW_LOCALE', $rewriteURl->getViewLocale()) + ->set('REDIRECTED', $rewriteURl->getRedirected()) + ->set('VIEW_ID', $rewriteURl->getViewId()); + + + if ($rewriteURl->getRedirected()) { + $redirectType = $redirectTypeSearch->findPk($rewriteURl->getID()); + if ($redirectType == null) { + $httpcode = RewritingRedirectType::DEFAULT_REDIRECT_TYPE; + } else { + $httpcode = $redirectType->getHttpcode(); + } + $loopResultRow->set('HTTPCODE', $httpcode); + } + + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } +} diff --git a/domokits/local/modules/RewriteUrl/Loop/RewriteUrlRuleLoop.php b/domokits/local/modules/RewriteUrl/Loop/RewriteUrlRuleLoop.php new file mode 100644 index 0000000..023b852 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Loop/RewriteUrlRuleLoop.php @@ -0,0 +1,83 @@ +getId()){ + $search->filterById($id); + } + + if (null !== $ruleType = $this->getRuleType()){ + $search->filterByRuleType($ruleType); + } + + if (null !== $value = $this->getValue()){ + $search->filterByValue($value); + } + + if (null !== $redirectUrl = $this->getRedirectUrl()){ + $search->filterByRedirectUrl($redirectUrl); + } + + return $search->orderByPosition(); + } + + public function parseResults(LoopResult $loopResult) + { + /** @var RewriteurlRule $rewriteUrlRule */ + foreach ($loopResult->getResultDataCollection() as $rewriteUrlRule){ + $loopResultRow = (new LoopResultRow($rewriteUrlRule)) + ->set('ID', $rewriteUrlRule->getId()) + ->set('RULE_TYPE', $rewriteUrlRule->getRuleType()) + ->set('VALUE', $rewriteUrlRule->getValue()) + ->set('ONLY404', $rewriteUrlRule->getOnly404()) + ->set('REDIRECT_URL', $rewriteUrlRule->getRedirectUrl()) + ->set('POSITION', $rewriteUrlRule->getPosition()) + ->set('REWRITE_URL_PARAMS', $rewriteUrlRule->getRewriteUrlParamCollection()); + + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } +} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/Model/RewriteurlRule.php b/domokits/local/modules/RewriteUrl/Model/RewriteurlRule.php new file mode 100644 index 0000000..12f3c6d --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Model/RewriteurlRule.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace RewriteUrl\Model; + +use RewriteUrl\Model\Base\RewriteurlRule as BaseRewriteurlRule; +use Thelia\Log\Tlog; +use Thelia\Model\Tools\PositionManagementTrait; + +class RewriteurlRule extends BaseRewriteurlRule +{ + use PositionManagementTrait; + + /** @var string */ + public const TYPE_REGEX = 'regex'; + + /** @var string */ + public const TYPE_GET_PARAMS = 'params'; + + /** @var string */ + public const TYPE_REGEX_GET_PARAMS = 'regex-params'; + + /** @var string */ + public const TYPE_TEXT = 'text'; + + protected $rewriteUrlParamCollection = null; + + /** + * @return \Propel\Runtime\Collection\ObjectCollection|RewriteurlRuleParam[] + */ + public function getRewriteUrlParamCollection() + { + if ($this->rewriteUrlParamCollection === null) { + $this->rewriteUrlParamCollection = RewriteurlRuleParamQuery::create()->filterByIdRule($this->getId())->find(); + } + + return $this->rewriteUrlParamCollection; + } + + protected function isMatchingPath(string $url): bool + { + if (!empty($this->getValue())) { + try { + $match = @preg_match('/' . $this->getValue() . '/', $url); + + if (false === $match) { + Tlog::getInstance()->error('Invalid pattern: ' . $this->getValue()); + } + + return (bool)$match; + } catch (\Exception $ex) { + Tlog::getInstance()->error('Failed to match rule : ' . $ex->getMessage()); + } + } + + return false; + } + + protected function isMatchingGetParams(array $getParamArray): bool + { + if ($this->getRewriteUrlParamCollection()->count() === 0) { + return false; + } + + foreach ($this->getRewriteUrlParamCollection() as $rewriteUrlParam) { + if (!$rewriteUrlParam->isMatching($getParamArray)) { + return false; + } + } + + return true; + } + + public function isMatching(string $url, array $getParamArray): bool + { + if ($this->getRuleType() === self::TYPE_REGEX) { + return $this->isMatchingPath($url); + } + + if ($this->getRuleType() === self::TYPE_GET_PARAMS) { + return $this->isMatchingGetParams($getParamArray); + } + + if ($this->getRuleType() === self::TYPE_REGEX_GET_PARAMS) { + return $this->isMatchingPath($url) && $this->isMatchingGetParams($getParamArray); + } + + return false; + } + + public function deleteAllRelatedParam(): void + { + RewriteurlRuleParamQuery::create()->filterByIdRule($this->getId())->find()->delete(); + } +} diff --git a/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParam.php b/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParam.php new file mode 100644 index 0000000..fe37b75 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParam.php @@ -0,0 +1,53 @@ +getParamName(), $getParamArray)) { + $value = $getParamArray[$this->getParamName()]; + if (empty($value)) { + if ($this->getParamCondition() === self::PARAM_CONDITION_EMPTY) { + return true; + } + } else { + if ($this->getParamCondition() === self::PARAM_CONDITION_NOT_EMPTY) { + return true; + } + } + + if ($value == $this->getParamValue()) { + if ($this->getParamCondition() === self::PARAM_CONDITION_EQUALS) { + return true; + } + } else { + if ($this->getParamCondition() === self::PARAM_CONDITION_NOT_EQUALS) { + return true; + } + } + + if ($this->getParamCondition() === self::PARAM_CONDITION_EXISTS) { + return true; + } + + } else { + if ($this->getParamCondition() === self::PARAM_CONDITION_MISSING) { + return true; + } + } + + return false; + } +} diff --git a/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParamQuery.php b/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParamQuery.php new file mode 100644 index 0000000..96d4e10 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Model/RewriteurlRuleParamQuery.php @@ -0,0 +1,21 @@ + + */ +class RewritingUrlOverride extends RewritingUrl +{ + /** + * disable the Thelia behavior + * + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null): void + { + } +} diff --git a/domokits/local/modules/RewriteUrl/Readme.md b/domokits/local/modules/RewriteUrl/Readme.md new file mode 100755 index 0000000..87ae24c --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Readme.md @@ -0,0 +1,59 @@ +# Rewrite Url + +This module allows you to create general redirection rules for your website. You can also manage rewritten urls for products, categories, folders, contents, brands. + +* Allows you to redirect a url to another based on a regular expression or matching GET parameters +* Allows you to reassign a url to another (product, category, folder, content, brand) +* Allows you to reassign all urls to another (product, category, folder, content, brand) +* Allows you to reassign a default url to your (product, category, folder, content, brand) +* Allows you to display the list of not rewriten urls (product, category, folder, content, brand) + +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/thelia-modules/RewriteUrl/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/thelia-modules/RewriteUrl/?branch=master) +[![License](https://poser.pugx.org/thelia/rewrite-url-module/license)](https://packagist.org/packages/thelia/rewrite-url-module) +[![Latest Stable Version](https://poser.pugx.org/thelia/rewrite-url-module/v/stable)](https://packagist.org/packages/thelia/rewrite-url-module) + +#### [See the changelog](https://github.com/thelia-modules/RewriteUrl/blob/master/CHANGELOG.md) + +## Compatibility + +Thelia > 2.1 + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is RewriteUrl. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/rewrite-url-module:~1.5.8 +``` + +## Usage + +BackOffice : +- in Product edit tab modules +- in Folder edit tab modules +- in Content edit tab modules +- in Brand edit tab modules +- in Category edit tab modules +- in Configuration list not rewriten urls +- in the module configuration page + +## Screenshot + +#### In "Modules" tab + +![RewriteUrl](https://github.com/thelia-modules/RewriteUrl/blob/master/screenshot/screenshot-1.jpeg) + +#### In Thelia configuration + +![RewriteUrl](https://github.com/thelia-modules/RewriteUrl/blob/master/screenshot/screenshot-2.jpeg) + +#### In the module configuration + +![RewriteUrl](https://github.com/thelia-modules/RewriteUrl/blob/master/screenshot/screenshot-3.png) \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/RewriteUrl.php b/domokits/local/modules/RewriteUrl/RewriteUrl.php new file mode 100755 index 0000000..b70d3e6 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/RewriteUrl.php @@ -0,0 +1,130 @@ + + * @author Gilles Bourgeat + */ +class RewriteUrl extends BaseModule +{ + /** @var string */ + const MODULE_DOMAIN = "rewriteurl"; + + /** @var string */ + const MODULE_NAME = "rewriteurl"; + + /* @var string */ + const UPDATE_PATH = __DIR__ . DS . 'Config' . DS . 'update'; + + /** @static null|array */ + static protected $unknownSources; + + + public function preActivation(ConnectionInterface $con = null) + { + if (!$this->getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, array(__DIR__ . '/Config/thelia.sql')); + + $this->setConfigValue('is_initialized', true); + } + + return true; + } + + /** + * @param string $currentVersion + * @param string $newVersion + * @param ConnectionInterface $con + * @throws \Exception + * @throws \Propel\Runtime\Exception\PropelException + * @since 1.2.3 + */ + public function update($currentVersion, $newVersion, ConnectionInterface $con = null): void + { + $finder = (new Finder())->files()->name('#.*?\.sql#')->sortByName()->in(self::UPDATE_PATH); + + if ($finder->count() === 0) { + return; + } + + $database = new Database($con); + + /** @var \Symfony\Component\Finder\SplFileInfo $updateSQLFile */ + foreach ($finder as $updateSQLFile) { + if (version_compare($currentVersion, str_replace('.sql', '', $updateSQLFile->getFilename()), '<')) { + $database->insertSql(null, [$updateSQLFile->getPathname()]); + } + } + + /* + * Fix for urls that redirect on itself + */ + $urls = RewritingUrlQuery::create() + ->where(RewritingUrlTableMap::ID . " = " . RewritingUrlTableMap::REDIRECTED) + ->find(); + + /** @var RewritingUrl $url */ + foreach ($urls as $url) { + $parent = RewritingUrlQuery::create() + ->filterByView($url->getView()) + ->filterByViewId($url->getViewId()) + ->filterByViewLocale($url->getViewLocale()) + ->filterByRedirected(null) + ->findOne(); + + $url->setRedirected(($parent === null) ? null : $parent->getId())->save(); + } + } + + /** + * @return array|null + */ + public static function getUnknownSources() + { + if (static::$unknownSources === null) { + static::$unknownSources = []; + if (null !== $config = ConfigQuery::read('obsolete_rewriten_url_view', null)) { + static::$unknownSources[] = $config; + } + } + return static::$unknownSources; + } + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode() . '\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()) . '/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/RewriteUrl/Service/RewritingRouterFirst.php b/domokits/local/modules/RewriteUrl/Service/RewritingRouterFirst.php new file mode 100644 index 0000000..d03c1d4 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Service/RewritingRouterFirst.php @@ -0,0 +1,150 @@ +getRealPathInfo() : $request->getPathInfo(); + + // Check RewriteUrl text rules + $textRule = RewriteurlRuleQuery::create() + ->filterByOnly404(0) + ->filterByValue(ltrim($pathInfo, '/')) + ->filterByRuleType('text') + ->orderByPosition() + ->findOne(); + + if ($textRule) { + $this->redirect($urlTool->absoluteUrl($textRule->getRedirectUrl()), 301); + } + + // Check RewriteUrl rules + $ruleCollection = RewriteurlRuleQuery::create() + ->filterByOnly404(0) + ->orderByPosition() + ->find(); + + /** @var RewriteurlRule $rule */ + foreach ($ruleCollection as $rule) { + if ($rule->isMatching($pathInfo, $request->query->all())) { + $this->redirect($urlTool->absoluteUrl($rule->getRedirectUrl()), 301); + } + } + + try { + $rewrittenUrlData = $urlTool->resolve($pathInfo); + } catch (UrlRewritingException $e) { + switch ($e->getCode()) { + case UrlRewritingException::URL_NOT_FOUND: + throw new ResourceNotFoundException(); + break; + default: + throw $e; + } + } + + // If we have a "lang" parameter, whe have to check if the found URL has the proper locale + // If it's not the case, find the rewritten URL with the requested locale, and redirect to it. + if (null == !$requestedLocale = $request->get('lang')) { + if (null !== $requestedLang = LangQuery::create()->findOneByLocale($requestedLocale)) { + if ($requestedLang->getLocale() != $rewrittenUrlData->locale) { + $localizedUrl = $urlTool->retrieve( + $rewrittenUrlData->view, + $rewrittenUrlData->viewId, + $requestedLang->getLocale() + )->toString(); + + $this->redirect($urlTool->absoluteUrl($localizedUrl), 301); + } + } + } + + /* is the URL redirected ? */ + if (null !== $rewrittenUrlData->redirectedToUrl) { + $redirect = RewritingUrlQuery::create() + ->filterByView($rewrittenUrlData->view) + ->filterByViewId($rewrittenUrlData->viewId) + ->filterByViewLocale($rewrittenUrlData->locale) + ->filterByRedirected(null, Criteria::ISNULL) + ->findOne(); + + // Differences with the base class for handling 301 or 302 redirection + $redirectType = $this->fetchRewritingRedirectTypeFromUrl($rewrittenUrlData->rewrittenUrl); + + if ($redirectType == null) { + $httpRedirectCode = RewritingRedirectType::DEFAULT_REDIRECT_TYPE; + } else { + $httpRedirectCode = $redirectType->getHttpcode(); + } + // End of differences + + $this->redirect($urlTool->absoluteUrl($redirect->getUrl()), $httpRedirectCode); + } + + /* define GET arguments in request */ + + if (null !== $rewrittenUrlData->view) { + $request->attributes->set('_view', $rewrittenUrlData->view); + if (null !== $rewrittenUrlData->viewId) { + $request->query->set($rewrittenUrlData->view . '_id', $rewrittenUrlData->viewId); + } + } + + if (null !== $rewrittenUrlData->locale) { + $this->manageLocale($rewrittenUrlData, $request); + } + + + foreach ($rewrittenUrlData->otherParameters as $parameter => $value) { + $request->query->set($parameter, $value); + } + + return array( + '_controller' => 'Thelia\\Controller\\Front\\DefaultController::noAction', + '_route' => 'rewrite', + '_rewritten' => true, + ); + } + throw new ResourceNotFoundException(); + } + + /** + * @param $url + * @return RewritingRedirectType + */ + public function fetchRewritingRedirectTypeFromUrl($url) + { + return RewritingRedirectTypeQuery::create() + ->joinRewritingUrl() + ->useRewritingUrlQuery() + ->filterByUrl($url) + ->endUse() + ->findOne(); + } +} diff --git a/domokits/local/modules/RewriteUrl/Service/RewritingRouterLast.php b/domokits/local/modules/RewriteUrl/Service/RewritingRouterLast.php new file mode 100644 index 0000000..a273553 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/Service/RewritingRouterLast.php @@ -0,0 +1,54 @@ +getRealPathInfo() : $request->getPathInfo(); + + // Check RewriteUrl text rules + $textRule = RewriteurlRuleQuery::create() + ->filterByOnly404(1) + ->filterByValue(ltrim($pathInfo, '/')) + ->filterByRuleType('text') + ->orderByPosition() + ->findOne(); + + if ($textRule) { + $this->redirect($urlTool->absoluteUrl($textRule->getRedirectUrl()), 301); + } + + $ruleCollection = RewriteurlRuleQuery::create() + ->filterByOnly404(1) + ->orderByPosition() + ->find(); + + /** @var RewriteurlRule $rule */ + foreach ($ruleCollection as $rule) { + if ($rule->isMatching($pathInfo, $request->query->all())) { + $this->redirect($urlTool->absoluteUrl($rule->getRedirectUrl()), 301); + } + } + } + throw new ResourceNotFoundException(); + } +} diff --git a/domokits/local/modules/RewriteUrl/composer.json b/domokits/local/modules/RewriteUrl/composer.json new file mode 100755 index 0000000..304d74b --- /dev/null +++ b/domokits/local/modules/RewriteUrl/composer.json @@ -0,0 +1,25 @@ +{ + "name": "thelia/rewrite-url-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "RewriteUrl" + }, + "authors": [ + { + "name": "Vincent Lopes", + "email": "vlopes@openstudio.fr", + "homepage": "http://thelia.net", + "role": "Developer" + }, + { + "name": "Gilles Bourgeat", + "email": "gbourgeat@openstudio.fr", + "homepage": "http://thelia.net", + "role": "Developer" + } + ] +} \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/logo.jpg b/domokits/local/modules/RewriteUrl/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74847c054390b08ddf6e66ae4cf04c6aa7c69eb8 GIT binary patch literal 17459 zcmeIa2UwHawkR4a7DQ2sbPZ zN9n!yepzd;w%>Qoefz$5&%Lkg`F$bdpL32eN1JVoKb#MpPXZn)xa9($F2VQ<2K3;&7 zth*aC)X=f?w6zqsdMqpR zNXlKp9qs^!xR^h3huhgZOSnrv{*AcA1^jC@@8d_mb#bwkek}LvsE-Ul&mYMnoFI>c zc|^D^`S^t%iHh^^3yX+~i*h{@xOnE}6XO-&iIfcv5cx3h=6i@7_uy))Av6cixNmQGLy z7bwF1(XSNEEf7c->BkqG{zC+~!=GgTLtXu?BM9{0?+SqeCg6f>&55KhJO_}{|X?z zaf#~^*Og18fXk$pu8>|jZveDh%=AlFuUt_7a}~HnbmQjj%h#@7y>w9xxP0l_UrhkO zb)w6cu3Wu#H<*R=YBE5E<@jem1RuAfd zHicZo=f_}Ya^V~11psvXd%ku@+PCz0j_YShmhtqE4?KKwssTeSQhWfjF=(}ehT48pP-@T3mmK!+0nz;$gs`WQMoVIS>&wOLB=w53yFBLC(MG*> ziPf}TBinVP?(pZJe$)w{^^LN_dGcb&tJf3RZ>xPB!|iUWI0@`sw?cw>3r@7utKz+? z9^B7!9ibiTOsgQ_?K9KXiWo$4)hrp?=^L`r73U%n``WU4%1ZD!?jilGpP#GF0k`5p zQh%oIAw=K0BVHzPewV0RND1^bR?+V#?7LE-PjNE6xWp_RM{e9GSO+U6r;8R|mVj|+ z2YJP`vXv=39TGpa_na8Sb!|VCRIQwafL6-NxhoA9t=giT^?j;xu%|AoMUli~#@QY~ z!&p>>N{9dadm5_gs6K;Sd8;36XWZK|!tN9UlJQoBgU8|Y8lb$QN|hec>lC1fm!iBq zlIVsHz1sBrGtZ4Ibl#6J7xp*P%R_U zu;LSI4>wMbl&B<0aqGcJpVlMyBb`n$OvciweYU{@mrmw4&uGe4*)uLZA>0qhSSO0;qVV->3&49( z(N8zeEMtDm4Mui2OAK)S&~a~bc5gjRXys)FYpGeN994dtp?ZR8W1Eq1BKTuK2wL_Y zEcrv_#9A&akD-Q!cH}6#Xz{j{wUUyOm6bO$WJo|@k2w5{S3qzd$Y+TuohiwBt_R}#3@ufMG^0S zHyjvHF)?g3Cz;?|Wp!5M{urtb#%U6h8?x756K4_ay!2VvjacFxQIDq$4T5~o=q!CH zi@MNz5jC#eOP^>1hg-6!p`mVWQ1(S<<_hc5)T$EK8!bU+2)cCtTTTC>3tYKP>$Odz z!Iq6X}+wKerGd9fWD9zgtuY%oMb*Is*SN(genA2ap|n z&7m_DPR(L{T@Y#;Q>Dwxl&u@+8vb1~%@<3VnC-*ps5IWp;#I=U#qk8| zP;O~7$4f-xR!|pNr+aAQ&qc0&MQl1;Y`I%(dA(*iyykd~d;W*_Y-V$^_qdD2Xq7&heKHmgFD=3E;eVh@OG?|i(>6oQuW7_-rIVplnNez2QO5VxEL52> zjrl*XD|ZW60S{0)TrA4(E)%<9JL9?g`6-xHRx^k1Th&aWs3DkM7&zqU#s_%XmaM18;zpuK+S6pu@~boJFcy*a&dF~_%V?FtjS+oClj0+Wv-F%ASzv4IwAxN zFKr3Q-Ljh_{R)YyJqIN7uk=0nG9~)zN4vLLH@_(ViI-HgdjC{PW67Q>Jv{a1t3dU> zUd!er)zL+&Nw=i>EqP$J1QkI%bY!TY1NfTpiEnJ$I)w`17{piax zdm(qY7$&@w`<90*HzuZi5<%&buv{EJ(hEAg4{~y@0hd?zANsAa9P4F%2c_nNimPx{ z9v;z*aG9D3Xp&>`gi`VT&(G}}bDHBa#T6Q?AGX7Gk(S@3y{r19rlD1#(DiR}lO4$w z-cXlt(s{b2rRGnb#~x`OO?@8JeLvp5tB;j+IqF@cXX=t17zls5ySJ^r9h$Z!oL+m4 zC_unxaTnVwrJUfFolXB{d37#!o(42ytLby=E{WA?-?Cb&d$`!TzMk}z!O>2^E|K^a zLedEtJ#Fi8Iw4wRliqP6H^-AGuQbjk0WKPWlRjXR5|7;1#PLK-NljOq8tmMCfe`8z z8$mD`d2Kv*cV=BnHZo;u@M!j|C|IEXn}DBwmrwcM;{6v`k7&_(WiBp-IsHS0KU?=F zR3d+RKbGqFsw&sTdQe~Q@edDSzVML#a5*2N$QV&UP^kY%%MaS8t)a@%I+B+u7?g8M zn&^Du$`>BHw)LI^=o_>17E{&2Qq;JVyrWSgp&D!7vocyQ>MR9b4b3obSHYW9XXJ~ZBx58262h=LhFbfJwxNhFl|J+@?rEJ_1g zcA2J@{=z?R1Trfqepg(%wRzM010z|cZQ3HPJ4&Z$WVb8iLLJ%a?(`!` zO=2Ms;pqi=(iFTY>vvNQqkbs7m=p&Cs&tf7xVm}x4@lD7a>jY+0r~tW1R{MDYW7<& zgx(S4As&vN5r@2jn6*3nerFJx0%b}7}RF{M)OcTVR%5Vi2uG7T2 z2{L2oLuJXXC|ej**#<+gh$~1t2Q+HoP?<9ZO*H&Yhm5<7yW%m9dLsrQlkFB?!nTQV0#9M9*}_J`@hY)NMv3UauU5^BvJb8+Jd0d}ui${&0$-sBsu+ z%@%GS=B*~zcpll6k={B|TcOn44cPE~z^_?ZLf6Dm)0=zblr{Ul zYf4#taptP5BweB`#N*?}U7}4vvg1mvG4m0fz2wBOuH?e17I&g|2eCok;~8sws~ldM zUClO{!)8`eSH7L7H_EK_yFGM8OQ+9U7NxJ`3D95qdG^F2*$pNcA_+|D+b$UH+tZJ| z`xhH@SWW2R(8}U5XGg#Ek0|( z|0~0di8|u#dD0bCf5ZXmIxyheC2K}BTValf9}ofx5IsSn$ zXFl3CD8?f5d3q4?$w{8oqiPr`#5Ee-C`%zFv}H8dyFq8+LNgk3-8P&>fLRmBkVW`z zH_TFi#0XODN(NirkO_FHRlEd8fNr|Vhc*dSh1^Ig zu%8AKqPgOSqMK{Pyr01)1m`sT-8kuJl+r}@_%Qs#1-fOZdVKC68hZ=6))%y!P+;0F zh~ZhAODSJ1>ztNZ=Pv5Ols{W9q>X>%ePAd{>T&hv)#0hKSbWS6Fl;G2B}&|xkuj#T z*>-8E4v1Rr;d;OC$^-tz>*lCs%PkxvN>G8iro(ZHBP3wAMQh3M>j$1L&Ya717K>Sk}gq7levD{w_{vLR~_RQkRFkIxKr%22cQ7&7g1 zK&&j2@7ueZQr`OWUECAC|&BS&s(GjZBHVfrX79UNv@#;`vcgJf-Im+?_-B}1tkoaP+_W|t*q zaKJ#8Zk+Lp7N5zNdOj07>SSn};UsKhE!m|Y;y_RlV^z`NZM*Spw8B(yOuZq*$<0UEZ&RejFMel{ILf=HK{k*k^!q>Vi zS%2aE4SL8qSKk$FvcY)0USo+O(>0o$pu1q?xSy<(Ao*M&>6`d%#$k;*WNGSXO}pR9 zt?MTCI#JYSAIp0BN0M8W>1yP4KBR6$bcqJr)0Y+Dr}V8>xN1H6R~B`5M}J&tuq-WK_-njO%U3b)x$t@sx>A=t zeQoRAYR*B=WUFSYKAxm+W_yD-JAS65y;dT%sQY3xDDgriFJ`#x?P}`%s63P6?`J~;&;uU*=Cx^8jg}RSva>rdir=eROY1W%2tgG(})beQh!TKchc*S%2`0{aa~i4MKPA zXwG%ylnKc1?S}pG`MQ$K2ei3n&p@2HCy8J!r;%lzUYExlWQJPBI`YbdZ#z^kVJzTY!|MjXI7} z4?=yYHK|>aamEyttX?Jw2b{epjUI?qxLZTPoIc-D*=P%%TTd-?W?gG`_t4n$opFCl z(m-WFj={$Pf8F?=AJ+1Bh0^*Xf#6h;)MHuMqN28?(b+>dhYJ_ms1n&?9S5JE4%W|- zyntoV%Z$5dCJYomSH7|?n6oxlJ?DsYlR#$^;xqMds%)j=U7&K&xrlXH> z@jFhoVUhS=q^8}&K!Nb0y{n6rM6w^Ot*k4&aw1yoEJ>&+pM_yRJSqM)u6A_QyS1pY zp(W${_rJL~fQ0kl)*;7U$R%7b`o*E?q*w24jSH|(+zRIu+ z2WsH&n18^03|;Z@sU$=W0}F{XHm0_X@4uyp-%))WZhl+EfswEFsp$tSFtMZ z67?VoYV^^WnRyyN>QorwI65P&@(Xfcpi2$uh_b@$d5|c79PX;Dt*uOa(mS^`*Cmfy z!Qpb!#8%4p9?VLl(;*w#ZH+=YnieAn0D~v9f+be3SA$6$K>SC2<}SZLPBbQ}Y<@ zcV~69+dKyVi$5ibGRHwP&1-Ktg;CTx9}_E1D!-2@FoX%c8k56)*c^fr=hqW2jrHJT zA!)7L#eJYuR8;B*l;U^OH;9FWCQ4n#t5M{%_l@rZwZ5^;sBGhlvcV-)oO)5|M#wQN zyU18P7=95SnjlONx^0dvd=(@kd&AjJ@&~SfOt)|O%=$p7p$yUe``ud&sCz-E{6CEP z+xP!%-$<>T+qRvSFn%>d&3P}Qd!J6`ZiIoYy1>~`Ci|9Dld$ue7Qw)f8pM^qQ>R%a zEEF9QScF8qfIp?q7A1L6T(nwHu+2Rw%TzdKcpc&;Xsy!zrS=N5t$@Pd<1xa>K&!ll zwxs4`*&dp=D)2I{{P#4^jN$Cu(*g;1o(e9kB)<$UwDw&9blb2csU0@ch!)dyd-sq1 zJYm-DR9L{(?!<*edsp9C>*QhfChp7~T=K3NGSBOHB~`|bY^k$ryCM8-wb9o-r=QJ7^hiW4obWpoG zWS@hhu;d4r+mt1#iN2r8Y#2YM)`s-uC|70R%FLrHs>?BUlSRU5iA&TGqsHdy!!j}8}!=`s~NTBus%_G#bNw7=Ly4+dy0QKC!lKt`Y z)vBzg06?kfYy+({f7GiEX|ax++n42APckrl`x-a zHvU1tsltw{1$DBXc3*V4wOK}6HNnPjHsvTcTW#`&p9w0CY4d*?p(JV_Q>ie zT-xnpVY|zkrsN0;Evj7-2M3oL042k6S2mJy71IawlCse4FHVX_0caMDg5HT^KeL{5}7x(S!AW;D9cro#d*F=ijr z$U*_5EV+l$Y5BcYrOR?e?A%uf&He*xWwPFl?ZGWtB_*8;Lt3RSqv($LJ4dKc(9D-i z#q{?xrTLhl;)1dQUXG6dfQ;JBjjT_dMFpr1j-v$>t41uN)tLLoDS`5fDECz54aj?A zaFopoDe-424d6Y4&Z_(KcGG4PMzaK@^X;VwEaX{2mQF$vsUIUHdz)tK!$y%G5lj>h z@A6s1Rtnr0eoGUOw#9kfmftX)iW}5G{lVrw-E7uJrIonl?X%+kjQ$K$mpJJuS{6`l zaoU>kP2<&$M+K;6tId(AnxQRT+vAjZrI4dheG}vA(t%q-Wrp5nLODzJSa7R+zkj23 zH56Qag6wPj-ozu5^Ca<&bLq_XgCGeSdtNbvPakR+UoG}n=JR$3 z;D!1cg$r;QewaIXf~Sdb{kGoDezP83b+!4Xx-z7}JqDw*f;mPm!x7{{Jq9KO$~*nB zD%zQFQqL^WsJFn7BGEvvt)9~gWK2$iFLE0I%Vw(ybHo*NQD<3~+5~C?pP^Q4_GVWU zX-(>!Z>h2^zQpOW>&vP7z(DHhM7)pr?J#6F?!kW6=i~(3ufSI@yOZy3Fcpyy-{2co zaQ`^j5cYn$F_1zMDi8n6{_GwKsPf^%`|AM&K#1>Jz$ur*kH!1vfZ6vjmN@yt67Rt! z1vUM107-Q9Dc9}~JnN2pxis5Wa{Ha<`~yGu(%1CoA}|q$-kPt^0bHt#H!?Z@X_o^` z)&7!)%6s*ddZ=9Y9DtsntbSCOw=z6bQj{F2x39LYs2h2*6khG?5*j&`$^9Gv;1BGq z&oW_B5srwv4Kb&4;`tWm39o2SK6`J)t|2q|^QL9%@rZ239>e!J+5INT+Tck_ci&x# zlm;H&hVHu~w~aQ{o5{Sc+gtU;9R|}O$zpK>CBmX;?%ax?bgHoV?`e(MVk^y2&eR^- zsC2qTxHlai$P|JTN{T8PB<<#zjY*dSj+@iGYI4{$zh!Hw^-almaXp=Nsc?DH-novR zbyHOIXD5gT-PdAN<4}VU7Njm=8-QV9(RUDax}xb4-cg@2N^Y2oO$Thv3Cl-8h7m-g zq@95%{f3e40x_YX1lMUgnc^ChfnRy7Jy&sNEU&Se=PsHn861wgSrc$mW>><|r}vnz zLuk)_o%31Z$)XY&h6XdhU^Q-}Y3XclOSf+Ra$}}@QBAP5P%7MX(O^~&Z95aSW}`Q! zVTwC_c(%lcF9V5XIqFzprqpf~HgT`|iVB3v#lI|bBVKHA!+#w*O=0wZ%UkDat2OHM z*mGjQm&S8rwK)g&Lnr!_dcrEDLzl`iOaE#QP^Dr|-ovjO1R@D{1^36!WrwK-{ zNt?*_*8yo9cP;SKVUo3~66+dE>c{$0d7xPjjoqAe%GGgYe`0p+)9}2Y717TeLygLV znY`L}#yIwAM2<(_Py-V|g2Y!*+T5A>EmVO)=lhq(``!f7yI1lgT z+dJEq_4YilYIwqYg)?{i&Qi-_*~s^>6Zqq(6eC=578i67l|I7pQOhxTQdJ~bxnYl~ z;T%9@uqNIxfFLX1`(6}|0e>5gQPO#3bE$|EE0q!&Hq9l59B@Ae^u~)pA>3)&cPawn zJUHxnUwgyNab+G*Wh1R_p7m_b51c{54mvEgVQnsh+0^bwf#%g@{VB`@BFk?p+wT%Q zI_(eS+)@NO;=1&NZOq-^!PV)*=F9qJw#At*kbAir8VR#h&s=7yo><*w9gM&2Y-1v3 z-@)o)HL?x(gbPGNj0jgWb4lE;pAplz^K)Su79vbVnWT4=+q4Cqk8%j-M@g=S4OX`~ zdn?9S9Yu0?WE(+rK4lG*26>fCgZUG5@==%#ZFCJeT4|H`-5${dNOuwmW&N5P8lt7yr1rwLI`0U~6Tk*OBnI@$Wt1~7Bl{{H$ z#2(L0&w8Aou)mnne^XJkDnq24s%7>vQ3aejhwSME6Y#BDBj}l`Ae>t{!+OOu%jsh0bl|5Wzc!8Lx)>Y%zKStyPB5__>%$^R{@uND z@hruP!2d9HmOX49!VJXcLSPGfpdSZ!gfvfWKOBW?RTtxCflZNH<{(RbqBHl4>_Nsf zQ>$OAoGS30cxij5axI z+e(~RLirVZI|oee9cs@%GI{>}$3E-Rxj07CfdY)V-C|R*Y&~=Tm$Y(-l066cr#L4p zd!x{B*s3zRZ#}`8vJLq-&3ZRBL_rm65k?kFqgXzueLovZs8a|ewOeNSYzKrYo>D&l zBDk<1h|e@L*2U{bBAYs|7W2RfofYNPFRxV0dEzJXtXCKM5~2Og z8#<|I-J(ElYR0_3DXuU z)rgD@V$PSV+5SIP61wS|vN;RY>jwJyqEp9=1-_|!2+)Q_Cqg;Ycv`_fz@T|rN3Ai# zrLCf00D#N<=YR@^oq~GbRJC&ehAIOCy*oFs|00u=`^AZb+5S$^pwCcp56R37-}w`WqEHy%;jla!%LKHL($T?)xWPJy%qTqHhd9|@$ z=tg-1SrPD}E(_nqVLHeuCV)%nuZuJ2bDSJGrEc>Oq`E!=(n!I_Ni4`kcug}WQwCD2 ziT9hxzE5tm)JU@djjlL74_?^-*MWz-2x1n|;=|suj%uo}WF+(kjlN)E)UH(s%n7tD zb@DiXU3(&(*lKf_vNG(>bW8k2xa;8w_Zlb?CuZTSr_hXWuD)a=Cu1#ZV?UrSiT;|= zY=m^Mv!OKzwwK0>3>uP@(`hIpmC*M;puF|(?I?Zea&U;3P+@7d?9Fbgw>Q%DKBc5~RriK&(|v43Z&PZuSsxt^VPDe9 zyhqneR2K1#8m?Z|e(VUh|C>tQtNn!{tNC~mHFQ)h*if)q3VDsAsuBZ6YN zSuH`%j#k-!h-R9)9x3DD+d!K|iwwEHdV-CERf>sK-8x>T9Q(L~G_ET{Ew@4fZ^J<% zVUfU)2Km5sJ?mi~Wi_21e10cvu8VBoW5mMwBHb`!`{BwX1|{ug2m8!|ge=f)=?O zuYk=xDJle_tASMpax2mFMFmfEKXPOWv+H8m9A`0phk2I? z7pAdU9*o;~dxy?h%ls)UyHuth?HZS+xzJ2b!VPW-+- zlQWJ?Evxs_z-P=^CxvAuzrec8A)=S;&H-9;9|P8SbD3xmhHBJgpZ)mjH`b;2gGWjo z>p!l$$2Q#IOxjqNcQ^-V=;o{l*xo|(Zl<%Ddm(j!g+Um)bnB=D8wNcflr@aq`-Egs zeNY8Tl;x^m!0&2rlQ36#SHzn6fDlrOL>c9z2vmvzouq1TCSprkcq|Kt(T7TAORx75 z2>w0^==ZLahx4MMy1ATK7A{t>7sb}lsUkfnCP6b}jnPUY}8Ol0OtL^^o% z@aToAh&6<5=o~Pv%4IYh)HYz`OM;~1Zmg|tub!! zdK>QnhtC0NtNZ#kBlhB+l?NH6{$|~07TPj*Uhb2&50o3n%g|F02Gv8NzwU7+DEDjN zp9dPO6PAA2?!@{VQKP&SAJi%`(a?&deIoDFT+iJ3@e zH$ykp1(NSALineEiGwRCs(GU&7vmm!*=T@)Ja|saA1iLA3Rwt-x;Jag-Esz!-Vg3- z-n(WD-!-w~5$(T)(N5qMZb@~VQp{CazO z6aKRU8be_-X_?!4nF+mZgVg5$gmGbz<7rXyt7G~;SB+@sFdQbZQVANLOR4q`7jE-a zLR43n=sLD4i~6qH!eAU}4mn?@aabhwiPT60DA=NmoU}fx)I8eM(`ufZzR21%s+9zL z;~5GyIbI2I7Pgu_Hl42w=V3scSiZ4bkcg{G3vI{dO(HZ6&j_+rq1O{xjO`_Ho|Sqe zK<;m99&%-=6VD6OAKdu5{JHPvfj#GY9sN2O{+b?pxQ=DXciR}FG3%>h!uKYdLT^UX zf>FKqF}+x-2$$F}nVkeT8n3eHfXMqQIBwnkJTwPv@A-42sNS)kvE#cWnl65L3B?8o zkLepA*0|UjFW&xsc;OCrj|?Vjds)r_?Zo|RLIK;b+UB&N^k*zARLIfqw=~kL$^?kTE>!*Zs(#zWMP?Zre|;1 z1CyAwk}CX@sZCI-M)8aL!ftn0x7AF!op1~D6!(kEn-W;7mE5N*<|!tH5>N>aC~&m6 zzTYozfB92_e*jl6@^mh;ifKw`M^tu3m=D?6q3(W24#wm+JLJo7~d^*)Mdh zi^@@F2Cz3_xrhF;PPIZI#o_HsUh{_*sy7r>4gQJh|C~H90Pt_#{;%ZE|BLlDV47Am z7On5dubA&JhEigPnyRGaEJ$s8EKMzyr5fz@$j|wqj|E-OXaK#@=%SH&1?9?Z43-0l ztK`T8CVVL{Iq??<<}8?I6;G^8v%Z^~6}+=7HO<+5TX21kZck<)VW-p)>9X_GVk znOWGIzc;?7;ap=}Tx6i?@H+IAAj;Ve$&=#ht{rk4X56sLD+@?ZeQm?PKD)3$U(_W~ zwNWH<4lw^=74WUFW{N&3Vl$z+Hag{#XSZ0}c3sEuX@ED1;d3LDf+Vj@$g&hYoJBV$G79NB5xNiWOD z|M^`GrqFgHoUQFcOGp)at0d7d@A1qgvVMbip=Ju5c`$qWV#38#;kCj^@BVeAhm8Ho z4Vs<24%crWNjD#CtBqZHOZSgPz{>zF22xp}>aYK!opy&b$Ymv}?NPB-CUEc=jQQiYv;ZT%f{Ec+jBmTWacO|BBJo*3dzr&-Tq8Ut~VVsX{MuVlr<+ zQmShDB%H@EGS6^!tHbgirv*00Ai+e@_L#V2k=IuBFd+qr(KUf~rRA_{##tfN#T7>O z#g*6{V$17ETw|GrK*@qF%vaGnzx>4k0Kh7JY-s_sd6QVgJ+v-L;YKF@c2dQN41@h5 zQaTX9%puWHk&6ukahFiJ>~KFZYkim}Z2N-r?bhCJDhsmZ%{U1wx`<1-JZ{MNJKYPo zf#+-n-roHImx5Y7sWgVTH$h^%BOEbFW!(tACCTH%u*_xR_hz!>V2%`%;i?oT?E<4P zu$i#Ll+F^N#LaaiK(ORX#xrPN&^HA0h{@2luXbvA->~U`jhO>1HHjBl96w*5d_-n> zFyqv}>5DwHs#(*jok|!@O4g;Jr)cxYLdKkl)0RlR822&ct&Eb=j(6@``aEfu9+z$y zJ{{4n-FP}Ui#jfsZxk<;mdW~mI7;lpH6eGY$=c_e%4NIOU-H_ge|qjS1qKa1UgnMU zu*#Mg;rP<3|G4#F0oltH(W(MeuT6`(?G3d*446qfO+A!dvako2*xi{9- zMett*3W-*-Nr_aw4yLOeygwv6bjSJPZ7k%E=-OEl*OM?xbIsN5@VzS+?~e7Ey3MX1 z%GELsX&=9ypFh5o>${j+xwU`t>Bq+v_R|_C&DV5Je6#HhvcwX`PNv^icdf+nl((!w zyFTL;!8Zzn_Gfx$uoO&MUM3Xli4@{= znqfvqP*HtW8gmg-HKdf=)d4QZe2duo)jLZxvjY4JlVFL~)(pxE(?$oZ~B{zVZH!k%-o;~{ufVkh=4x0)kNaFLF#vC%fGtGXc} zs~uf?FjO8fVLaM%F~f`-m7+W@a%Z7=iRhPh@n8QB)A+B)OPYH%txY>?#a;NM7wl#3 z6IX&wW<|Pi4MO(HnSLv&_2z0T9FTV{YQ#*1_EJ+|1#2sLPk*X0J^x!?HsZ{+_oRIl$6v4jOG@N8HZS?L>5Ebma$Ii@-7Z;wJ(}-OTuCM`7laJ@Du@S=2dT zQS~+~QLHze`uPcIklHcVtz4|CZYD?J2{;mQR2n$fbn!m`0Ko7Fiaq~GDCkZ7YSfIo zVzyH(m5=P5L0=r}^{xcg84f1pVQry9uludjJasZjtqgUH*9Js#Dfudcc3Ei|4pVyb zw*}y7_ByLr*g1ffCFl&b;C|SXBuBygpKIhV-2edE@OsR=*ptGJty5@D+M33bUT$~xCSX-%0fJ|HsI2|g6-CJaaM=+%f3(yoZYG7a05njwK}T6Bl`yH}oiqW-vEI2W z;}r$j@zy+{)yz4k>Mf6Jx}xJ1#grq47nwe(Zki#qAek%72jWR!i4>OZ! z)U!yBGqahnias-RX`cFeu%`JVH|L1xTT%GlI*vYKX<*KKPStldTHS~1ZrIG}(Ng!P ze+d(Xci5~;7vp(|?-DF43BRsSTFB*rP)3`|Ixfyb1zmQ}PI5rSOr_a^jqmp#MVE4j3{gp1I=Gfr?W!BL6LvJ|;>-czk_c^qCI zH)S@88h9xr-?3GFnR@UhB)~rom}3}kG}hMVz8sqJ0ySe}NkVhb&tWGaDS}Rm372FS zu%asMx6SZ5RbX_(5Of}4Z5^^z+lfV4Xenj5Vur`f2IE5qDpSa59e;!rydL7Ng}#>0 Tlf3tL*Z4R5zg+`Y&WHaS{cM6B literal 0 HcmV?d00001 diff --git a/domokits/local/modules/RewriteUrl/screenshot/screenshot-1.jpeg b/domokits/local/modules/RewriteUrl/screenshot/screenshot-1.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..544098d689b9d27d3d9220a04e365bb9b8e15ced GIT binary patch literal 107388 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 YNasK#PZQ_)OVrp8T?Z-|f(N7j1xEyXSO5S3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/RewriteUrl/screenshot/screenshot-3.png b/domokits/local/modules/RewriteUrl/screenshot/screenshot-3.png new file mode 100644 index 0000000000000000000000000000000000000000..4619f59162e42c4c5d692c3b0e994a19df7fd8f3 GIT binary patch literal 123206 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 WW@<&}p9&TLe)cxbyQx-w34Z}}lFzCD literal 0 HcmV?d00001 diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration-js.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration-js.html new file mode 100644 index 0000000..4edec76 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration-js.html @@ -0,0 +1,425 @@ +{default_translation_domain domain='googleshoppingxml.bo.default'} + +{javascripts file="assets/js/bootstrap-switch/bootstrap-switch.js"} + +{/javascripts} + +{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} + +{/javascripts} + + + + + + diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration.html new file mode 100644 index 0000000..34e54a6 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/module-configuration.html @@ -0,0 +1,140 @@ +{$d='rewriteurl.bo.default'} + + +{include file="RewriteUrl/module-configuration-js.html"} + diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module-js.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module-js.html new file mode 100755 index 0000000..a9404ff --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module-js.html @@ -0,0 +1,188 @@ + \ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module.html new file mode 100755 index 0000000..b88b92a --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-module.html @@ -0,0 +1,327 @@ +{* +/*************************************************************************************/ +/* This file is part of the RewriteUrl module for Thelia. */ +/* */ +/* Copyright (c) OpenStudio */ +/* email : dev@thelia.net */ +/* web : http://www.thelia.net */ +/* */ +/* For the full copyright and license information, please view the LICENSE.txt */ +/* file that was distributed with this source code. */ +/*************************************************************************************/ +*} + +
+
+
+
+ + + + {ifloop rel="rewriteUrl"} + + + + + + + + + + + {loop type="rewrite_url" name="rewriteUrl" view_id="{$ID}" view="{$viewName}" redirect="0"} + + + + + + + {/loop} + + {/ifloop} +
+ {intl l='Default url' d="rewriteurl.bo.default"} + +
#{intl l='View locale' d="rewriteurl.bo.default"}{intl l='Url' d="rewriteurl.bo.default"}{intl l='Actions' d="rewriteurl.bo.default"}
+ {$ID_URL} + + {$code = "_"|explode:$VIEW_LOCALE} + {$VIEW_LOCALE} + + {$URL} + + + +
+
+
+ + + + {ifloop rel="rewriteUrl"} + + + + + + + + + + + + + {loop type="rewrite_url" name="rewriteUrl" view_id="{$ID}" view="{$viewName}" redirect="1"} + + + + + + + + + {/loop} + + {/ifloop} + {elseloop rel="rewriteUrl"} + + + + + + {/elseloop} +
+ {intl l='Url redirected' d="rewriteurl.bo.default"} +
#{intl l='View locale' d="rewriteurl.bo.default"}{intl l='Url' d="rewriteurl.bo.default"}{intl l='Redirected' d="rewriteurl.bo.default"}{intl l='Type' d="rewriteurl.bo.default"}{intl l='Actions' d="rewriteurl.bo.default"}
+ {$ID_URL} + + {$code = "_"|explode:$VIEW_LOCALE} + {$VIEW_LOCALE} + + {$URL} + + {$REDIRECTED} + + + +
+ + + +
+
+
+ {intl l="No redirected url." d="rewriteurl.bo.default"} +
+
+
+ {intl l="New url" d="rewriteurl.bo.default"} +
+ {form name="rewriteurl.add.form"} +
+ + {form_hidden_fields form=$form} + + {if $form_error} +
{$form_error_message nofilter}
+ {/if} + +
+ + {form_field form=$form field='success_url'} + + {/form_field} + + {form_field form=$form field="view"} + + {/form_field} + + {form_field form=$form field="view-id"} + + {/form_field} + +
+
+
+ {form_field form=$form field="locale"} + + {/form_field} +
+
+
+
+ {form_field form=$form field="url"} +
+ {$url_language|default:{config key="url_site"}}/ + +
+ {/form_field} +
+
+
+
+ {form_field form=$form field="default"} + + {/form_field} +
+
+
+
+ {form_field form=$form field="httpcode"} + + {/form_field} +
+
+
+ +
+
+
+ {/form} +
+
+ + {loop type="rewrite_url" name="rewriteUrl" view_id=$ID view=$viewName limit=1} +
+

+ {intl l='Redirect all urls' d="rewriteurl.bo.default"} +

+
+
+
+ {intl l="Redirect all urls on a (category, product, folder, content, brand)." d="rewriteurl.bo.default"} +
+ {intl l="This action is irreversible after confirmation." d="rewriteurl.bo.default"} +
+ +
+
+
+ {/loop} +
+ + + + {* -- Delete RewriteUrl confirmation dialog ----------------------------------- *} + + {capture "rewrite_delete_dialog"} + + {/capture} + + {include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "rewrite_delete_dialog" + dialog_title = {intl l="Delete Url" d="rewriteurl.bo.default"} + dialog_message = {intl l="Do you really want to delete the url %html ?" d="rewriteurl.bo.default" html=""} + + form_action = {url path='/admin/module/rewriteurl/delete'} + form_content = {$smarty.capture.rewrite_delete_dialog nofilter} + } + + + {* -- Default RewriteUrl confirmation dialog ----------------------------------- *} + + {capture "rewrite_default_dialog"} + + {/capture} + + {include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "rewrite_default_dialog" + dialog_title = {intl l="Default Url" d="rewriteurl.bo.default"} + dialog_message = {intl l="Do you really want to set the url %html as default ?" d="rewriteurl.bo.default" html=""} + + form_action = {url path='/admin/module/rewriteurl/setdefault'} + form_content = {$smarty.capture.rewrite_default_dialog nofilter} + } + +
\ No newline at end of file diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-value-render.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-value-render.html new file mode 100644 index 0000000..dcce3e7 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/RewriteUrl/tab-value-render.html @@ -0,0 +1,44 @@ +
+ / + + / +
+ +
+ / + + +
+ +
+ {foreach from=$REWRITE_URL_PARAMS item=ruleParam} +
+
+
+ +
+ +
+ +
+ +
+ +
+ + + + + + +
+
+ {/foreach} +
diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/configuration-catalog.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/configuration-catalog.html new file mode 100644 index 0000000..164b010 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/configuration-catalog.html @@ -0,0 +1,6 @@ +{loop type="auth" name="can_change" role="ADMIN" module="RewriteUrl" access="VIEW"} + + {intl l='Not rewriten urls' d="rewriteurl.bo.default"} + + +{/loop} diff --git a/domokits/local/modules/RewriteUrl/templates/backOffice/default/list-notrewritenurls.html b/domokits/local/modules/RewriteUrl/templates/backOffice/default/list-notrewritenurls.html new file mode 100644 index 0000000..2029b34 --- /dev/null +++ b/domokits/local/modules/RewriteUrl/templates/backOffice/default/list-notrewritenurls.html @@ -0,0 +1,425 @@ +{extends file="admin-layout.tpl"} + +{block name="no-return-functions"} + {$admin_current_location = 'configuration'} +{/block} + +{block name="page-title"}{intl l='List of not rewriten urls' d="rewriteurl.bo.default"}{/block} + +{block name="main-content"} +
+
+ + + +
+
+
+
+ {intl l="List of not rewriten urls" d="rewriteurl.bo.default"} +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
+ {ifloop rel="list-notrewritenurls-category"} +
+ + + + + + + + + + + + {loop type="list-notrewritenurls" name="list-notrewritenurls-category" page=$page_category backend_context="on" lang=$edit_language_id view="category" limit="10"} + + + + + + {/loop} + + + + + + +
+ {intl l='Categories' d="rewriteurl.bo.default"} +
+ {intl l='ID' d="rewriteurl.bo.default"} + + {intl l='Name' d="rewriteurl.bo.default"} + + {intl l='Actions' d="rewriteurl.bo.default"} +
+ {$ID} + + {$NAME} + + + + +
+ {include + file = "includes/pagination.html" + + loop_ref = "list-notrewritenurls-category" + max_page_count = 10 + page_param_name = "page_category" + page_url = {url path="/admin/list-notrewritenurls" current_tab='categories'} + } + +
+
+ {/ifloop} + {elseloop rel="list-notrewritenurls-category"} +
+
+ {intl l="All your categories have rewriten urls" d="rewriteurl.bo.default"} +
+ {/elseloop} +
+
+ {ifloop rel="list-notrewritenurls-product"} +
+ + + + + + + + + + + + + {loop type="list-notrewritenurls" name="list-notrewritenurls-product" lang=$edit_language_id view='product' page=$page_product limit="10" backend_context="on"} + + + + + + + {/loop} + + + + + + +
+ {intl l='Products' d="rewriteurl.bo.default"} +
+ {intl l='ID' d="rewriteurl.bo.default"} + + {intl l='Name' d="rewriteurl.bo.default"} + + {intl l='Reference' d="rewriteurl.bo.default"} + + {intl l='Actions' d="rewriteurl.bo.default"} +
+ {$ID} + + {$NAME} + + {$REF} + + + + +
+ {include + file = "includes/pagination.html" + + loop_ref = "list-notrewritenurls-product" + max_page_count = 10 + page_param_name = "page_product" + page_url = {url path="/admin/list-notrewritenurls" current_tab='products'} + } + +
+
+ {/ifloop} + {elseloop rel="list-notrewritenurls-product"} +
+
+ {intl l="All your products have rewriten urls" d="rewriteurl.bo.default"} +
+ {/elseloop} +
+
+ {ifloop rel="list-notrewritenurls-brand"} +
+ + + + + + + + + + + + {loop type="list-notrewritenurls" name="list-notrewritenurls-brand" lang=$edit_language_id view='brand' page=$page_brand limit="10" backend_context="on"} + + + + + + {/loop} + + + + + + +
+ {intl l='Brands' d="rewriteurl.bo.default"} +
+ {intl l='ID' d="rewriteurl.bo.default"} + + {intl l='Name' d="rewriteurl.bo.default"} + + {intl l='Actions' d="rewriteurl.bo.default"} +
+ {$ID} + + {$NAME} + + + + +
+ {include + file = "includes/pagination.html" + + loop_ref = "list-notrewritenurls-brand" + max_page_count = 10 + page_param_name = "page_brand" + page_url = {url path="/admin/list-notrewritenurls" current_tab='brands'} + } +
+
+ {/ifloop} + {elseloop rel="list-notrewritenurls-brand"} +
+
+ {intl l="All your brands have rewriten urls" d="rewriteurl.bo.default"} +
+ {/elseloop} +
+
+ {ifloop rel="list-notrewritenurls-folder"} +
+ + + + + + + + + + + + {loop type="list-notrewritenurls" name="list-notrewritenurls-folder" lang=$edit_language_id view='folder' page=$page_folder limit="10" backend_context="on"} + + + + + + {/loop} + + + + + + +
+ {intl l='Folders' d="rewriteurl.bo.default"} +
+ {intl l='ID' d="rewriteurl.bo.default"} + + {intl l='Name' d="rewriteurl.bo.default"} + + {intl l='Actions' d="rewriteurl.bo.default"} +
+ {$ID} + + {$NAME} + + + + +
+ {include + file = "includes/pagination.html" + + loop_ref = "list-notrewritenurls-folder" + max_page_count = 10 + page_param_name = "page_folder" + page_url = {url path="/admin/list-notrewritenurls" current_tab='folders'} + } +
+
+ {/ifloop} + {elseloop rel="list-notrewritenurls-folder"} +
+
+ {intl l="All your folders have rewriten urls" d="rewriteurl.bo.default"} +
+ {/elseloop} +
+
+ {ifloop rel="list-notrewritenurls-content"} +
+ + + + + + + + + + + + {loop type="list-notrewritenurls" name="list-notrewritenurls-content" lang=$edit_language_id view='content' page=$page_content limit="10" backend_context="on"} + + + + + + {/loop} + + + + + + +
+ {intl l='Contents' d="rewriteurl.bo.default"} +
+ {intl l='ID' d="rewriteurl.bo.default"} + + {intl l='Name' d="rewriteurl.bo.default"} + + {intl l="Actions" d="rewriteurl.bo.default"} +
+ {$ID} + + {$NAME} + + + + +
+ {include + file = "includes/pagination.html" + + loop_ref = "list-notrewritenurls-content" + max_page_count = 10 + page_param_name = "page_content" + page_url = {url path="/admin/list-notrewritenurls" current_tab='contents'} + } +
+
+ {/ifloop} + {elseloop rel="list-notrewritenurls-content"} +
+
+ {intl l="All your contents have rewriten urls" d="rewriteurl.bo.default"} +
+ {/elseloop} +
+
+
+
+
+
+
+
+{/block} + +{block name="javascript-initialization"} + +{/block} \ No newline at end of file diff --git a/domokits/local/modules/ShortCode/Config/TheliaMain.sql b/domokits/local/modules/ShortCode/Config/TheliaMain.sql new file mode 100644 index 0000000..37f0982 --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/TheliaMain.sql @@ -0,0 +1,25 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- short_code +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `short_code`; + +CREATE TABLE `short_code` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `tag` VARCHAR(55) NOT NULL, + `event` VARCHAR(255) NOT NULL, + `active` TINYINT, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + UNIQUE INDEX `short_code_U_1` (`tag`) +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/ShortCode/Config/config.xml b/domokits/local/modules/ShortCode/Config/config.xml new file mode 100644 index 0000000..8f50daf --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/config.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/ShortCode/Config/module.xml b/domokits/local/modules/ShortCode/Config/module.xml new file mode 100644 index 0000000..a75ed8d --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/module.xml @@ -0,0 +1,43 @@ + + + ShortCode\ShortCode + + Add short codes Wordpress'ShortCode syntax + + + + Ajoute les short codes avec la syntax wordpress + + + + + en_US + fr_FR + + 2.0.0 + + + Vincent Lopes-Vicente + vlopes@openstudio.fr + + + classic + + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/ShortCode/Config/routing.xml b/domokits/local/modules/ShortCode/Config/routing.xml new file mode 100644 index 0000000..480ce41 --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/routing.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/domokits/local/modules/ShortCode/Config/schema.xml b/domokits/local/modules/ShortCode/Config/schema.xml new file mode 100644 index 0000000..ddd0c15 --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/schema.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + +
+ +
diff --git a/domokits/local/modules/ShortCode/Config/sqldb.map b/domokits/local/modules/ShortCode/Config/sqldb.map new file mode 100644 index 0000000..63a93ba --- /dev/null +++ b/domokits/local/modules/ShortCode/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +thelia.sql=thelia diff --git a/domokits/local/modules/ShortCode/Event/ShortCodeEvent.php b/domokits/local/modules/ShortCode/Event/ShortCodeEvent.php new file mode 100644 index 0000000..d3fb3ff --- /dev/null +++ b/domokits/local/modules/ShortCode/Event/ShortCodeEvent.php @@ -0,0 +1,60 @@ +content = $content; + $this->attributes = $attributes; + $this->result = $content; + } + + /** + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * @return string + */ + public function getResult() + { + return $this->result; + } + + /** + * @param string $result + */ + public function setResult($result) + { + $this->result = $result; + } +} \ No newline at end of file diff --git a/domokits/local/modules/ShortCode/EventListener/ResponseListener.php b/domokits/local/modules/ShortCode/EventListener/ResponseListener.php new file mode 100644 index 0000000..502aaf4 --- /dev/null +++ b/domokits/local/modules/ShortCode/EventListener/ResponseListener.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ShortCode\EventListener; + +use Maiorano\Shortcodes\Library\SimpleShortcode; +use Maiorano\Shortcodes\Manager\ShortcodeManager; +use ShortCode\Event\ShortCodeEvent; +use ShortCode\Model\ShortCode; +use ShortCode\Model\ShortCodeQuery; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Thelia\Log\Tlog; + +class ResponseListener implements EventSubscriberInterface +{ + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + + public function __construct( + EventDispatcherInterface $eventDispatcher + ) { + $this->eventDispatcher = $eventDispatcher; + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::RESPONSE => [['dispatchShortCodeEvents', 64]], + ]; + } + + public function dispatchShortCodeEvents(ResponseEvent $event): void + { + if ($event->getRequest()->get('disable_shortcode', 0) == 1) { + return; + } + + $response = $event->getResponse(); + + if ( + $response instanceof BinaryFileResponse + || $response instanceof StreamedResponse + || $response instanceof RedirectResponse + || $response instanceof JsonResponse + ) { + return; + } + + $dispatcher = $this->eventDispatcher; + + $simpleShortCodes = []; + + $shortCodes = ShortCodeQuery::create() + ->filterByActive(1) + ->find(); + + /** @var ShortCode $shortCode */ + foreach ($shortCodes as $shortCode) { + $simpleShortCodes[$shortCode->getTag()] = new SimpleShortcode($shortCode->getTag(), null, function ($content, $attributes) use ($shortCode, $dispatcher) { + $shortCodeEvent = new ShortCodeEvent($content, $attributes); + $dispatcher->dispatch($shortCodeEvent, $shortCode->getEvent()); + + return $shortCodeEvent->getResult(); + }); + } + + $manager = new ShortcodeManager($simpleShortCodes); + + $content = $response->getContent(); + + try { + $content = $manager->doShortCode($content, null, true); + } catch (\Exception $exception) { + Tlog::getInstance()->error($exception->getMessage()); + } + + $response->setContent($content); + } +} diff --git a/domokits/local/modules/ShortCode/I18n/en_US.php b/domokits/local/modules/ShortCode/I18n/en_US.php new file mode 100755 index 0000000..0b4fa14 --- /dev/null +++ b/domokits/local/modules/ShortCode/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/domokits/local/modules/ShortCode/I18n/fr_FR.php b/domokits/local/modules/ShortCode/I18n/fr_FR.php new file mode 100755 index 0000000..3708624 --- /dev/null +++ b/domokits/local/modules/ShortCode/I18n/fr_FR.php @@ -0,0 +1,4 @@ + 'La traduction française de la chaine', +); diff --git a/domokits/local/modules/ShortCode/LICENCE b/domokits/local/modules/ShortCode/LICENCE new file mode 100644 index 0000000..3312f1f --- /dev/null +++ b/domokits/local/modules/ShortCode/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/domokits/local/modules/ShortCode/Model/ShortCode.php b/domokits/local/modules/ShortCode/Model/ShortCode.php new file mode 100644 index 0000000..4541fe4 --- /dev/null +++ b/domokits/local/modules/ShortCode/Model/ShortCode.php @@ -0,0 +1,10 @@ +/local/modules/``` directory and be sure that the name of the module is ShortCode. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/shortcode-module:~1.0 +``` + +## Usage + +This module https://github.com/thelia-modules/ShortCodeMeta is a good example of how to use ShortCode. + +### 1. Register your short codes + You can do this at the post activation of your module. The best way to do this is to use the module method : `ShortCode::createNewShortCodeIfNotExist` + the first parameter is the name you will use to call the short code in your templates (like this `[my_shortcode_name], second parameter is the event dispatched when the short code is detected. + +### 2. Add short codes to your templates + The short codes syntax is as follows: + ``` + [shortcode] - No content, no attributes + [shortcode]My Content[/shortcode] - Short code with content + [shortcode attribute=value foo=bar] - Short code with attributes + [shortcode attribute=value foo=bar]My Content[/shortcode] - Short code with content and attributes + ``` + +### 3. Listen events associated to your short codes + When a short code is detected in response a `ShortCodeEvent` is dispatched with the event name given at the creation. + So if you want replace your short code by something you have to listen this event. + In this event you have 3 properties : + - `content` (string) The content between your tags it will be `My Content` for the example above. + - `attributes` (array) The array of all attributes passed to your short code `['attribute'=>'value', 'foo'=>'bar']` for the example above. + - `result` (string) Your short code will be replaced by this value in response (equal to content by default) \ No newline at end of file diff --git a/domokits/local/modules/ShortCode/ShortCode.php b/domokits/local/modules/ShortCode/ShortCode.php new file mode 100644 index 0000000..029d9f0 --- /dev/null +++ b/domokits/local/modules/ShortCode/ShortCode.php @@ -0,0 +1,89 @@ +getConfigValue('is_initialized', false)) { + $database = new Database($con); + + $database->insertSql(null, array(__DIR__ . '/Config/TheliaMain.sql')); + + $this->setConfigValue('is_initialized', true); + } + + return true; + } + + /** + * Create a new ShortCode + * @param string $shortCodeName the name for call the ShortCode in template + * @param string $eventName the name of the event dispatched when shortcode is in template + * @throws PropelException + */ + public static function createNewShortCodeIfNotExist($shortCodeName, $eventName) + { + if (null === ShortCodeQuery::create()->findOneByTag($shortCodeName)) { + $shortCode = new \ShortCode\Model\ShortCode(); + $shortCode->setTag($shortCodeName) + ->setEvent($eventName) + ->setActive(1) + ->save(); + } + } + + /** + * Active a ShortCode by his name + * @param string $shortCodeName the name for call the ShortCode in template + * @throws PropelException + */ + public static function activateShortCode($shortCodeName) + { + $shortCode = ShortCodeQuery::create() + ->filterByTag($shortCodeName) + ->findOne(); + + if (null !== $shortCode) { + $shortCode->setActive(1) + ->save(); + } + } + + /** + * Deactive a ShortCode by his name + * @param string $shortCodeName the name for call the ShortCode in template + * @throws PropelException + */ + public static function deactivateShortCode($shortCodeName) + { + $shortCode = ShortCodeQuery::create() + ->filterByTag($shortCodeName) + ->findOne(); + + if (null !== $shortCode) { + $shortCode->setActive(0) + ->save(); + } + } +} diff --git a/domokits/local/modules/ShortCode/composer.json b/domokits/local/modules/ShortCode/composer.json new file mode 100644 index 0000000..9f3e354 --- /dev/null +++ b/domokits/local/modules/ShortCode/composer.json @@ -0,0 +1,12 @@ +{ + "name": "thelia/short-code-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1", + "maiorano84/shortcodes": "v2.0.0-beta" + }, + "extra": { + "installer-name": "ShortCode" + } +} \ No newline at end of file diff --git a/domokits/local/modules/ShortCodeMeta/Config/config.xml b/domokits/local/modules/ShortCodeMeta/Config/config.xml new file mode 100644 index 0000000..69c89e8 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/Config/config.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/ShortCodeMeta/Config/module.xml b/domokits/local/modules/ShortCodeMeta/Config/module.xml new file mode 100644 index 0000000..60ca399 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/Config/module.xml @@ -0,0 +1,40 @@ + + + ShortCodeMeta\ShortCodeMeta + + Add meta to header by short code + + + + Ajoute des méta-données au header par les short codes + + + + + en_US + fr_FR + + 2.0.0 + + + Vincent Lopes-Vicente + vlopes@openstudio.fr + + + classic + + + ShortCode + + + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/ShortCodeMeta/Config/routing.xml b/domokits/local/modules/ShortCodeMeta/Config/routing.xml new file mode 100644 index 0000000..f1bc5a9 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/Config/routing.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/domokits/local/modules/ShortCodeMeta/Config/schema.xml b/domokits/local/modules/ShortCodeMeta/Config/schema.xml new file mode 100644 index 0000000..99ef826 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/Config/schema.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/domokits/local/modules/ShortCodeMeta/EventListener/ShortCodeListener.php b/domokits/local/modules/ShortCodeMeta/EventListener/ShortCodeListener.php new file mode 100644 index 0000000..524fb69 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/EventListener/ShortCodeListener.php @@ -0,0 +1,45 @@ + [['checkEmptyPage', 128]], + ShortCodeMeta::PAGINATION_META_SHORT_CODE => [['addPaginationMeta', 128]], + ]; + } + + public function addPaginationMeta(ShortCodeEvent $event) + { + $attributes = $event->getAttributes(); + + if (!isset($attributes['rel'])) { + return; + } + + $rel = $attributes['rel']; + + $staticVariableName = strtoupper($attributes['rel']).'_PAGE_URL'; + + if (null !== $url = ShortCodeMeta::$$staticVariableName) { + $event->setResult(''); + } + } + + public function checkEmptyPage(ShortCodeEvent $event) + { + if (ShortCodeMeta::$IS_EMPTY_PAGE === true) { + $event->setResult(''); + } + } + +} \ No newline at end of file diff --git a/domokits/local/modules/ShortCodeMeta/I18n/en_US.php b/domokits/local/modules/ShortCodeMeta/I18n/en_US.php new file mode 100755 index 0000000..0b4fa14 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/domokits/local/modules/ShortCodeMeta/I18n/fr_FR.php b/domokits/local/modules/ShortCodeMeta/I18n/fr_FR.php new file mode 100755 index 0000000..3708624 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/I18n/fr_FR.php @@ -0,0 +1,4 @@ + 'La traduction française de la chaine', +); diff --git a/domokits/local/modules/ShortCodeMeta/LICENSE b/domokits/local/modules/ShortCodeMeta/LICENSE new file mode 100644 index 0000000..2152256 --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 OpenStudio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/domokits/local/modules/ShortCodeMeta/Readme.md b/domokits/local/modules/ShortCodeMeta/Readme.md new file mode 100644 index 0000000..d5df0ea --- /dev/null +++ b/domokits/local/modules/ShortCodeMeta/Readme.md @@ -0,0 +1,54 @@ +# Short Code Meta + +ShortCodeMeta allow you to add meat in head for +- Empty page (`noindex, nofollow`) +- Pagination link + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is ShortCodeMeta. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/short-code-meta-module:~1.0 +``` + +## Usage + +This module use ShortCode (https://github.com/thelia-modules/ShortCode) to add metas in head after smarty has completly build the page. +The short codes are automatically added in templates with the hook `main.head-bottom` so be sure you have this hook in your template layout. + +### Empty pages + +To add a meta `noindex, nofollow` to an empty page you have to inform the module with the smarty tag `{set_empty_page_meta}` +All the page where this tag is present will have a noindex meta. +For example if you use a loop product in your category page you can add this tag in your elseloop like this : +``` + {ifloop rel="product_list"} +
+ {loop type="product" name="product_list" category=$category_id} +

{$TITLE} + {/loop} +

+ {/ifloop} + {elseloop rel="product_list"} + {set_empty_page_meta} + {/elseloop} +``` +With this, all categories page without products will not be indexed by robots. + + +### Pagination meta link + +To add a ` + + + + + + + + + diff --git a/domokits/local/modules/SmartyRedirection/Config/module.xml b/domokits/local/modules/SmartyRedirection/Config/module.xml new file mode 100644 index 0000000..0fd9df3 --- /dev/null +++ b/domokits/local/modules/SmartyRedirection/Config/module.xml @@ -0,0 +1,26 @@ + + + SmartyRedirection\SmartyRedirection + + Redirection function for templates + + + Fonction de redirection pour les templates + + + en_US + fr_FR + + 2.0.0 + + + Benjamin Perche + bperche9@gmail.com + + + classic + 2.5.0 + prod + diff --git a/domokits/local/modules/SmartyRedirection/LICENSE.txt b/domokits/local/modules/SmartyRedirection/LICENSE.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/domokits/local/modules/SmartyRedirection/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/domokits/local/modules/SmartyRedirection/Readme.md b/domokits/local/modules/SmartyRedirection/Readme.md new file mode 100644 index 0000000..ca6b070 --- /dev/null +++ b/domokits/local/modules/SmartyRedirection/Readme.md @@ -0,0 +1,39 @@ +# Smarty Redirection + +This module adds a smarty function to redirect the user directly from a template + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is SmartyRedirection. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/smarty-redirection-module ~1.0.0 +``` + +## Usage + +You can use the ```{redirect }``` function like ```{url }```. +Only one parameter is specific to this function: ```status```. + +If this parameter isn't given, its value is 302. Otherwise, you can set it to 301 to define a permanent redirection in a template. + +## Example + +```smarty +{if ! $foo} + {redirect path="/anywhere"} +{/if} +``` + +```smarty +{if ! $foo} + {redirect path="/anywhere" status=301} +{/if} +``` diff --git a/domokits/local/modules/SmartyRedirection/Smarty/Plugins/Redirect.php b/domokits/local/modules/SmartyRedirection/Smarty/Plugins/Redirect.php new file mode 100644 index 0000000..36e286e --- /dev/null +++ b/domokits/local/modules/SmartyRedirection/Smarty/Plugins/Redirect.php @@ -0,0 +1,62 @@ + + */ +class Redirect extends AbstractSmartyPlugin +{ + const DEFAULT_REDIRECTION_STATUS = 302; + /** + * @var UrlGenerator + */ + protected $urlGeneratorPlugin; + + public function __construct(UrlGenerator $urlGenerator) + { + $this->urlGeneratorPlugin = $urlGenerator; + } + + /** + * @param $params + */ + public function throwRedirect($params) + { + $status = static::DEFAULT_REDIRECTION_STATUS; + + if (isset($params["status"])) { + $status = (int) $params["status"]; + unset ($params["status"]); + } + + throw new RedirectException($this->urlGeneratorPlugin->generateUrlFunction($params, $foo), $status); + } + + /** + * @return array of SmartyPluginDescriptor + */ + public function getPluginDescriptors() + { + return array( + new SmartyPluginDescriptor("function", "redirect", $this, "throwRedirect"), + ); + } +} diff --git a/domokits/local/modules/SmartyRedirection/SmartyRedirection.php b/domokits/local/modules/SmartyRedirection/SmartyRedirection.php new file mode 100644 index 0000000..23218ca --- /dev/null +++ b/domokits/local/modules/SmartyRedirection/SmartyRedirection.php @@ -0,0 +1,21 @@ + + + + + + + + + + + +
+ + + diff --git a/domokits/local/modules/StoreSeo/Config/module.xml b/domokits/local/modules/StoreSeo/Config/module.xml new file mode 100755 index 0000000..10fa3c4 --- /dev/null +++ b/domokits/local/modules/StoreSeo/Config/module.xml @@ -0,0 +1,26 @@ + + + StoreSeo\StoreSeo + + Manage translations for your store main SEO meta + + + Gère les traductions des principales metas SEO de votre boutique + + + en_US + fr_FR + + 2.0.1 + + + Etienne Perriere + eperriere@openstudio.fr + + + classic + 2.5.0 + other + diff --git a/domokits/local/modules/StoreSeo/Config/routing.xml b/domokits/local/modules/StoreSeo/Config/routing.xml new file mode 100755 index 0000000..b2ce795 --- /dev/null +++ b/domokits/local/modules/StoreSeo/Config/routing.xml @@ -0,0 +1,6 @@ + + + + diff --git a/domokits/local/modules/StoreSeo/Controller/StoreSeoConfigController.php b/domokits/local/modules/StoreSeo/Controller/StoreSeoConfigController.php new file mode 100755 index 0000000..990414f --- /dev/null +++ b/domokits/local/modules/StoreSeo/Controller/StoreSeoConfigController.php @@ -0,0 +1,97 @@ + + */ +class StoreSeoConfigController extends BaseAdminController +{ + /** + * @Route("/admin/module/StoreSeo", name="storeseo_configuration_default", methods="GET") + */ + public function defaultAction() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], ["storeseo"], AccessManager::VIEW)) { + return $response; + } + + // Get current edition language locale + $locale = $this->getCurrentEditionLocale(); + + $form = $this->createForm( + "storeseo_form_config", + FormType::class, + [ + 'title' => StoreSeo::getConfigValue('title', null, $locale), + 'description' => StoreSeo::getConfigValue('description', null, $locale), + 'keywords' => StoreSeo::getConfigValue('keywords', null, $locale) + ] + ); + + $this->getParserContext()->addForm($form); + + return $this->render("storeseo-configuration"); + } + + /** + * @Route("/admin/module/StoreSeo", name="storeseo_configuration_save", methods="POST") + */ + public function saveAction() + { + if (null !== $response = $this->checkAuth([AdminResources::MODULE], ["storeseo"], AccessManager::UPDATE)) { + return $response; + } + + $baseForm = $this->createForm("storeseo_form_config"); + + $errorMessage = null; + + // Get current edition language locale + $locale = $this->getCurrentEditionLocale(); + + try { + $form = $this->validateForm($baseForm); + $data = $form->getData(); + + // Save data + StoreSeo::setConfigValue('title', $data["title"], $locale); + StoreSeo::setConfigValue('description', $data["description"], $locale); + StoreSeo::setConfigValue('keywords', $data["keywords"], $locale); + + } catch (FormValidationException $ex) { + // Invalid data entered + $errorMessage = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + // Any other error + $errorMessage = $this->getTranslator()->trans('Sorry, an error occurred: %err', ['%err' => $ex->getMessage()], StoreSeo::DOMAIN_NAME, $locale); + } + + if (null !== $errorMessage) { + // Mark the form as with error + $baseForm->setErrorMessage($errorMessage); + + // Send the form and the error to the parser + $this->getParserContext() + ->addForm($baseForm) + ->setGeneralError($errorMessage) + ; + } else { + $this->getParserContext() + ->set("success", true) + ; + } + + return $this->defaultAction(); + } +} diff --git a/domokits/local/modules/StoreSeo/Form/StoreSeoForm.php b/domokits/local/modules/StoreSeo/Form/StoreSeoForm.php new file mode 100755 index 0000000..1c66d32 --- /dev/null +++ b/domokits/local/modules/StoreSeo/Form/StoreSeoForm.php @@ -0,0 +1,38 @@ +formBuilder + ->add( + 'title', + TextType::class, + ['label' => $this->translator->trans('Store name', [], 'storeseo.fo.default')] + ) + ->add( + 'description', + TextType::class, + ['label' => $this->translator->trans('Store description', [], 'storeseo.fo.default')] + ) + ->add( + 'keywords', + TextType::class, + ['label' => $this->translator->trans('Keywords', [], 'storeseo.fo.default')] + ) + ; + } +} diff --git a/domokits/local/modules/StoreSeo/Hook/StoreSeoHook.php b/domokits/local/modules/StoreSeo/Hook/StoreSeoHook.php new file mode 100755 index 0000000..4abb755 --- /dev/null +++ b/domokits/local/modules/StoreSeo/Hook/StoreSeoHook.php @@ -0,0 +1,19 @@ + + */ +class StoreSeoHook extends BaseHook +{ + public function onModuleConfig(HookRenderEvent $event) + { + $event->add($this->render('storeseo-configuration.html')); + } +} \ No newline at end of file diff --git a/domokits/local/modules/StoreSeo/I18n/backOffice/default/en_US.php b/domokits/local/modules/StoreSeo/I18n/backOffice/default/en_US.php new file mode 100755 index 0000000..78ab426 --- /dev/null +++ b/domokits/local/modules/StoreSeo/I18n/backOffice/default/en_US.php @@ -0,0 +1,9 @@ + 'Configuration correctly saved', + 'Configure StoreSEO' => 'Configure StoreSEO', + 'Home' => 'Home', + 'Modules' => 'Modules', + 'StoreSeo configuration' => 'StoreSEO configuration', +); diff --git a/domokits/local/modules/StoreSeo/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/StoreSeo/I18n/backOffice/default/fr_FR.php new file mode 100755 index 0000000..ca86d96 --- /dev/null +++ b/domokits/local/modules/StoreSeo/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,9 @@ + 'Configuration correctement sauvegardée', + 'Configure StoreSEO' => 'Configurer StoreSEO', + 'Home' => 'Accueil', + 'Modules' => 'Modules', + 'StoreSeo configuration' => 'Configuration de StoreSEO', +); diff --git a/domokits/local/modules/StoreSeo/I18n/en_US.php b/domokits/local/modules/StoreSeo/I18n/en_US.php new file mode 100755 index 0000000..cc80e0e --- /dev/null +++ b/domokits/local/modules/StoreSeo/I18n/en_US.php @@ -0,0 +1,8 @@ + 'Keywords', + 'Sorry, an error occurred: %err' => 'Sorry, an error occurred: %err', + 'Store description' => 'Store description', + 'Store name' => 'Store name', +); diff --git a/domokits/local/modules/StoreSeo/I18n/fr_FR.php b/domokits/local/modules/StoreSeo/I18n/fr_FR.php new file mode 100755 index 0000000..cef43d6 --- /dev/null +++ b/domokits/local/modules/StoreSeo/I18n/fr_FR.php @@ -0,0 +1,8 @@ + 'Mots-clés', + 'Sorry, an error occurred: %err' => 'Désolé, une erreur s\'est produite : %err', + 'Store description' => 'Description de la boutique', + 'Store name' => 'Nom de la boutique', +); diff --git a/domokits/local/modules/StoreSeo/Readme.md b/domokits/local/modules/StoreSeo/Readme.md new file mode 100755 index 0000000..46e696c --- /dev/null +++ b/domokits/local/modules/StoreSeo/Readme.md @@ -0,0 +1,56 @@ +# Store Seo + +Manage translation for your store SEO meta. + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is StoreSeo. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/store-seo-module:~1.2.0 +``` + +## Usage + +Once activated, click on the configuration button of the module. + +Then, select one of your store available language and fill inputs with your store title, description and keywords. Save and do it for each of your language. + +They will be used on pages with no SEO meta configured. + +## Integration + +Open the layout.tpl file of your template. + +Check the ```Define some stuff for Smarty``` section at the top of the file, and be sur that you have this assignation: + +``` +{assign var="lang_locale" value={lang attr="locale"}} +``` + + +Add this line in the `````` section, before the `````` tag : + +``` +{store_seo_meta locale=$lang_locale} +``` + + +Also add this in the ```{block name="meta"}```, after the ```<meta name="description">``` tag : + +``` +{if $page_keywords} + <meta name="keywords" content="{$page_keywords}"> +{else} + <meta name="keywords" content="{$default_keywords}"> +{/if} +``` + +Finally, be sure that you have no ```{$page_title = {config key="store_name"}}``` declaration in your other template files. diff --git a/domokits/local/modules/StoreSeo/Smarty/Plugins/StoreSeoPlugin.php b/domokits/local/modules/StoreSeo/Smarty/Plugins/StoreSeoPlugin.php new file mode 100755 index 0000000..5293726 --- /dev/null +++ b/domokits/local/modules/StoreSeo/Smarty/Plugins/StoreSeoPlugin.php @@ -0,0 +1,48 @@ +<?php + +namespace StoreSeo\Smarty\Plugins; + +use StoreSeo\StoreSeo; +use Thelia\Model\ConfigQuery; +use TheliaSmarty\Template\AbstractSmartyPlugin; +use TheliaSmarty\Template\SmartyPluginDescriptor; + +/** + * Class StoreSeoPlugin + * @package StoreSeo\Smarty\Plugins + * @author Etienne Perriere <eperriere@openstudio.fr> + */ +class StoreSeoPlugin extends AbstractSmartyPlugin +{ + + /** + * @return SmartyPluginDescriptor[] an array of SmartyPluginDescriptor + */ + public function getPluginDescriptors() + { + return [ + new SmartyPluginDescriptor("function", "store_seo_meta", $this, "changeSeoMeta") + ]; + } + + /** + * Assign meta title, description and keyword for the template + * + * @param array $params + * @param \Smarty $smarty + */ + public function changeSeoMeta($params, &$smarty) + { + // Get language and moduleConfig + $locale = $params['locale']; + + // Get store title + $smarty->assign("store_name", StoreSeo::getConfigValue('title', null, $locale)); + + // Get store description + $smarty->assign("store_description", StoreSeo::getConfigValue('description', null, $locale)); + + // Get store keywords + $smarty->assign("default_keywords", StoreSeo::getConfigValue('keywords', null, $locale)); + } +} \ No newline at end of file diff --git a/domokits/local/modules/StoreSeo/StoreSeo.php b/domokits/local/modules/StoreSeo/StoreSeo.php new file mode 100755 index 0000000..a60000d --- /dev/null +++ b/domokits/local/modules/StoreSeo/StoreSeo.php @@ -0,0 +1,42 @@ +<?php +/*************************************************************************************/ +/* This file is part of the Thelia package. */ +/* */ +/* Copyright (c) OpenStudio */ +/* email : dev@thelia.net */ +/* web : http://www.thelia.net */ +/* */ +/* For the full copyright and license information, please view the LICENSE.txt */ +/* file that was distributed with this source code. */ +/*************************************************************************************/ + +namespace StoreSeo; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; + +/** + * Class StoreSeo + * @package StoreSeo + * @author Etienne Perriere <eperriere@openstudio.fr> + */ +class StoreSeo extends BaseModule +{ + /** @var string */ + const DOMAIN_NAME = 'storeseo'; + + /* + * You may now override BaseModuleInterface methods, such as: + * install, destroy, preActivation, postActivation, preDeactivation, postDeactivation + * + * Have fun ! + */ + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/StoreSeo/composer.json b/domokits/local/modules/StoreSeo/composer.json new file mode 100755 index 0000000..89142ec --- /dev/null +++ b/domokits/local/modules/StoreSeo/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/store-seo-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "StoreSeo" + } +} diff --git a/domokits/local/modules/StoreSeo/templates/backOffice/default/storeseo-configuration.html b/domokits/local/modules/StoreSeo/templates/backOffice/default/storeseo-configuration.html new file mode 100755 index 0000000..309df8c --- /dev/null +++ b/domokits/local/modules/StoreSeo/templates/backOffice/default/storeseo-configuration.html @@ -0,0 +1,98 @@ +{extends file="admin-layout.tpl"} + +{block name="no-return-functions"} +{$admin_current_location = 'modules'} +{/block} + +{block name="page-title"}{intl d="storeseo.bo.default" l='StoreSeo configuration'}{/block} + +{block name="check-resource"}admin.module{/block} +{block name="check-access"}view{/block} +{block name="check-module"}StoreSeo{/block} + +{block name="main-content"} +<div class="container" id="wrapper"> + + <ul class="breadcrumb"> + <li><a href="{url path='/admin'}">{intl l="Home" d="storeseo.bo.default"}</a></li> + <li><a href="{url path='/admin/modules'}">{intl l="Modules" d="storeseo.bo.default"}</a></li> + <li>{intl l="StoreSeo configuration" d="storeseo.bo.default"}</li> + </ul> + + <div class="general-block-decorator"> + + <div class="title title-without-tabs"> + {intl l="Configure StoreSEO" d="storeseo.bo.default"} + </div> + + <div class="row"> + <div class="col-md-12"> + {if $success|default:false} + <div class="alert alert-success"> + {intl l="Configuration correctly saved" d="storeseo.bo.default"} + </div> + {/if} + + <div class="form-container"> + {form name='storeseo_form_config'} + <form method="post" action="{url path='/admin/module/StoreSeo'}"> + + {form_hidden_fields form=$form} + + {include "includes/inner-form-toolbar.html" close_url={url path='/admin/modules'}} + <br/> + + {form_field form=$form field="title"} + <div class="form-group {if $error}has-error{/if}"> + <label class="control-label"> + {$label} + + {form_error form=$form field="title"} + <br /> + <span class="error">{$message|default:null}</span> + {/form_error} + </label> + + <input type="text" class="form-control" name="{$name}" value="{$value}" /> + </div> + {/form_field} + + {form_field form=$form field="description"} + <div class="form-group {if $error}has-error{/if}"> + <label class="control-label"> + {$label} + + {form_error form=$form field="description"} + <br /> + <span class="error">{$message|default:null}</span> + {/form_error} + </label> + + <input type="text" class="form-control" name="{$name}" value="{$value}" /> + </div> + {/form_field} + + {form_field form=$form field="keywords"} + <div class="form-group {if $error}has-error{/if}"> + <label class="control-label"> + {$label} + + {form_error form=$form field="keywords"} + <br /> + <span class="error">{$message|default:null}</span> + {/form_error} + </label> + + <input type="text" class="form-control" name="{$name}" value="{$value}" /> + </div> + {/form_field} + + </form> + {/form} + </div> + </div> + </div> + + </div> +</div> +{/block} diff --git a/domokits/local/modules/StripePayment/Classes/StripePaymentException.php b/domokits/local/modules/StripePayment/Classes/StripePaymentException.php new file mode 100644 index 0000000..633ef04 --- /dev/null +++ b/domokits/local/modules/StripePayment/Classes/StripePaymentException.php @@ -0,0 +1,13 @@ +<?php + +namespace StripePayment\Classes; + +/** + * Class StripePaymentException + * @package StripePayment\Classes + * @author Etienne Perriere - OpenStudio <eperriere@openstudio.fr> + */ +class StripePaymentException extends \Exception +{ + +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/Classes/StripePaymentLog.php b/domokits/local/modules/StripePayment/Classes/StripePaymentLog.php new file mode 100644 index 0000000..f89d5dd --- /dev/null +++ b/domokits/local/modules/StripePayment/Classes/StripePaymentLog.php @@ -0,0 +1,60 @@ +<?php + +namespace StripePayment\Classes; + +use Thelia\Log\Tlog; + +/** + * Class StripePaymentLog + * @package StripePayment\Classes + * @author Etienne Perriere - OpenStudio <eperriere@openstudio.fr> + */ +class StripePaymentLog +{ + const EMERGENCY = 'EMERGENCY'; + const ALERT = 'ALERT'; + const CRITICAL = 'CRITICAL'; + const ERROR = 'ERROR'; + const WARNING = 'WARNING'; + const NOTICE = 'NOTICE'; + const INFO = 'INFO'; + const DEBUG = 'DEBUG'; + const LOGCLASS = "\\Thelia\\Log\\Destination\\TlogDestinationFile"; + + /** @var Tlog $log */ + protected $log; + + /** + * Log a message + * + * @param string $message Message + * @param string $severity EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG + * @param string $category Category + */ + public function logText($message, $severity = 'ALERT', $category = 'stripe') + { + $this->setTLogStripe(); + $msg = "$category.$severity: $message"; + $this->log->info($msg); + // Back to previous state + $this->getBackToPreviousState(); + } + + /** + * @return Tlog + */ + protected function setTLogStripe() + { + /* + * Write Log + */ + $this->log = Tlog::getInstance(); + $this->log->setDestinations(self::LOGCLASS); + $this->log->setConfig(self::LOGCLASS, 0, THELIA_ROOT . "log" . DS . "log-stripe.txt"); + } + + protected function getBackToPreviousState() + { + $this->log->setDestinations("\\Thelia\\Log\\Destination\\TlogDestinationRotatingFile"); + } +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/Config/config.xml b/domokits/local/modules/StripePayment/Config/config.xml new file mode 100644 index 0000000..571db36 --- /dev/null +++ b/domokits/local/modules/StripePayment/Config/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<config xmlns="http://thelia.net/schema/dic/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd"> + <forms> + <form name="stripepayment_config_form" class="StripePayment\Form\StripePaymentConfigForm"/> + </forms> + <hooks> + <hook id="stripepayment.hook" class="StripePayment\Hook\StripePaymentHook" scope="request"> + <argument id="request" type="service"/> + <argument type="service" id="thelia.taxEngine"/> + <tag name="hook.event_listener" event="order-invoice.payment-extra" type="front" method="includeStripe"/> + <tag name="hook.event_listener" event="order-invoice.after-javascript-include" type="front" method="declareStripeOnClickEvent"/> + <tag name="hook.event_listener" event="main.after-javascript-include" type="front" method="includeStripeJsV3"/> + <tag name="hook.event_listener" event="main.head-bottom" type="front" method="onMainHeadBottom"/> + <tag name="hook.event_listener" event="module.configuration" type="back" templates="render:stripepayment-configuration.html"/> + </hook> + </hooks> + <!-- + <services> + <service id="stripepayment.cart.event_listener" class="StripePayment\EventListeners\CartEventListener" scope="request"> + <argument id="request" type="service"/> + <argument type="service" id="event_dispatcher" /> + <argument type="service" id="thelia.taxEngine"/> + <tag name="kernel.event_subscriber"/> + </service> + </services> + --> +</config> diff --git a/domokits/local/modules/StripePayment/Config/module.xml b/domokits/local/modules/StripePayment/Config/module.xml new file mode 100644 index 0000000..e28c711 --- /dev/null +++ b/domokits/local/modules/StripePayment/Config/module.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module xmlns="http://thelia.net/schema/dic/module" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_1.xsd"> + <fullnamespace>StripePayment\StripePayment</fullnamespace> + <descriptive locale="en_US"> + <title>Stripe + + + Stripe + + + en_US + fr_FR + + 3.0.1 + + Etienne Perriere + eperriere@openstudio.fr + + payment + 2.5.0 + other + diff --git a/domokits/local/modules/StripePayment/Config/routing.xml b/domokits/local/modules/StripePayment/Config/routing.xml new file mode 100644 index 0000000..7b1c007 --- /dev/null +++ b/domokits/local/modules/StripePayment/Config/routing.xml @@ -0,0 +1,30 @@ + + + + diff --git a/domokits/local/modules/StripePayment/Config/schema.xml b/domokits/local/modules/StripePayment/Config/schema.xml new file mode 100644 index 0000000..5385763 --- /dev/null +++ b/domokits/local/modules/StripePayment/Config/schema.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/domokits/local/modules/StripePayment/Controller/StripePaymentConfigController.php b/domokits/local/modules/StripePayment/Controller/StripePaymentConfigController.php new file mode 100644 index 0000000..62a5b7a --- /dev/null +++ b/domokits/local/modules/StripePayment/Controller/StripePaymentConfigController.php @@ -0,0 +1,75 @@ +checkAuth([AdminResources::MODULE], ["stripepayment"], AccessManager::UPDATE)) { + return $response; + } + + $baseForm = $this->createForm(StripePaymentConfigForm::getName()); + + $errorMessage = null; + + try { + $form = $this->validateForm($baseForm); + $data = $form->getData(); + StripePayment::setConfigValue(StripePayment::ENABLED, is_bool($data["enabled"]) ? (int) ($data["enabled"]) : $data["enabled"]); + StripePayment::setConfigValue(StripePayment::STRIPE_ELEMENT, is_bool($data["stripe_element"]) ? (int) ($data["stripe_element"]) : $data["stripe_element"]); + StripePayment::setConfigValue(StripePayment::ONE_CLICK_PAYMENT, is_bool($data["one_click_payment"]) ? (int) ($data["one_click_payment"]) : $data["one_click_payment"]); + StripePayment::setConfigValue(StripePayment::SECRET_KEY, is_bool($data["secret_key"]) ? (int) ($data["secret_key"]) : $data["secret_key"]); + StripePayment::setConfigValue(StripePayment::PUBLISHABLE_KEY, is_bool($data["publishable_key"]) ? (int) ($data["publishable_key"]) : $data["publishable_key"]); + StripePayment::setConfigValue(StripePayment::WEBHOOKS_KEY, is_bool($data["webhooks_key"]) ? (int) ($data["webhooks_key"]) : $data["webhooks_key"]); + StripePayment::setConfigValue(StripePayment::SECURE_URL, is_bool($data["secure_url"]) ? (int) ($data["secure_url"]) : $data["secure_url"]); + } catch (FormValidationException $ex) { + // Invalid data entered + $errorMessage = $this->createStandardFormValidationErrorMessage($ex); + } catch (\Exception $ex) { + // Any other error + $errorMessage = Translator::getInstance()->trans('Sorry, an error occurred: %err', ['%err' => $ex->getMessage()], "", StripePayment::MESSAGE_DOMAIN); + } + + if (null !== $errorMessage) { + // Mark the form as with error + $baseForm->setErrorMessage($errorMessage); + + // Send the form and the error to the parser + $context + ->addForm($baseForm) + ->setGeneralError($errorMessage) + ; + } else { + $context + ->set("success", true) + ; + } + + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/StripePayment')); + } +} diff --git a/domokits/local/modules/StripePayment/Controller/StripePaymentController.php b/domokits/local/modules/StripePayment/Controller/StripePaymentController.php new file mode 100644 index 0000000..ec099ad --- /dev/null +++ b/domokits/local/modules/StripePayment/Controller/StripePaymentController.php @@ -0,0 +1,24 @@ + + */ +class StripePaymentController extends BasePaymentModuleController +{ + /** + * Return a module identifier used to calculate the name of the log file, + * and in the log messages. + * + * @return string the module code + */ + protected function getModuleCode() + { + return 'StripePayment'; + } +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/Controller/StripeWebHooksController.php b/domokits/local/modules/StripePayment/Controller/StripeWebHooksController.php new file mode 100644 index 0000000..2e0deb6 --- /dev/null +++ b/domokits/local/modules/StripePayment/Controller/StripeWebHooksController.php @@ -0,0 +1,149 @@ +logText(serialize($event)); + + // Handle the event + switch ($event->type) { + case 'checkout.session.completed': + /** @var Session $sessionCompleted */ + $sessionCompleted = $event->data->object; + $this->handleSessionCompleted($sessionCompleted, $dispatcher); + break; + case 'payment_intent.succeeded': + // Needed to wait for order to be created (Stripe is faster than Thelia) + sleep(5); + /** @var Session $sessionCompleted */ + $paymentId = $event->data->object->id; + $this->handlePaymentIntentSuccess($paymentId, $dispatcher); + break; + case 'payment_intent.payment_failed': + // Needed to wait for order to be created (Stripe is faster than Thelia) + sleep(5); + /** @var Session $sessionCompleted */ + $paymentId = $event->data->object->id; + $this->handlePaymentIntentFail($paymentId, $dispatcher); + break; + default: + // Unexpected event type + (new StripePaymentLog())->logText('Unexpected event type'); + + return new Response('Unexpected event type', 400); + } + + return new Response('Success', 200); + } catch (\UnexpectedValueException $e) { + // Invalid payload + (new StripePaymentLog())->logText($e->getMessage()); + return new Response('Invalid payload', 400); + } catch (SignatureVerification $e) { + return new Response($e->getMessage(), 400); + } catch (\Exception $e) { + return new Response($e->getMessage(), 404); + } + } + + return new Response('Bad request', 400); + } + + protected function handleSessionCompleted(Session $sessionCompleted, EventDispatcherInterface $dispatcher) + { + $order = OrderQuery::create() + ->findOneByRef($sessionCompleted->client_reference_id); + + if (null === $order) { + throw new \Exception("Order with reference $sessionCompleted->client_reference_id not found"); + } + + $this->setOrderToPaid($order, $dispatcher); + } + + protected function handlePaymentIntentSuccess($paymentId, EventDispatcherInterface $dispatcher) + { + $order = OrderQuery::create() + ->findOneByTransactionRef($paymentId); + + if (null === $order) { + throw new \Exception("Order with transaction ref $paymentId not found"); + } + + $this->setOrderToPaid($order, $dispatcher); + } + + protected function handlePaymentIntentFail($paymentId, EventDispatcherInterface $dispatcher) + { + $order = OrderQuery::create() + ->findOneByTransactionRef($paymentId); + + if (null === $order) { + throw new \Exception("Order with transaction ref $paymentId not found"); + } + + $this->setOrderToCanceled($order, $dispatcher); + } + + protected function setOrderToPaid($order, EventDispatcherInterface $dispatcher) + { + $paidStatusId = OrderStatusQuery::create() + ->filterByCode('paid') + ->select('ID') + ->findOne(); + + $event = new OrderEvent($order); + $event->setStatus($paidStatusId); + $dispatcher->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + } + + protected function setOrderToCanceled($order, EventDispatcherInterface $dispatcher) + { + $canceledStatusId = OrderStatusQuery::create() + ->filterByCode('canceled') + ->select('ID') + ->findOne(); + + $event = new OrderEvent($order); + $event->setStatus($canceledStatusId); + $dispatcher->dispatch($event, TheliaEvents::ORDER_UPDATE_STATUS); + } +} diff --git a/domokits/local/modules/StripePayment/EventListeners/CartEventListener.php b/domokits/local/modules/StripePayment/EventListeners/CartEventListener.php new file mode 100644 index 0000000..3b27f14 --- /dev/null +++ b/domokits/local/modules/StripePayment/EventListeners/CartEventListener.php @@ -0,0 +1,212 @@ +request = $requestStack->getCurrentRequest(); + $this->dispatcher = $dispatcher; + $this->taxEngine = $taxEngine; + } + + public static function getSubscribedEvents() + { + $events = [ + TheliaEvents::CART_RESTORE_CURRENT => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CART_CREATE_NEW => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CART_ADDITEM => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CART_DELETEITEM => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CART_UPDATEITEM => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CART_CLEAR => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::CHANGE_DEFAULT_CURRENCY => ["createOrUpdatePaymentIntent", 64], + TheliaEvents::ORDER_SET_POSTAGE => [ "createOrUpdatePaymentIntent", 64 ] + ]; + + return $events; + } + + public function createOrUpdatePaymentIntent(ActionEvent $event) + { + $secretKey = StripePayment::getConfigValue('secret_key'); + Stripe::setApiKey($secretKey); + + /** @var Session $session */ + $session = $this->request->getSession(); + + $paymentIntentValues = $this->getPaymentIntentValues($event); + + if (false === $paymentIntentValues) { + return; + } + + if ( + $session->has(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY) + && + null !== $paymentId = $session->get(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY) + ) + { + + $payment = PaymentIntent::update( + $paymentId, + $paymentIntentValues + ); + $session->set(StripePayment::PAYMENT_INTENT_SECRET_SESSION_KEY, $payment->client_secret); + + return; + } + try { + /** @var PaymentIntent $payment */ + $payment = PaymentIntent::create($paymentIntentValues); + + $session->set(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY, $payment->id); + $session->set(StripePayment::PAYMENT_INTENT_SECRET_SESSION_KEY, $payment->client_secret); + } catch (\Exception $exception){ + Tlog::getInstance()->addAlert($exception->getMessage()); + } + + return; + } + + + protected function getPaymentIntentValues(ActionEvent $event) + { + /** @var Session $session */ + $session = $this->request->getSession(); + $currency = $session->getCurrency(); + + $data = $this->getCartAndOrderFromEvent($event); + + if (false === $data) { + return false; + } + + /** @var Cart $cart */ + $cart = $data['cart']; + + /** @var Order $order */ + $order = $data['order']; + + $postageAmount = floatval($order->getPostage()); + + $country = $this->taxEngine->getDeliveryCountry(); + + $cartAmount = floatval($cart->getTaxedAmount($country)); + + $totalAmount = ($postageAmount + $cartAmount) * 100; + + if (!$totalAmount > 0) { + return false; + } + + $values = [ + 'amount' => intval(round($totalAmount)), + 'currency' => strtolower($currency->getCode()) + ]; + + if (null !== $stripeCustomerId = $this->getStripeCustomerId($session)) { + $values['customer'] = $stripeCustomerId; + } + + return $values; + } + + protected function getStripeCustomerId(Session $session) + { + if (null === $session->getCustomerUser()) { + return null; + } + + if (!$session->has(StripePayment::PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY)) { + /** @var Customer $customer */ + $customer = $session->getCustomerUser(); + $email = $customer->getEmail(); + + $stripeCustomer = \Stripe\Customer::create([ + 'email' => $email + ]); + + $session->set(StripePayment::PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY, $stripeCustomer->id); + } + + return $session->get(StripePayment::PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY); + } + + protected function getCartAndOrderFromEvent(ActionEvent $event) + { + /** @var Session $session */ + $session = $this->request->getSession(); + + if ($event instanceof CartRestoreEvent) { + return [ + 'cart' => $event->getCart(), + 'order' => $session->getOrder() + ]; + } + + if ($event instanceof CartCreateEvent) { + return [ + 'cart' => $event->getCart(), + 'order' => $session->getOrder() + ]; + } + + if ($event instanceof CartEvent) { + return [ + 'cart' => $event->getCart(), + 'order' => $session->getOrder() + ]; + } + + if ($event instanceof CurrencyChangeEvent) { + return [ + 'cart' => $session->getSessionCart($this->dispatcher), + 'order' => $session->getOrder() + ]; + } + + if ($event instanceof OrderEvent) { + return [ + 'cart' => $session->getSessionCart($this->dispatcher), + 'order' => $event->getOrder() + ]; + } + + return false; + } +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/EventListeners/SendConfirmationEmailListener.php b/domokits/local/modules/StripePayment/EventListeners/SendConfirmationEmailListener.php new file mode 100644 index 0000000..2a89ebc --- /dev/null +++ b/domokits/local/modules/StripePayment/EventListeners/SendConfirmationEmailListener.php @@ -0,0 +1,75 @@ +parser = $parser; + $this->mailer = $mailer; + $this->eventDispatcher = $eventDispatcher; + } + + /** + * @return MailerFactory + */ + public function getMailer() + { + return $this->mailer; + } + + public function updateOrderStatus(OrderEvent $event) + { + $stripe = new StripePayment(); + + if ($event->getOrder()->isPaid() && $stripe->isPaymentModuleFor($event->getOrder())) { + $this->eventDispatcher->dispatch($event, TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL); + $this->eventDispatcher->dispatch($event, TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL); + } + } + + + public function cancelOrderConfirmationEmail(OrderEvent $event) + { + $stripe = new StripePayment(); + + if ($stripe->isPaymentModuleFor($event->getOrder()) && !$event->getOrder()->isPaid()) { + $event->stopPropagation(); + } + } + + public static function getSubscribedEvents() + { + return array( + TheliaEvents::ORDER_UPDATE_STATUS => array("updateOrderStatus", 128), + TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => array("cancelOrderConfirmationEmail", 150), + TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => array("cancelOrderConfirmationEmail", 150) + ); + } + +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/Form/Base/StripePaymentConfigForm.php b/domokits/local/modules/StripePayment/Form/Base/StripePaymentConfigForm.php new file mode 100644 index 0000000..0b83966 --- /dev/null +++ b/domokits/local/modules/StripePayment/Form/Base/StripePaymentConfigForm.php @@ -0,0 +1,208 @@ +formBuilder attribute : + * + * $this->formBuilder->add("name", "text") + * ->add("email", "email", array( + * "attr" => array( + * "class" => "field" + * ), + * "label" => "email", + * "constraints" => array( + * new \Symfony\Component\Validator\Constraints\NotBlank() + * ) + * ) + * ) + * ->add('age', 'integer'); + * + * @return null + */ + protected function buildForm() + { + $translationKeys = $this->getTranslationKeys(); + $fieldsIdKeys = $this->getFieldsIdKeys(); + + $this->addEnabledField($translationKeys, $fieldsIdKeys); + $this->addStripeElementField($translationKeys, $fieldsIdKeys); + $this->addOneClickPaymentField($translationKeys, $fieldsIdKeys); + $this->addSecretKeyField($translationKeys, $fieldsIdKeys); + $this->addPublishableKeyField($translationKeys, $fieldsIdKeys); + $this->addWebhooksKeyField($translationKeys, $fieldsIdKeys); + $this->addSecureUrlField($translationKeys, $fieldsIdKeys); + } + + protected function addEnabledField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("enabled", CheckboxType::class, array( + "label" => $this->readKey("enabled", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("enabled", $fieldsIdKeys), + "help" => $this->readKey("help.enabled", $translationKeys) + ], + "required" => false, + "constraints" => array( + ), + "value" => StripePayment::getConfigValue(StripePayment::ENABLED, false), + )) + ; + } + + protected function addStripeElementField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("stripe_element", CheckboxType::class, array( + "label" => $this->readKey("stripe_element", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("stripeelementch", $fieldsIdKeys), + "help" => $this->readKey("help.stripe_element", $translationKeys) + ], + "required" => false, + "constraints" => array( + ), + "value" => StripePayment::getConfigValue(StripePayment::STRIPE_ELEMENT, false), + )) + ; + } + + protected function addOneClickPaymentField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("one_click_payment", CheckboxType::class, array( + "label" => $this->readKey("one_click_payment", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("one_click_payment", $fieldsIdKeys) + ], + "required" => false, + "constraints" => array( + ), + "value" => StripePayment::getConfigValue(StripePayment::ONE_CLICK_PAYMENT, false), + )) + ; + } + + protected function addSecretKeyField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("secret_key", TextType::class, array( + "label" => $this->readKey("secret_key", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("secret_key", $fieldsIdKeys), + "help" => $this->readKey("help.secret_key", $translationKeys) + ], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => StripePayment::getConfigValue(StripePayment::SECRET_KEY), + )) + ; + } + + protected function addPublishableKeyField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("publishable_key", TextType::class, array( + "label" => $this->readKey("publishable_key", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("publishable_key", $fieldsIdKeys), + "help" => $this->readKey("help.publishable_key", $translationKeys) + ], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => StripePayment::getConfigValue(StripePayment::PUBLISHABLE_KEY), + )) + ; + } + + protected function addWebhooksKeyField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("webhooks_key", TextType::class, array( + "label" => $this->readKey("webhooks_key", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("webhooks_key", $fieldsIdKeys), + "help" => $this->readKey("help.webhooks_key", $translationKeys) + ], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => StripePayment::getConfigValue(StripePayment::WEBHOOKS_KEY), + )) + ; + } + protected function addSecureUrlField(array $translationKeys, array $fieldsIdKeys) + { + $this->formBuilder + ->add("secure_url", TextType::class, array( + "label" => $this->readKey("secure_url", $translationKeys), + "label_attr" => [ + "for" => $this->readKey("secure_url", $fieldsIdKeys), + "help" => $this->readKey("help.secure_url", $translationKeys) + ], + "required" => true, + "constraints" => array( + new NotBlank(), + ), + "data" => StripePayment::getConfigValue(StripePayment::SECURE_URL), + )) + ; + } + + public static function getName() + { + return static::FORM_NAME; + } + + public function readKey($key, array $keys, $default = '') + { + if (isset($keys[$key])) { + return $keys[$key]; + } + + return $default; + } + + public function getTranslationKeys() + { + return array(); + } + + public function getFieldsIdKeys() + { + return array( + "enabled" => "enabled", + "secret_key" => "secret_key", + "publishable_key" => "publishable_key", + "webhooks_key" => "webhooks_key", + "secure_url" => "secure_url" + ); + } +} diff --git a/domokits/local/modules/StripePayment/Form/StripePaymentConfigForm.php b/domokits/local/modules/StripePayment/Form/StripePaymentConfigForm.php new file mode 100644 index 0000000..979ce2e --- /dev/null +++ b/domokits/local/modules/StripePayment/Form/StripePaymentConfigForm.php @@ -0,0 +1,33 @@ + $this->translator->trans("Activate payment with stripe ?", [], StripePayment::MESSAGE_DOMAIN), + "stripe_element" => $this->translator->trans("Activate Element ?", [], StripePayment::MESSAGE_DOMAIN), + "one_click_payment" => $this->translator->trans("Activate one click payment ?", [], StripePayment::MESSAGE_DOMAIN), + "secret_key" => $this->translator->trans("Your secret key", [], StripePayment::MESSAGE_DOMAIN), + "publishable_key" => $this->translator->trans("Your publishable key (test or live)", [], StripePayment::MESSAGE_DOMAIN), + "webhooks_key" => $this->translator->trans("Your webhooks key", [], StripePayment::MESSAGE_DOMAIN), + "secure_url" => $this->translator->trans("Your chain of char for secure return webhook", [], StripePayment::MESSAGE_DOMAIN), + "help.enabled" => $this->translator->trans("Do you want to activate Stripe Payment", [], StripePayment::MESSAGE_DOMAIN), + "help.stripe_element" => $this->translator->trans("Element is the embedded and customizable payment form", [], StripePayment::MESSAGE_DOMAIN), + "help.secret_key" => $this->translator->trans("You can see all your keys in your Stripe dashboard. Also note that you can place your test or your live API keys", [], StripePayment::MESSAGE_DOMAIN), + ); + } +} diff --git a/domokits/local/modules/StripePayment/Hook/StripePaymentHook.php b/domokits/local/modules/StripePayment/Hook/StripePaymentHook.php new file mode 100644 index 0000000..b854d6f --- /dev/null +++ b/domokits/local/modules/StripePayment/Hook/StripePaymentHook.php @@ -0,0 +1,74 @@ + + */ +class StripePaymentHook extends BaseHook +{ + protected $request; + + protected $taxEngine; + + public function __construct(Request $request, TaxEngine $taxEngine) + { + $this->request = $request; + $this->taxEngine = $taxEngine; + } + + public function includeStripe(HookRenderEvent $event) + { + if(StripePayment::getConfigValue('stripe_element')){ + $publicKey = StripePayment::getConfigValue('publishable_key'); + $clientSecret = $this->request->getSession()->get(StripePayment::PAYMENT_INTENT_SECRET_SESSION_KEY); + $currency = strtolower($this->request->getSession()->getCurrency()->getCode()); + $country = $this->taxEngine->getDeliveryCountry()->getIsoalpha2(); + $event->add($this->render( + 'assets/js/stripe-js.html', + [ + 'stripe_module_id' => $this->getModule()->getModuleId(), + 'public_key' => $publicKey, + 'oneClickPayment' => StripePayment::getConfigValue(StripePayment::ONE_CLICK_PAYMENT, false), + 'clientSecret' => $clientSecret, + 'currency' => $currency, + 'country' => $country + ] + )); + } + } + + public function declareStripeOnClickEvent(HookRenderEvent $event) + { + if(StripePayment::getConfigValue('stripe_element')){ + $publicKey = StripePayment::getConfigValue('publishable_key'); + $event->add($this->render( + 'assets/js/order-invoice-after-js-include.html', + [ + 'stripe_module_id' => $this->getModule()->getModuleId(), + 'public_key' => $publicKey + ] + )); + } + } + + public function includeStripeJsV3(HookRenderEvent $event) + { + $event->add(''); + } + + public function onMainHeadBottom(HookRenderEvent $event) + { + $content = $this->addCSS('assets/css/styles.css'); + $event->add($content); + } +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/I18n/backOffice/default/en_US.php b/domokits/local/modules/StripePayment/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..115c80f --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/backOffice/default/en_US.php @@ -0,0 +1,12 @@ + 'Configuration correctly saved', + 'Configure stripepayment' => 'Configure stripepayment', + 'Home' => 'Home', + 'Modules' => 'Modules', + 'StripePayment configuration' => 'StripePayment configuration', + 'The configuration value enabled' => 'The configuration value enabled', + 'The configuration value publishable_key' => 'The configuration value publishable_key', + 'The configuration value secret_key' => 'The configuration value secret_key', +); diff --git a/domokits/local/modules/StripePayment/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/StripePayment/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..7fc731d --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,17 @@ + 'Configuration correctement sauvegardée', + 'Configure stripepayment' => 'Configurer Stripe', + 'Home' => 'Accueil', + 'Modules' => 'Modules', + 'StripePayment configuration' => 'Configuration du module Stripe', + 'The configuration value enabled' => 'La valeur de configuration "enabled"', + 'The configuration value publishable_key' => 'La valeur de configuration "publishable_key"', + 'The configuration value secret_key' => 'La valeur de configuration "secret_key"', + 'The configuration value secure_url' => 'La valeur de configuration secure_url', + 'The configuration value webhooks_key whsec_...' => 'La valeur de configuration webhooks_key whsec_...', + 'Webhooks endpoint url' => 'URL d\'endpoint WebHook', + 'Webhooks event to activate' => 'Événements WebHook à activer', + 'active stripe element' => 'Activer Stripe Element', +); diff --git a/domokits/local/modules/StripePayment/I18n/email/default/en_US.php b/domokits/local/modules/StripePayment/I18n/email/default/en_US.php new file mode 100644 index 0000000..a3bd1cb --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/email/default/en_US.php @@ -0,0 +1,13 @@ + 'Dear customer,', + 'Payment is confirmed for your order' => 'Payment is confirmed for your order', + 'Reference %ref' => 'Reference: %ref', + 'Thank you again for your purchase.' => 'Thank you again for your purchase!', + 'Thank you for your order!' => 'Thank you for your order!', + 'The %name team.' => 'The %name team.', + 'This is a confirmation of the payment of your order %order on %name.' => 'This is a confirmation of the payment of your order %order on %name.', + 'Your invoice is now available in your customer account on' => 'Your invoice is now available in your customer account on', + 'Your invoice is now available in your customer account on %site' => 'Your invoice is now available in your customer account on %site.', +); diff --git a/domokits/local/modules/StripePayment/I18n/email/default/fr_FR.php b/domokits/local/modules/StripePayment/I18n/email/default/fr_FR.php new file mode 100644 index 0000000..2b922e5 --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/email/default/fr_FR.php @@ -0,0 +1,13 @@ + 'Cher client,', + 'Payment is confirmed for your order' => 'Le paiement de votre commande est confirmé', + 'Reference %ref' => 'Référence de commande : %ref', + 'Thank you again for your purchase.' => 'Merci encore pour cet achat !', + 'Thank you for your order!' => 'Merci pour votre commande !', + 'The %name team.' => 'L\'équipe %name.', + 'This is a confirmation of the payment of your order %order on %name.' => 'Ce message confirme le paiement de votre commande n° %order sur %name.', + 'Your invoice is now available in your customer account on' => 'Votre facture est maintenant disponible sur votre compte sur ', + 'Your invoice is now available in your customer account on %site' => 'Votre facture est maintenant disponible sur votre compte sur %site. ', +); diff --git a/domokits/local/modules/StripePayment/I18n/en_US.php b/domokits/local/modules/StripePayment/I18n/en_US.php new file mode 100644 index 0000000..88eb9c9 --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/en_US.php @@ -0,0 +1,21 @@ + 'Activated ?', + 'An error occurred during payment.' => 'An error occurred during payment.', + 'An error occurred with Stripe.' => 'An error occurred with Stripe.', + 'Authentication with Stripe failed. Please contact administrators.' => 'Authentication with Stripe failed. Please contact administrators.', + 'Do you want to activate Stripe Payment' => 'Do you want to activate Stripe Payment', + 'Invalid parameters were supplied to Stripe.' => 'Invalid parameters were supplied to Stripe.', + 'Network communication failed.' => 'Network communication failed.', + 'Payment confirmation of your order {$order_ref} on %store_name' => 'Payment confirmation of your order {$order_ref} on %store_name', + 'Payment confirmation on %store_name' => 'Payment confirmation on %store_name', + 'Sorry, an error occurred: %err' => 'Sorry, an error occurred: %err', + 'Stripe library isn\'t installed' => 'Stripe library isn\'t installed', + 'The payment mean does not have the same amount as your cart. Please reload and try again.' => 'The payment mean does not have the same amount as your cart. Please reload and try again.', + 'Too many requests too quickly.' => 'Too many requests too quickly.', + 'You can see all your keys in your Stripe dashboard. Also note that you can place your test or your live API keys' => 'You can see all your keys in your Stripe dashboard. Also note that you have to place your test and your live API keys', + 'Your card has been declined.' => 'Your card has been declined.', + 'Your publishable key (test or live)' => 'Your publishable key (test or live)', + 'Your secret key' => 'Your secret key', +); diff --git a/domokits/local/modules/StripePayment/I18n/fr_FR.php b/domokits/local/modules/StripePayment/I18n/fr_FR.php new file mode 100644 index 0000000..c265567 --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/fr_FR.php @@ -0,0 +1,29 @@ + 'Activer Element ?', + 'Activate payment with stripe ?' => 'Activer le paiement avec Stripe ?', + 'An error occurred during payment.' => 'Une erreur est survenue lors du paiement.', + 'An error occurred with Stripe.' => 'Une erreur est survenue lors du paiement avec Stripe.', + 'Authentication with Stripe failed. Please contact administrators.' => 'Des paramètres invalides ont été envoyés à Stripe.', + 'Discount' => 'Remise', + 'Do you want to activate Stripe Payment' => 'Voulez-vous activer Stripe ?', + 'Element is the embedded and customizable payment form' => 'Element est un formulaire intégrer et personlisable.', + 'Invalid parameters were supplied to Stripe.' => 'Une erreur liée au réseau empêche la communication avec Stripe.', + 'Network communication failed.' => 'L\'authentification auprès de Stripe a échoué. Merci de contacter les administrateurs du site.', + 'Payment confirmation for Stripe Payment' => 'Confirmation de paiement par Stripe', + 'Payment confirmation of your order {$order_ref} on {$store_name}' => 'Confirmation de paiement pour votre commande {$order_ref} sur {$store_name}', + 'Sorry, an error occurred: %err' => 'Désolé, une erreur est survenue : %err', + 'Stripe library is missing.' => 'La libraire Stripe est manquante', + 'Stripe version is greater than max version (< %version). Current version: %curVersion.' => 'La version de la libraire Stripe est plus haute qua la version maximum ( < %version). Version actuelle %curVersion.', + 'Stripe version is lower than min version (%version). Current version: %curVersion.' => 'La version de la libraire Stripe est plus basse qua la version minimum ( > %version). Version actuelle %curVersion.', + 'The payment mean does not have the same amount as your cart. Please reload and try again.' => 'Le moyen de paiement n\'indique pas le même montant que votre panier. Rechargez la pager et réessayez.', + 'Too many requests too quickly.' => 'Trop de requêtes en peu de temps.', + 'Total' => 'Total', + 'You can see all your keys in your Stripe dashboard. Also note that you can place your test or your live API keys' => 'Vos clés sont disponibles dans votre compte sur la plateforme d\'administration Stripe. Veuillez noter que vous devez renseigner ici vos clés publique et privée.', + 'Your card has been declined.' => 'Votre carte bancaire a été refusée.', + 'Your chain of char for secure return webhook' => 'Une chaine de caractère pour sécuriser le retour des Webhooks', + 'Your publishable key (test or live)' => 'Votre clé publique', + 'Your secret key' => 'Votre clé secrète', + 'Your webhooks key' => 'Votre clé Webhooks ?', +); diff --git a/domokits/local/modules/StripePayment/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/StripePayment/I18n/frontOffice/default/fr_FR.php new file mode 100644 index 0000000..855d244 --- /dev/null +++ b/domokits/local/modules/StripePayment/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,6 @@ + 'Ou entrer les détails de votre carte de crédit', + 'Quick pay' => 'Paiement rapide', +); diff --git a/domokits/local/modules/StripePayment/LICENSE.txt b/domokits/local/modules/StripePayment/LICENSE.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/domokits/local/modules/StripePayment/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/domokits/local/modules/StripePayment/Readme.md b/domokits/local/modules/StripePayment/Readme.md new file mode 100644 index 0000000..a6856f9 --- /dev/null +++ b/domokits/local/modules/StripePayment/Readme.md @@ -0,0 +1,43 @@ +# Stripe + +Thelia payment module for [Stripe](http://stripe.com). + +You need a subscription to Stripe payment solution to use this module. + +## Installation + +Either you install StripePayment manually or via composer, the presence of Stripe API files is checked when you try to activate the module. +If the API files are absent, you can't use Stripe. +Be aware that API files are set into the core/vendor folder. + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is StripePayment. +* Install the Stripe PHP library : + * add "stripe/stripe-php" to your composer.json file with command : `composer require stripe/stripe-php:"6.*"` + * or download the library from and install it in your `core/vendor` directory +* Activate it in your Thelia administration panel + + +### Composer + +Add it in your main thelia composer.json file: + +``` +composer require thelia/stripe-payment-module ~2.0.0 +``` + +### Configuration + +Enter your Stripe keys (*secret* and *public*) available on your [Stripe dashboard](https://dashboard.stripe.com/). + +Put your Stripe account in live mode. + +Then activate the Stripe in the module configuration panel. + +Activate the webhooks in stripe dashboard with the url specified in Thelia Back-office Stripe configuration, +and add events listed in Thelia Back-office Stripe configuration. + +### Logs + +Stripe error logs are stored in a specific file located in the log folder. diff --git a/domokits/local/modules/StripePayment/Resource/images/module/stripe.png b/domokits/local/modules/StripePayment/Resource/images/module/stripe.png new file mode 100644 index 0000000000000000000000000000000000000000..20b7de7b5736fee12a83cbb932e87b38127c2fb2 GIT binary patch literal 58172 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

158iNo&|W@WJ46i$la-Km^hsBM)EiW4 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 + */ +class StripePayment extends AbstractPaymentModule +{ + const MESSAGE_DOMAIN = "stripepayment"; + const CONFIRMATION_MESSAGE_NAME = "stripe_confirm_payment"; + + const PAYMENT_INTENT_ID_SESSION_KEY = 'payment_intent_id'; + const PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY = 'payment_intent_customer_id'; + const PAYMENT_INTENT_SECRET_SESSION_KEY = 'payment_intent_secret'; + + const ENABLED = "enabled"; + const STRIPE_ELEMENT = "stripe_element"; + const ONE_CLICK_PAYMENT = "one_click_payment"; + const SECRET_KEY = "secret_key"; + const PUBLISHABLE_KEY = "publishable_key"; + const WEBHOOKS_KEY = "webhooks_key"; + const SECURE_URL = "secure_url"; + + public function preActivation(ConnectionInterface $con = null) + { + // Check if Stripe API is present + try { + $this->checkApi(); + } catch (\Exception $ex) { + throw $ex; + } + + return true; + } + + public function postActivation(ConnectionInterface $con = null): void + { + // Module image + $moduleModel = $this->getModuleModel(); + + if (! $moduleModel->isModuleImageDeployed($con)) { + $this->deployImageFolder($moduleModel, sprintf('%s'.DS.'Resource'.DS.'images'.DS.'module', __DIR__), $con); + } + + $this->createMailMessage(); + } + + public function createMailMessage() + { + // Create payment confirmation message from templates, if not already defined + if (null === MessageQuery::create()->findOneByName(self::CONFIRMATION_MESSAGE_NAME)) { + + $languages = LangQuery::create()->find(); + + $message = new Message(); + $message + ->setName(self::CONFIRMATION_MESSAGE_NAME) + ->setHtmlTemplateFileName(self::CONFIRMATION_MESSAGE_NAME.'.html') + ->setTextTemplateFileName(self::CONFIRMATION_MESSAGE_NAME.'.txt') + ; + + foreach ($languages as $language) { + /** @var Lang $language */ + $locale = $language->getLocale(); + $message + ->setLocale($locale) + ->setTitle( + Translator::getInstance()->trans( + "Payment confirmation for Stripe Payment", + [], + self::MESSAGE_DOMAIN, + $locale + ) + ) + ->setSubject( + Translator::getInstance()->trans( + 'Payment confirmation of your order {$order_ref} on {$store_name}', + [], + self::MESSAGE_DOMAIN, + $locale + ) + ) + ; + } + + $message->save(); + } + } + + public function checkApi() + { + try { + $ReflectedClass = new \ReflectionClass('Stripe\Stripe'); + } catch (\Exception $ex) { + throw new \Exception( + Translator::getInstance()->trans( + "Stripe library is missing.", + [], + self::MESSAGE_DOMAIN + ) + ); + } + } + + /** + * + * Method used by payment gateway. + * + * If this method return a \Thelia\Core\HttpFoundation\Response instance, this response is send to the + * browser. + * + * In many cases, it's necessary to send a form to the payment gateway. On your response you can return this form already + * completed, ready to be sent + * + * @param \Thelia\Model\Order $order processed order + * @return null|\Thelia\Core\HttpFoundation\Response + */ + public function pay(Order $order) + { + if (!$this->isValidPayment()) { + throw new Exception("Your connection is not secured. Check that 'https' is present at the beginning of the site's address."); + } + + return $this->doPay($order); + } + + protected function doPay(Order $order) + { + $session = $this->getRequest()->getSession(); + + try { + + if(StripePayment::getConfigValue('stripe_element')){ + $order->setTransactionRef($session->get(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY)) + ->save(); + $session->set(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY, null); + $session->set(StripePayment::PAYMENT_INTENT_SECRET_SESSION_KEY, null); + $session->set(StripePayment::PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY, null); + + return; + } + + $session->set(StripePayment::PAYMENT_INTENT_ID_SESSION_KEY, null); + $session->set(StripePayment::PAYMENT_INTENT_SECRET_SESSION_KEY, null); + $session->set(StripePayment::PAYMENT_INTENT_CUSTOMER_ID_SESSION_KEY, null); + + // Create the session on Stripe's servers - this will charge the user's order and save session id into order transaction reference + return $this->createStripeSession($order); + } catch(\Stripe\Exception\CardException $e) { + // The card has been declined + // FIXME Translate message here + $logMessage = sprintf( + 'Error paying order %d with Stripe. Card declined. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'Your card has been declined.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (\Stripe\Exception\RateLimitException $e) { + // Too many requests made to the API too quickly + $logMessage = sprintf( + 'Error paying order %d with Stripe. Too many requests. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'Too many requests too quickly.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (\Stripe\Exception\InvalidRequestException $e) { + // Invalid parameters were supplied to Stripe's API + $logMessage = sprintf( + 'Error paying order %d with Stripe. Invalid parameters. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'Invalid parameters were supplied to Stripe.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (\Stripe\Exception\AuthenticationException $e) { + // Authentication with Stripe's API failed + // (maybe you changed API keys recently) + $logMessage = sprintf( + 'Error paying order %d with Stripe. Authentication failed: API key changed? Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'Authentication with Stripe failed. Please contact administrators.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (\Stripe\Exception\ApiConnectionException $e) { + // Network communication with Stripe failed + $logMessage = sprintf( + 'Error paying order %d with Stripe. Network communication failed. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'Network communication failed.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (\Stripe\Exception\ApiErrorException $e) { + // Display a very generic error to the user + $logMessage = sprintf( + 'Error paying order %d with Stripe. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'An error occurred with Stripe.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } catch (StripePaymentException $e) { + // Amount shown to the user by Stripe & order amount are not equal + $logMessage = sprintf( + 'Error paying order %d with Stripe. Amounts are different. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = $e->getMessage(); + } catch (\Exception $e) { + // Something else happened, completely unrelated to Stripe + $logMessage = sprintf( + 'Error paying order %d with Stripe but maybe unrelated with it. Message: %s', + $order->getId(), + $e->getMessage() + ); + + $userMessage = Translator::getInstance() + ->trans( + 'An error occurred during payment.', + [], + StripePayment::MESSAGE_DOMAIN + ); + } + + if ($logMessage !== NULL) { + (new StripePaymentLog())->logText($logMessage); + + return new RedirectResponse( + URL::getInstance()->absoluteUrl("/order/failed/".$order->getId()."/".$userMessage) + ); + } + + return new Response(); + } + + public function createStripeSession(OrderModel $order) + { + /* Impossible d'ajouter une ligne spécifique pour la remise, cette partie est mise de côté en attendant que stripe ajoute cette possibilité + + $lineItems = $this->prepareLineItems($order); + + */ + + $currency = $order->getCurrency(); + + if (null === $currency) { + $currency = $this->getRequest()->getSession()->getCurrency(); + } + + $lineItems[] = [ + 'name'=> Translator::getInstance()->trans('Total', [], StripePayment::MESSAGE_DOMAIN ), + 'quantity'=> 1, + 'currency' => strtolower($currency->getCode()), + 'amount' => round($order->getTotalAmount(), 2) * 100 + ]; + + if(empty($lineItems)){ + throw new \Exception("Sorry, your cart is empty. There's nothing to pay."); + } + + $stripe = new \Stripe\StripeClient(StripePayment::getConfigValue('secret_key')); + + $session = $stripe->checkout->sessions->create([ + 'customer_email' => $order->getCustomer()->getEmail(), + 'client_reference_id' => $order->getRef(), + 'payment_method_types' => ['card'], + 'line_items' => $lineItems, + 'mode' => 'payment', + 'success_url' => URL::getInstance()->absoluteUrl('/order/placed/' . $order->getId()), + 'cancel_url' => URL::getInstance()->absoluteUrl('/order/failed/' . $order->getId() . '/error'), + ]); + + $order->setTransactionRef($session->payment_intent)->save(); + + /** @var ParserInterface $parser */ + $parser = $this->getContainer()->get("thelia.parser"); + + $parser->setTemplateDefinition( + $parser->getTemplateHelper()->getActiveFrontTemplate(), + true + ); + + $renderedTemplate = $parser->render( + "stripe-paiement.html", + [ + 'checkout_session_id' => $session->id, + 'public_key' => StripePayment::getConfigValue('publishable_key') + ] + ); + + return new Response($renderedTemplate); + } + + /** + * + * This method is call on Payment loop. + * + * If you return true, the payment method will be display + * If you return false, the payment method will not be display + * + * @return boolean + */ + public function isValidPayment() + { + $secretKey = self::getConfigValue(self::SECRET_KEY); + return ( (($this->isDevEnvironment() || $this->isSslEnabled()) && self::getConfigValue('enabled')) && $secretKey && $this->getCurrentOrderTotalAmount() > 0); + } + + /** + * Return true if the current environment is in Dev mode + * + * @return bool + */ + protected function isDevEnvironment() + { + return 'dev' === $this->getContainer()->getParameter('kernel.environment'); + } + + /** + * return true if SSL is enabled + * + * @return bool + */ + protected function isSslEnabled() + { + return $this->getRequest()->isSecure(); + } + + public function checkOrderAmount(OrderModel $order, $stripeAmount) + { + $orderAmount = $order->getTotalAmount() * 100; + + if (strval($stripeAmount) != strval($orderAmount)) { + throw new StripePaymentException(Translator::getInstance() + ->trans( + 'The payment mean does not have the same amount as your cart. Please reload and try again.', + [], + StripePayment::MESSAGE_DOMAIN + ) + ); + } + } + + protected function prepareLineItems(Order $order, $currency) + { + $stripeAmount = 0; + $lineItems = []; + + $baseSourceFilePath = ConfigQuery::read('images_library_path'); + if ($baseSourceFilePath === null) { + $baseSourceFilePath = THELIA_LOCAL_DIR . 'media' . DS . 'images'; + } else { + $baseSourceFilePath = THELIA_ROOT . $baseSourceFilePath; + } + if(null !== $orderProducts = OrderProductQuery::create()->filterByOrderId($order->getId())->joinOrderProductTax('opt', Criteria::LEFT_JOIN)->withColumn('SUM(`opt`.AMOUNT)', 'TOTAL_TAX')->withColumn('SUM(`opt`.PROMO_AMOUNT)', 'TOTAL_PROMO_TAX')->groupById()->find()){ + foreach ($orderProducts as $orderProduct) { + $description=''; + if(null !== $orderProductAttributeCombinations = OrderProductAttributeCombinationQuery::create()->filterByOrderProductId($orderProduct->getId())->find()){ + foreach ($orderProductAttributeCombinations as $orderProductAttributeCombination) { + if($description) $description .= ', '; + $description .= $orderProductAttributeCombination->getAttributeTitle() . ' ' . $orderProductAttributeCombination->getAttributeAvTitle(); + } + } + $images=array(); + if(null !== $product = ProductQuery::create()->filterByRef($orderProduct->getProductRef())->findOne()){ + if(null !== $productImages = ProductImageQuery::create()->filterByProductId($product->getId())->filterByVisible(1)->orderBy('position')->find()){ + foreach ($productImages as $productImage) { + // Put source image file path + $sourceFilePath = sprintf( + '%s/%s/%s', + $baseSourceFilePath, + 'product', + $productImage->getFile() + ); + + // Create image processing event + $event = new ImageEvent(); + $event->setSourceFilepath($sourceFilePath); + $event->setCacheSubdirectory('product'); + $width=100; + try { + // Dispatch image processing event + $event->setWidth($width); + $order->getDispatcher()->dispatch(TheliaEvents::IMAGE_PROCESS, $event); + $images[]=$event->getFileUrl(); + } catch (\Exception $ex) { + // Ignore the result and log an error + Tlog::getInstance()->addError(sprintf("Failed to process image in image loop: %s", $ex->getMessage())); + } + } + } + } + if($orderProduct->getWasInPromo()){ + $amount = (float) $orderProduct->getPromoPrice() + (float) $orderProduct->getVirtualColumn('TOTAL_PROMO_TAX'); + }else{ + $amount = (float) $orderProduct->getPrice() + (float) $orderProduct->getVirtualColumn('TOTAL_TAX'); + } + + $stripeAmount += $amount * $orderProduct->getQuantity() * 100; + $lineItems[] = [ + 'name' => $orderProduct->getTitle(), + 'description' => $description, + 'images' => $images, + 'amount' => $amount*100, + 'currency' => $currency, + 'quantity' => $orderProduct->getQuantity(), + ]; + } + } + if ($order->getPostage()){ + if (null !== $module = ModuleQuery::create()->findPk($order->getDeliveryModuleId())){ + $locale = $this->getRequest()->getLocale(); + if ($locale === 'en') { + $locale = 'en_US'; + } + $module->setLocale($locale); + + if (!$module->getTitle()) { + $module->setLocale('fr_FR'); + } + $lineItems[] = ['name'=> $module->getTitle(), 'description' => $module->getChapo(), 'quantity'=> 1, 'currency' => $currency, 'amount' => ($order->getPostage()*100)]; + $stripeAmount += $order->getPostage() * 100; + } + } + + if($order->getDiscount() > 0){ + $description=null; + if(null !== $orderCoupons = OrderCouponQuery::create()->filterByOrderId($order->getId())->find()){ + foreach($orderCoupons as $orderCoupon){ + if($description)$description .= ', '; + $description .= $orderCoupon->getTitle(); + } + } + $lineItems[] = ['name'=> Translator::getInstance()->trans('Discount', [], StripePayment::MESSAGE_DOMAIN ), 'description' => $description, 'quantity'=> 1, 'currency' => $currency, 'amount' => -($order->getDiscount()*100)]; + $stripeAmount -= $order->getDiscount() * 100; + } + + $this->checkOrderAmount($order, $stripeAmount); + + return $lineItems; + } + + + /** + * if you want, you can manage stock in your module instead of order process. + * Return false to decrease the stock when order status switch to pay + * + * @return bool + */ + public function manageStockOnCreation() + { + return false; + } + + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR . ucfirst(self::getModuleCode()). "/I18n/*"]) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/StripePayment/composer.json b/domokits/local/modules/StripePayment/composer.json new file mode 100644 index 0000000..6341e7d --- /dev/null +++ b/domokits/local/modules/StripePayment/composer.json @@ -0,0 +1,12 @@ +{ + "name": "thelia/stripe-payment-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1", + "stripe/stripe-php": "^v7.100" + }, + "extra": { + "installer-name": "StripePayment" + } +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/templates/backOffice/default/stripepayment-configuration.html b/domokits/local/modules/StripePayment/templates/backOffice/default/stripepayment-configuration.html new file mode 100644 index 0000000..87a1794 --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/backOffice/default/stripepayment-configuration.html @@ -0,0 +1,174 @@ +

+
+
+ {intl l="Configure stripepayment" d="stripepayment.bo.default"} +
+ +
+
+ {if $success|default:null} +
+ {intl l="Configuration correctly saved" d="stripepayment.bo.default"} +
+ {/if} + + {form name="stripepayment_config_form"} + + {include "includes/inner-form-toolbar.html" hide_flags = 1 close_url={url path='/admin/modules'}} +
+ + {form_field form=$form field="success_url"} + + {/form_field} + + {form_hidden_fields form=$form} + + {form_field form=$form field="enabled"} +
+ + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + {form_field form=$form field="stripe_element"} +
+ + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + {form_field form=$form field="one_click_payment"} +
+ + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + {form_field form=$form field="secret_key"} +
+ + + + {if ! empty($label_attr.help)} + {$label_attr.help nofilter} + {/if} +
+ {/form_field} + {form_field form=$form field="publishable_key"} +
+ + + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="webhooks_key"} +
+ + + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + + {form_field form=$form field="secure_url"} +
+ + + + {if ! empty($label_attr.help)} + {$label_attr.help} + {/if} +
+ {/form_field} + +
+ + +
+ +
+ +
    +
  • payment_intent.payment_failed
  • +
  • payment_intent.succeeded
  • +
  • checkout.session.completed
  • +
+
+ {include "includes/inner-form-toolbar.html" hide_flags = 1 close_url={url path='/admin/modules'} page_bottom=1} + + {/form} +
+
+
+
diff --git a/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.html b/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.html new file mode 100644 index 0000000..b57d755 --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.html @@ -0,0 +1,34 @@ +{extends file="email-layout.tpl"} + +{* Open in browser *} +{block name="browser"}{/block} + +{* No big image header *} +{block name="image-header"}{/block} + +{* No pre-header *} +{block name="pre-header"}{/block} + +{* Subject *} +{block name="email-subject"}Payment confirmation {$store_name}{/block} + +{* Title *} +{block name="email-title"}{/block} + +{* Content *} +{block name="email-content"} +

{$store_name}

+ +

{intl l="Payment is confirmed for your order" d="stripepayment.email.default"}

+ +

{intl l="Reference %ref" ref={$order_ref} d="stripepayment.email.default"}

+ +

+ {intl l="Your invoice is now available in your customer account on" d="stripepayment.email.default"} + {$store_name}. +

+ +

{intl l="Thank you for your order!" d="stripepayment.email.default"}

+ +

{intl l="The %name team." name={$store_name} d="stripepayment.email.default"}

+{/block} diff --git a/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.txt b/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.txt new file mode 100644 index 0000000..1e3c866 --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/email/default/stripe_confirm_payment.txt @@ -0,0 +1,9 @@ +{intl l="Dear customer," d="stripepayment.email.default"} + +{intl l="This is a confirmation of the payment of your order %order on %name." order={$order_ref} name={$store_name} d="stripepayment.email.default"} + +{intl l="Your invoice is now available in your customer account on %site" site={$store_url} d="stripepayment.email.default"} + +{intl l="Thank you again for your purchase." d="stripepayment.email.default"} + +{intl l="The %name team." name={$store_name} d="stripepayment.email.default"} diff --git a/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/css/styles.css b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/css/styles.css new file mode 100644 index 0000000..87bff2d --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/css/styles.css @@ -0,0 +1,61 @@ +/** + * The CSS shown here will not be introduced in the Quickstart guide, but shows + * how you can use CSS to style your Element's container. + */ +.payment { + margin-bottom: 20px; +} +.stripe-payment { + width: 80%; + margin: auto; + text-align: center; +} +.stripe-payment .payment{ + background-color: #f5f5f5; + border-radius: 5px; +} +.stripe-payment .payment-label { + font-size: 20px; + font-weight: 500; +} +#payment-request-button { + margin-top: 10px; +} +#card-element { + box-sizing: border-box; + + height: 40px; + + padding: 10px 12px; + + border: 1px solid transparent; + border-radius: 4px; + background-color: white; + + box-shadow: 0 1px 3px 0 #e6ebf1; + -webkit-transition: box-shadow 150ms ease; + transition: box-shadow 150ms ease; +} + +#card-element--focus { + box-shadow: 0 1px 3px 0 #cfd7df; +} + +#card-element--invalid { + border-color: #fa755a; +} + +#card-element--webkit-autofill { + background-color: #fefde5 !important; +} +#card-errors, #payment-request-errors { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; + border-radius: .25rem; + padding: .75rem 1.25rem; + text-align: center; +} +#card-errors.hidden, #payment-request-errors.hidden { + display: none; +} \ No newline at end of file diff --git a/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/order-invoice-after-js-include.html b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/order-invoice-after-js-include.html new file mode 100644 index 0000000..58040e7 --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/order-invoice-after-js-include.html @@ -0,0 +1,166 @@ + diff --git a/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/stripe-js.html b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/stripe-js.html new file mode 100644 index 0000000..720ee8e --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/frontOffice/default/assets/js/stripe-js.html @@ -0,0 +1,29 @@ + + +
+ {if $oneClickPayment} +
+ {intl l="Quick pay" d="stripepayment.fo.default"} +
+ +
+ +
+ + {/if} +
+ {if $oneClickPayment} + {intl l="Or enter card details" d="stripepayment.fo.default"} + {/if} +
+ +
+
+ +
diff --git a/domokits/local/modules/StripePayment/templates/frontOffice/default/stripe-paiement.html b/domokits/local/modules/StripePayment/templates/frontOffice/default/stripe-paiement.html new file mode 100644 index 0000000..1654133 --- /dev/null +++ b/domokits/local/modules/StripePayment/templates/frontOffice/default/stripe-paiement.html @@ -0,0 +1,16 @@ + + \ No newline at end of file diff --git a/domokits/local/modules/TheliaBlocks/.github/workflows/npm-publish.yml b/domokits/local/modules/TheliaBlocks/.github/workflows/npm-publish.yml new file mode 100644 index 0000000..e7a8905 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/.github/workflows/npm-publish.yml @@ -0,0 +1,24 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages + +name: Node.js Package + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd templates/backOffice/default/app && npm ci + - run: cd templates/backOffice/default/app && npm run build + - run: cd templates/backOffice/default/app && npm publish --access public + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + diff --git a/domokits/local/modules/TheliaBlocks/.github/workflows/release.yml b/domokits/local/modules/TheliaBlocks/.github/workflows/release.yml new file mode 100644 index 0000000..91f2a25 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/TheliaBlocks/.gitignore b/domokits/local/modules/TheliaBlocks/.gitignore new file mode 100755 index 0000000..80e5be4 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/.gitignore @@ -0,0 +1,3 @@ +node_modules +.DS_Store + diff --git a/domokits/local/modules/TheliaBlocks/.husky/pre-commit b/domokits/local/modules/TheliaBlocks/.husky/pre-commit new file mode 100755 index 0000000..a9f6a01 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run build diff --git a/domokits/local/modules/TheliaBlocks/Command/ValidateJsonContent.php b/domokits/local/modules/TheliaBlocks/Command/ValidateJsonContent.php new file mode 100644 index 0000000..7b9614f --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Command/ValidateJsonContent.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Command; + +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Thelia\Command\ContainerAwareCommand; +use TheliaBlocks\Model\BlockGroupI18nQuery; + +class ValidateJsonContent extends ContainerAwareCommand +{ + public function __construct() + { + parent::__construct(); + } + + protected function configure(): void + { + $this + ->setName('thelia_blocks:blocks:validate') + ->setDescription('Validate & update json_content structure'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $jsonContents = BlockGroupI18nQuery::create()->find(); + + $output->writeln('============================================================= '); + $output->writeln('Thelia blocks json_content validation started'); + $progressBar = new ProgressBar($output, $jsonContents->count()); + $progressBar->start(); + + foreach ($jsonContents as $jsonContent) { + $content = $jsonContent->getJsonContent(); + + $decodedJson = json_decode($content, true); + + foreach ($decodedJson as $key => $value) { + /* if ($value['type']['id'] === 'blockAccordion') { + $oldData = $decodedJson[$key]['data']; + + $group = array_map(function ($item) { + if (isset($item['group'])) { + $item['content'] = []; + $item['content'][] = $item['group']; + + unset($item['group']); + + $item['content'][0]['data'] = ['content' => [$item['content'][0]['data']]]; + } + + return $item; + }, $oldData); + + $decodedJson[$key]['data'] = [ + 'title' => '', + 'group' => $group, + ]; + } */ + + if ($value['type']['id'] === "blockAccordion") { + $accordionTitle = $decodedJson[$key]['data']['group']['title']; + $accordionContent = $decodedJson[$key]['data']['group']['group']; + + $decodedJson[$key]['data'] = [ + 'title' => $accordionTitle, + 'group' => $accordionContent, + ]; + } + + if ($value['type']['id'] === 'blockGroup') { + $oldData = $decodedJson[$key]['data']; + + $itemsFromData = array_map(function ($item) { + return $item; + }, $oldData); + + $decodedJson[$key]['data'] = [ + 'content' => [$itemsFromData], + ]; + } + + if ($value['type']['id'] === 'multiColumns') { + $oldData = $decodedJson[$key]['data']; + + $itemsFromGroupsInCol = array_map(function ($item) { + if (isset($item['group'])) { + $item = $item['group']['data']; + } + + foreach ($item as $index => $column){ + if (null === $column['type']['id'] || empty($column['type']['id'])) { + unset($item[$index]); + } + } + + return $item; + }, $oldData); + + $oldData = $itemsFromGroupsInCol; + + $decodedJson[$key]['title'] = [ + 'default' => \count($itemsFromGroupsInCol) . ' Columns', + 'fr' => \count($itemsFromGroupsInCol) . ' Colonnes', + 'en' => \count($itemsFromGroupsInCol) . ' Columns', + 'es' => \count($itemsFromGroupsInCol) . ' Columnas', + 'it' => \count($itemsFromGroupsInCol) . ' Colonne', + ]; + + $decodedJson[$key]['data'] = $oldData; + } + } + + $jsonContent->setJsonContent(json_encode($decodedJson)); + + $jsonContent->save(); + + $progressBar->advance(); + } + + $progressBar->finish(); + $output->writeln(''); + $output->writeln('Thelia blocks json_content validation ended'); + $output->writeln('============================================================= '); + + return 1; + } +} diff --git a/domokits/local/modules/TheliaBlocks/Config/TheliaMain.sql b/domokits/local/modules/TheliaBlocks/Config/TheliaMain.sql new file mode 100644 index 0000000..91cdbc5 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/TheliaMain.sql @@ -0,0 +1,64 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- block_group +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `block_group`; + +CREATE TABLE `block_group` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `slug` VARCHAR(50), + `visible` TINYINT DEFAULT 0 NOT NULL, + `created_at` DATETIME, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + UNIQUE INDEX `slug_unique` (`slug`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- item_block_group +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `item_block_group`; + +CREATE TABLE `item_block_group` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `item_type` VARCHAR(255), + `item_id` INTEGER, + `block_group_id` INTEGER, + PRIMARY KEY (`id`), + INDEX `fi_item_block_group_block_group_id` (`block_group_id`), + CONSTRAINT `fk_item_block_group_block_group_id` + FOREIGN KEY (`block_group_id`) + REFERENCES `block_group` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- block_group_i18n +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `block_group_i18n`; + +CREATE TABLE `block_group_i18n` +( + `id` INTEGER NOT NULL, + `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255) NOT NULL, + `json_content` TEXT, + PRIMARY KEY (`id`,`locale`), + CONSTRAINT `block_group_i18n_fk_d94d4c` + FOREIGN KEY (`id`) + REFERENCES `block_group` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/TheliaBlocks/Config/config.xml b/domokits/local/modules/TheliaBlocks/Config/config.xml new file mode 100755 index 0000000..eb30e5e --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/config.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/TheliaBlocks/Config/module.xml b/domokits/local/modules/TheliaBlocks/Config/module.xml new file mode 100755 index 0000000..4dc156e --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/module.xml @@ -0,0 +1,40 @@ + + + TheliaBlocks\TheliaBlocks + + Assemble blocks and display them wherever you want + + + + Assemblez des blocs et afficher les où vous voulez + + + + + en_US + fr_FR + + 2.1.15 + + + + + + + classic + + OpenApi + ShortCode + TheliaLibrary + + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/TheliaBlocks/Config/routing.xml b/domokits/local/modules/TheliaBlocks/Config/routing.xml new file mode 100755 index 0000000..fc772b7 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/routing.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/domokits/local/modules/TheliaBlocks/Config/schema.xml b/domokits/local/modules/TheliaBlocks/Config/schema.xml new file mode 100755 index 0000000..c14f2fe --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/schema.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
diff --git a/domokits/local/modules/TheliaBlocks/Config/sqldb.map b/domokits/local/modules/TheliaBlocks/Config/sqldb.map new file mode 100755 index 0000000..a58fd16 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +TheliaMain.sql=TheliaMain diff --git a/domokits/local/modules/TheliaBlocks/Config/update/1.0.1.sql b/domokits/local/modules/TheliaBlocks/Config/update/1.0.1.sql new file mode 100644 index 0000000..213be37 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/update/1.0.1.sql @@ -0,0 +1,24 @@ +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +DROP TABLE IF EXISTS `item_block_group`; + +CREATE TABLE `item_block_group` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `item_type` VARCHAR(255), + `item_id` INTEGER, + `block_group_id` INTEGER, + PRIMARY KEY (`id`), + INDEX `fi_item_block_group_block_group_id` (`block_group_id`), + CONSTRAINT `fk_item_block_group_block_group_id` + FOREIGN KEY (`block_group_id`) + REFERENCES `block_group` (`id`) + ON UPDATE RESTRICT + ON DELETE CASCADE +) ENGINE=InnoDB; + + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/TheliaBlocks/Config/update/2.1.9.sql b/domokits/local/modules/TheliaBlocks/Config/update/2.1.9.sql new file mode 100644 index 0000000..c7d54c5 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Config/update/2.1.9.sql @@ -0,0 +1,9 @@ +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +ALTER TABLE `block_group_i18n` + MODIFY `json_content` MEDIUMTEXT; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/domokits/local/modules/TheliaBlocks/Controller/Admin/BlockGroupController.php b/domokits/local/modules/TheliaBlocks/Controller/Admin/BlockGroupController.php new file mode 100644 index 0000000..975c84f --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Controller/Admin/BlockGroupController.php @@ -0,0 +1,269 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Controller\Admin; + +use OpenApi\Annotations as OA; +use OpenApi\Controller\Admin\BaseAdminOpenApiController; +use OpenApi\Model\Api\ModelFactory; +use OpenApi\Service\OpenApiService; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Core\HttpFoundation\JsonResponse; +use Thelia\Core\HttpFoundation\Request; +use TheliaBlocks\Model\BlockGroup; +use TheliaBlocks\Model\BlockGroupI18n; +use TheliaBlocks\Model\BlockGroupI18nQuery; +use TheliaBlocks\Model\BlockGroupQuery; +use TheliaBlocks\Model\ItemBlockGroup; +use TheliaBlocks\Model\ItemBlockGroupQuery; + +/** + * @Route("/open_api/block_group", name="block_group") + */ +class BlockGroupController extends BaseAdminOpenApiController +{ + /** + * @Route("", name="add_block_group", methods="POST") + * + * @OA\Post( + * path="/block_group", + * tags={"block group"}, + * summary="Add a new group of block", + * @OA\RequestBody( + * required=true, + * @OA\JsonContent( + * @OA\Property( + * property="blockGroup", + * ref="#/components/schemas/BlockGroup" + * ), + * @OA\Property( + * property="itemBlockGroup", + * ref="#/components/schemas/ItemBlockGroup" + * ), + * @OA\Property( + * property="locale", + * default="en_US", + * type="string" + * ), + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function createBlockGroup( + Request $request, + ModelFactory $modelFactory + ) { + $data = json_decode($request->getContent(), true); + /** @var \TheliaBlocks\Model\Api\BlockGroup $openApiBlockGroup */ + $openApiBlockGroup = $modelFactory->buildModel('BlockGroup', $data['blockGroup']); + $openApiBlockGroup->validate(self::GROUP_CREATE); + + if (!isset($data['locale'])) { + $data['locale'] = $request->getSession()->getAdminLang()->getLocale(); + } + + /** @var BlockGroup $blockGroup */ + $blockGroup = $openApiBlockGroup->toTheliaModel($data['locale']); + $blockGroup->save(); + + if (isset($data['itemBlockGroup'])) { + $this->assignBlockGroupToItem($modelFactory, $data['itemBlockGroup'], $blockGroup->getId()); + } + + $blockGroup->clearItemBlockGroups(); + + return OpenApiService::jsonResponse( + $modelFactory->buildModel('BlockGroup', $blockGroup) + ); + } + + /** + * @Route("", name="update_block_group", methods="PATCH") + * + * @OA\Patch( + * path="/block_group", + * tags={"block group"}, + * summary="Update a block group", + * @OA\RequestBody( + * required=true, + * @OA\JsonContent( + * @OA\Property( + * property="blockGroup", + * ref="#/components/schemas/BlockGroup" + * ), + * @OA\Property( + * property="itemBlockGroup", + * ref="#/components/schemas/ItemBlockGroup" + * ), + * @OA\Property( + * property="locale", + * type="string", + * default="en_US" + * ), + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function updateBlockGroup( + Request $request, + ModelFactory $modelFactory + ) { + $data = json_decode($request->getContent(), true); + /** @var \TheliaBlocks\Model\Api\BlockGroup $openApiBlockGroup */ + $openApiBlockGroup = $modelFactory->buildModel('BlockGroup', $data['blockGroup']); + $openApiBlockGroup->validate(self::GROUP_UPDATE); + + if (!isset($data['locale'])) { + $data['locale'] = $request->getSession()->getAdminLang()->getLocale(); + } + + /** @var BlockGroup $blockGroup */ + $blockGroup = $openApiBlockGroup->toTheliaModel($data['locale']); + $blockGroup->save(); + + if (isset($data['itemBlockGroup'])) { + $this->assignBlockGroupToItem($modelFactory, $data['itemBlockGroup'], $blockGroup->getId()); + } + $blockGroup->clearItemBlockGroups(); + + return OpenApiService::jsonResponse($modelFactory->buildModel('BlockGroup', $blockGroup)); + } + + /** + * @Route("/{blockGroupId}", name="delete_block_group", methods="DELETE", requirements={"blockGroupId"="\d+"}) + * + * @OA\Delete( + * path="/block_group/{blockGroupId}", + * tags={"block group"}, + * summary="Delete a block group", + * @OA\Parameter( + * name="blockGroupId", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="204", + * description="Success" + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function deleteBlockGroup( + $blockGroupId + ) { + $blockGroup = BlockGroupQuery::create() + ->filterById($blockGroupId) + ->findOne(); + + $blockGroup->delete(); + + return new JsonResponse('Success', 204); + } + + /** + * @Route("/duplicate/{blockGroupId}", name="duplicate_block_group", methods="POST", requirements={"blockGroupId"="\d+"}) + * + * @OA\Post( + * path="/block_group/duplicate/{blockGroupId}", + * tags={"block group"}, + * summary="Duplicate a group of block", + * @OA\Parameter( + * name="blockGroupId", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function duplicateBlockGroup( + $blockGroupId + ) { + $propelBlockGroup = BlockGroupQuery::create()->filterById($blockGroupId)->findOne(); + + if (null === $propelBlockGroup) { + return OpenApiService::jsonResponse(null, 404); + } + + $newBlockGroup = $propelBlockGroup->copy(); + $newBlockGroup->save(); + $newBlockId = $newBlockGroup->getId(); + + $blockGroupI18ns = BlockGroupI18nQuery::create()->filterById($blockGroupId)->find(); + + array_map(function (BlockGroupI18n $blockI18n) use ($newBlockId): void { + $newBlockI18n = $blockI18n->copy(); + $newBlockI18n->setId($newBlockId)->save(); + }, iterator_to_array($blockGroupI18ns)); + + return OpenApiService::jsonResponse($newBlockGroup->getId()); + } + + protected function assignBlockGroupToItem(ModelFactory $modelFactory, $itemBlockGroup, $blockGroupId) + { + $openApiItemBlockGroup = $modelFactory->buildModel('ItemBlockGroup', $itemBlockGroup); + /** @var ItemBlockGroup $itemBlockGroup */ + $itemBlockGroup = $openApiItemBlockGroup->toTheliaModel(); + $itemBlockGroup->setBlockGroupId($blockGroupId); + + // todo allow multiple block for an item + $oldItemBlockGroup = ItemBlockGroupQuery::create() + ->filterByItemType($itemBlockGroup->getItemType()) + ->filterByItemId($itemBlockGroup->getItemId()) + ->findOne(); + if (null !== $oldItemBlockGroup) { + $oldItemBlockGroup->delete(); + } + + $itemBlockGroup->save(); + + return $itemBlockGroup; + } +} diff --git a/domokits/local/modules/TheliaBlocks/Controller/Admin/ConfigurationController.php b/domokits/local/modules/TheliaBlocks/Controller/Admin/ConfigurationController.php new file mode 100644 index 0000000..55a6a79 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Controller/Admin/ConfigurationController.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Controller\Admin; + +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Controller\Admin\BaseAdminController; +use TheliaBlocks\Service\JsonBlockService; +use TheliaBlocks\TheliaBlocks; + +/** + * Class ConfigurationController. + * + * @author Damien Foulhoux + */ + +/** + * @Route("/admin/TheliaBlocks", name="thelia_blocks") + */ +class ConfigurationController extends BaseAdminController +{ + /** @var JsonBlockService */ + private $jsonBlockService; + + public function __construct(JsonBlockService $jsonBlockService) + { + TheliaBlocks::$pageNeedTheliaBlockAssets = true; + $this->jsonBlockService = $jsonBlockService; + } + + /** + * @Route("", name="_list", methods="GET") + */ + public function reactAppListingAction() + { + return $this->render('thelia-blocks-configuration'); + } + + /** + * @Route("/new", name="_new", methods="GET") + */ + public function reactAppNewAction() + { + return $this->render('thelia-blocks-new-configuration'); + } + + /** + * @Route("/{blockGroupId}", name="_edit", methods="GET", requirements={"blockGroupId"="\d+"}) + */ + public function reactAppEditAction($blockGroupId) + { + return $this->render('thelia-blocks-item-configuration', [ + 'groupId' => $blockGroupId, + ]); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Controller/Admin/ItemBlockGroupController.php b/domokits/local/modules/TheliaBlocks/Controller/Admin/ItemBlockGroupController.php new file mode 100644 index 0000000..ae036e3 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Controller/Admin/ItemBlockGroupController.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Controller\Admin; + +use OpenApi\Annotations as OA; +use OpenApi\Controller\Admin\BaseAdminOpenApiController; +use OpenApi\Model\Api\ModelFactory; +use OpenApi\Service\OpenApiService; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Core\HttpFoundation\JsonResponse; +use Thelia\Core\HttpFoundation\Request; +use TheliaBlocks\Model\BlockGroup; +use TheliaBlocks\Model\ItemBlockGroup; +use TheliaBlocks\Model\ItemBlockGroupQuery; + +/** + * @Route("/open_api/item_block_group", name="item_block_group") + */ +class ItemBlockGroupController extends BaseAdminOpenApiController +{ + /** + * @Route("", name="_create", methods="POST") + * + * @OA\Post( + * path="/item_block_group", + * tags={"item block group", "block group"}, + * summary="Add a relation between an item and a block group", + * @OA\RequestBody( + * required=true, + * @OA\JsonContent( + * @OA\Property( + * property="itemBlockGroup", + * ref="#/components/schemas/ItemBlockGroup" + * ) + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function createItemBlockGroup( + Request $request, + ModelFactory $modelFactory + ) { + $data = json_decode($request->getContent(), true); + $openApiItemBlockGroup = $modelFactory->buildModel('ItemBlockGroup', $data['itemBlockGroup']); + /** @var ItemBlockGroup $itemBlockGroup */ + $itemBlockGroup = $openApiItemBlockGroup->toTheliaModel(); + + // todo allow multiple block for an item + $oldItemBlockGroup = ItemBlockGroupQuery::create() + ->filterByItemType($itemBlockGroup->getItemType()) + ->filterByItemId($itemBlockGroup->getItemId()) + ->findOne(); + if (null !== $oldItemBlockGroup) { + $oldItemBlockGroup->delete(); + } + + $itemBlockGroup->save(); + + $theliaBlock = $modelFactory->buildModel('BlockGroup', $itemBlockGroup->getBlockGroup(), $request->get('locale')); + + return OpenApiService::jsonResponse($theliaBlock, 200); + } + + /** + * @Route("/{itemBlockGroupId}", name="_delete", methods="DELETE", requirements={"itemBlockGroupId"="\d+"}) + * + * @OA\Delete( + * path="/item_block_group/{itemBlockGroupId}", + * tags={"item block group", "block group"}, + * summary="Delete a relation between an item and a block group", + * @OA\Parameter( + * name="itemBlockGroupId", + * in="path", + * required=true, + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Response( + * response="204", + * description="Success" + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function deleteItemBlockGroup( + $itemBlockGroupId + ) { + $itemBlockGroup = ItemBlockGroupQuery::create() + ->filterById($itemBlockGroupId) + ->findOne(); + + if (null !== $itemBlockGroup) { + $itemBlockGroup->delete(); + } + + return new JsonResponse('Success', 204); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Controller/Front/BlockGroupController.php b/domokits/local/modules/TheliaBlocks/Controller/Front/BlockGroupController.php new file mode 100644 index 0000000..6bfb79d --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Controller/Front/BlockGroupController.php @@ -0,0 +1,271 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Controller\Front; + +use OpenApi\Annotations as OA; +use OpenApi\Controller\Front\BaseFrontOpenApiController; +use OpenApi\Model\Api\ModelFactory; +use OpenApi\Service\OpenApiService; +use Propel\Runtime\ActiveQuery\Criteria; +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Model\Lang; +use TheliaBlocks\Model\Api\BlockGroup; +use TheliaBlocks\Model\BlockGroupI18nQuery; +use TheliaBlocks\Model\BlockGroupQuery; + +/** + * @Route("/open_api/block_group", name="block_group") + */ +class BlockGroupController extends BaseFrontOpenApiController +{ + /** + * @Route("", name="_get", methods="GET") + * + * @OA\Get( + * path="/block_group", + * tags={"block group"}, + * summary="Get a block group", + * @OA\Parameter( + * name="id", + * in="query", + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Parameter( + * name="slug", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="visible", + * in="query", + * @OA\Schema( + * type="boolean", + * default="true" + * ) + * ), + * @OA\Parameter( + * name="locale", + * in="query", + * description="Current locale by default", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function getBlockGroup( + Request $request, + ModelFactory $modelFactory + ) { + $blockGroupQuery = BlockGroupQuery::create(); + + if (null !== $id = $request->get('id')) { + $blockGroupQuery->filterById($id); + } + + if (null !== $slug = $request->get('slug')) { + $blockGroupQuery->filterBySlug($slug); + } + + if ($request->get('visible') !== null) { + $visible = (bool) json_decode(strtolower($request->get('visible'))); + $blockGroupQuery->filterByVisible($visible); + } + + $propelBlockGroup = $blockGroupQuery->findOne(); + + if (null === $propelBlockGroup) { + return OpenApiService::jsonResponse(null, 404); + } + + /** @var BlockGroup $blockGroup */ + $blockGroup = $modelFactory->buildModel('BlockGroup', $propelBlockGroup, $request->get('locale')); + + if (null !== $blockGroup && empty($blockGroup->getJsonContent())) { + $requestLocale = $request->get('locale'); + + if (!in_array($requestLocale, $blockGroup->getLocales())) { + // Copy default locale JSON content + $defaultLocale = Lang::getDefaultLanguage()->getLocale(); + + $copyLocale = $blockGroup->getLocales()[0]; + + if (in_array($defaultLocale, $blockGroup->getLocales())) { + $copyLocale = $defaultLocale; + } + + if ( + null !== $copyGroup = BlockGroupI18nQuery::create() + ->filterById($blockGroup->getId()) + ->filterByLocale($copyLocale) + ->findOne() + ) { + $blockGroup->setJsonContent($copyGroup->getJsonContent()); + } + } + } + + return OpenApiService::jsonResponse($blockGroup); + } + + /** + * @Route("/list", name="_get_list", methods="GET") + * + * @OA\Get( + * path="/block_group/list", + * tags={"block group"}, + * summary="Get list of block groups", + * @OA\Parameter( + * name="limit", + * in="query", + * @OA\Schema( + * type="integer" + * ) + * ), + * @OA\Parameter( + * name="offset", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="itemType", + * description="the type of an item linked to the block group", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="title", + * in="query", + * @OA\Schema( + * type="string" + * ), + * ), + * @OA\Parameter( + * name="itemId", + * description="the id of an item linked to the block group (itemType has too be defined too)", + * in="query", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="visible", + * in="query", + * @OA\Schema( + * type="boolean", + * default="true" + * ) + * ), + * @OA\Parameter( + * name="locale", + * in="query", + * description="Current locale by default", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Response( + * response="200", + * description="Success", + * @OA\JsonContent(ref="#/components/schemas/BlockGroup") + * ), + * @OA\Response( + * response="400", + * description="Bad request", + * @OA\JsonContent(ref="#/components/schemas/Error") + * ) + * ) + */ + public function getBlockGroups( + Request $request, + ModelFactory $modelFactory + ) { + $blockGroupQuery = BlockGroupQuery::create(); + + if (null !== $limit = $request->get('limit')) { + $blockGroupQuery->limit($limit); + } + + if (null !== $offset = $request->get('offset')) { + $blockGroupQuery->offset($offset); + } + + if (null !== $title = $request->get('title')) { + $blockGroupQuery + ->useBlockGroupI18nQuery() + ->filterByTitle('%' . $title . '%', Criteria::LIKE) + ->endUse(); + } + + if (null !== $itemType = $request->get('itemType')) { + $itemBlockGroupQuery = $blockGroupQuery->useItemBlockGroupQuery() + ->filterByItemType($itemType); + + if (null !== $itemId = $request->get('itemId')) { + $itemBlockGroupQuery->filterByItemId($itemId); + } + + $itemBlockGroupQuery->endUse(); + } + + if ($request->get('visible') !== null) { + $visible = (bool) json_decode(strtolower($request->get('visible'))); + $blockGroupQuery->filterByVisible($visible); + } + + $order = $request->get('order'); + + switch ($order) { + case 'id': + $blockGroupQuery->orderById(Criteria::ASC); + break; + case 'id_reverse': + $blockGroupQuery->orderById(Criteria::DESC); + break; + default: + $blockGroupQuery->orderById(Criteria::DESC); + } + + $propelTheliaBlocks = $blockGroupQuery->find(); + + if (empty($propelTheliaBlocks)) { + return OpenApiService::jsonResponse([], 404); + } + + $theliaBlocks = array_map( + fn ($propelBlockGroup) => $modelFactory->buildModel('BlockGroup', $propelBlockGroup, $request->get('locale')), + iterator_to_array($propelTheliaBlocks) + ); + + return OpenApiService::jsonResponse($theliaBlocks); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Controller/Front/PreviewGroupController.php b/domokits/local/modules/TheliaBlocks/Controller/Front/PreviewGroupController.php new file mode 100644 index 0000000..b7220bf --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Controller/Front/PreviewGroupController.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Controller\Front; + +/* + * This file is part of the Thelia package. + * http://www.thelia.net + * + * (c) OpenStudio + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\Routing\Annotation\Route; +use Thelia\Controller\Front\BaseFrontController; +use Thelia\Core\HttpFoundation\Request; + +/** + * @Route("/TheliaBlocks", name="thelia_blocks_front") + */ +class PreviewGroupController extends BaseFrontController +{ + /** + * @Route("/preview", name="_preview", methods="POST") + */ + public function previewBlockGroup(Request $request) + { + return $this->render('thelia-blocks-preview', [ + 'json' => $request->get('json'), + ]); + } +} diff --git a/domokits/local/modules/TheliaBlocks/EventListeners/ShortCodeListener.php b/domokits/local/modules/TheliaBlocks/EventListeners/ShortCodeListener.php new file mode 100644 index 0000000..feac7c7 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/EventListeners/ShortCodeListener.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\EventListeners; + +use ShortCode\Event\ShortCodeEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Template\ParserInterface; +use Thelia\Core\Template\TheliaTemplateHelper; +use Thelia\Log\Tlog; +use Thelia\Model\CategoryQuery; +use Thelia\Model\ContentQuery; +use Thelia\Model\FolderQuery; +use Thelia\Model\ProductQuery; +use TheliaBlocks\Model\BlockGroupQuery; +use TheliaBlocks\TheliaBlocks; + +class ShortCodeListener implements EventSubscriberInterface +{ + /** @var ParserInterface */ + protected $parser; + + /** @var Request */ + protected $request; + + /** @var TheliaTemplateHelper */ + private $templateHelper; + + public function __construct(RequestStack $requestStack, ParserInterface $parser, TheliaTemplateHelper $templateHelper) + { + $this->request = $requestStack->getCurrentRequest(); + $this->parser = $parser; + $this->templateHelper = $templateHelper; + } + + public static function getSubscribedEvents() + { + return [ + TheliaBlocks::BLOCK_GROUP_SHORT_CODE => [['blockGroupShortCode']], + TheliaBlocks::ADMIN_CSS_SHORTCODE => [['addBlockGroupCss']], + TheliaBlocks::ADMIN_JS_SHORTCODE => [['addBlockGroupJs']], + TheliaBlocks::PRODUCT_LINK => [['renderProductLink']], + TheliaBlocks::CATEGORY_LINK => [['renderCategoryLink']], + TheliaBlocks::FOLDER_LINK => [['renderFolderLink']], + TheliaBlocks::CONTENT_LINK => [['renderContentLink']], + ]; + } + + public function addBlockGroupCss(ShortCodeEvent $event): void + { + if (TheliaBlocks::$pageNeedTheliaBlockAssets) { + $event->setResult( + $this->parser->render('thelia-blocks-css.html') + ); + } + } + + public function addBlockGroupJs(ShortCodeEvent $event): void + { + if (TheliaBlocks::$pageNeedTheliaBlockAssets) { + $event->setResult( + $this->parser->render('thelia-blocks-js.html') + ); + } + } + + public function blockGroupShortCode(ShortCodeEvent $event): void + { + $attributes = $event->getAttributes(); + + if (!isset($attributes['slug'])) { + return; + } + + $blockGroupSlug = $attributes['slug']; + $blockGroup = BlockGroupQuery::create() + ->filterBySlug($blockGroupSlug) + ->findOne(); + + if (null === $blockGroup) { + Tlog::getInstance()->warning("Block group with slug $blockGroupSlug not found"); + + return; + } + + $lang = $this->request->getSession()->getLang(); + $blockGroup->setLocale($lang->getLocale()); + + $blocks = json_decode($blockGroup->getJsonContent(), true); + + if (!\is_array($blocks)) { + return; + } + + // Todo return the raw value of block group + $raw = isset($attributes['raw']) && (bool) json_decode(strtolower($attributes['raw'])) === true; + + if ($raw) { + $event->setResult($this->parser->render('blocks/rawBlockGroup.html', compact('blocks'))); + + return; + } + + $blockRenders = []; + foreach ($blocks as $block) { + $blockRenders[] = $this->parser->render('blocks'.DS.$block['type']['id'].'.html', $block); + } + + $event->setResult(implode(' ', $blockRenders)); + } + + public function renderProductLink(ShortCodeEvent $event): void + { + $event->setResult($this->generateLink(ProductQuery::create(), $event)); + } + + public function renderCategoryLink(ShortCodeEvent $event): void + { + $event->setResult($this->generateLink(CategoryQuery::create(), $event)); + } + + public function renderContentLink(ShortCodeEvent $event): void + { + $event->setResult($this->generateLink(ContentQuery::create(), $event)); + } + + public function renderFolderLink(ShortCodeEvent $event): void + { + $event->setResult($this->generateLink(FolderQuery::create(), $event)); + } + + public function generateLink(CategoryQuery|ProductQuery|ContentQuery|FolderQuery $query, ShortCodeEvent $event) + { + $attributes = $event->getAttributes(); + $id = $attributes['id']; + $locale = $this->request->getSession()->getLang()->getLocale(); + + $item = $query + ->filterById($id) + ->findOne(); + + $url = $item->getUrl($locale); + $title = $attributes['title'] ?? $item->getTitle(); + $link = $this->renderLinkTemplate($url, $title); + + return $link; + } + + private function renderLinkTemplate(string $url, string $title) + { + return ''.$title.''; + } +} diff --git a/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksBackHook.php b/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksBackHook.php new file mode 100644 index 0000000..664b57c --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksBackHook.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Hook; + +use Thelia\Core\Event\Hook\HookRenderBlockEvent; +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Tools\URL; +use TheliaBlocks\Model\BlockGroupQuery; +use TheliaBlocks\TheliaBlocks; + +class TheliaBlocksBackHook extends BaseHook +{ + public function onProductTab(HookRenderBlockEvent $event): void + { + $this->addTheliaBlocksConfigurationTab($event, 'product'); + } + + public function onCategoryTab(HookRenderBlockEvent $event): void + { + $this->addTheliaBlocksConfigurationTab($event, 'category'); + } + + public function onBrandTab(HookRenderBlockEvent $event): void + { + $this->addTheliaBlocksConfigurationTab($event, 'brand', $event->getArgument('brand_id')); + } + + public function onContentTab(HookRenderBlockEvent $event): void + { + $this->addTheliaBlocksConfigurationTab($event, 'content'); + } + + public function onFolderTab(HookRenderBlockEvent $event): void + { + $this->addTheliaBlocksConfigurationTab($event, 'folder'); + } + + public function onBlockItemConfiguration(HookRenderEvent $event): void + { + $itemId = $event->getArgument('itemId'); + $itemType = $event->getArgument('itemType'); + $groupId = $event->getArgument('groupId'); + + $event->add($this->getConfigurationRender($itemType, $itemId, $groupId)); + } + + public function onMainCss(HookRenderEvent $event): void + { + $event->add('[block_group_admin_css]'); + } + + public function onMainJs(HookRenderEvent $event): void + { + $event->add('[block_group_admin_js]'); + } + + protected function addTheliaBlocksConfigurationTab(HookRenderBlockEvent $event, $itemType, $itemId = null): void + { + if (null === $itemId) { + $itemId = $event->getArgument('id'); + } + $groupId = $event->getArgument('groupId'); + + $event->add( + [ + 'id' => 'theliablocks_item_details', + 'title' => $this->trans('Blocs de contenus', [], TheliaBlocks::DOMAIN_NAME), + 'content' => $this->getConfigurationRender($itemType, $itemId, $groupId), + ] + ); + } + + private function getConfigurationRender($itemType, $itemId, $groupId = null) + { + TheliaBlocks::$pageNeedTheliaBlockAssets = true; + + $search = BlockGroupQuery::create(); + $search->useItemBlockGroupQuery() + ->filterByItemType($itemType) + ->filterByItemId($itemId) + ->endUse(); + + if ($groupId) { + $search->filterById($groupId); + } + + $group = $search->findOne(); + + return $this->render( + 'item-configuration.html', + [ + 'itemId' => $itemId, + 'itemType' => $itemType, + 'groupId' => $group?->getId(), + ] + ); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksMenuHook.php b/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksMenuHook.php new file mode 100644 index 0000000..9bbcdb8 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Hook/TheliaBlocksMenuHook.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +class TheliaBlocksMenuHook extends BaseHook +{ + public function onMainInTopMenuItems(HookRenderEvent $event): void + { + $event->add( + $this->render('hook-in-top-menu-item.html', $event->getTemplateVars()) + ); + } +} diff --git a/domokits/local/modules/TheliaBlocks/I18n/en_US.php b/domokits/local/modules/TheliaBlocks/I18n/en_US.php new file mode 100755 index 0000000..d391ee9 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + // 'an english string' => 'The displayed english string', +]; diff --git a/domokits/local/modules/TheliaBlocks/I18n/fr_FR.php b/domokits/local/modules/TheliaBlocks/I18n/fr_FR.php new file mode 100755 index 0000000..ff066ca --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + // 'an english string' => 'La traduction française de la chaine', +]; diff --git a/domokits/local/modules/TheliaBlocks/Loop/BlockGroup.php b/domokits/local/modules/TheliaBlocks/Loop/BlockGroup.php new file mode 100644 index 0000000..7dfdc93 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Loop/BlockGroup.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Loop; + +use Propel\Runtime\ActiveQuery\Criteria; +use Thelia\Core\Template\Element\BaseI18nLoop; +use Thelia\Core\Template\Element\LoopResult; +use Thelia\Core\Template\Element\LoopResultRow; +use Thelia\Core\Template\Element\PropelSearchLoopInterface; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Type\BooleanOrBothType; +use TheliaBlocks\Model\BlockGroupQuery; + +/** + * Class BlockGroup. + * + * @method int[] getId() + * @method string[] getSlug() + * @method string getItemType() + * @method int getItemId() + * @method bool|string getVisible() + */ +class BlockGroup extends BaseI18nLoop implements PropelSearchLoopInterface +{ + /** + * {@inheritdoc} + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntListTypeArgument('id'), + Argument::createAlphaNumStringListTypeArgument('slug'), + Argument::createAlphaNumStringTypeArgument('item_type'), + Argument::createIntTypeArgument('item_id'), + Argument::createBooleanOrBothTypeArgument('visible', 1) + ); + } + + /** + * this method returns a Propel ModelCriteria. + * + * @return \Propel\Runtime\ActiveQuery\ModelCriteria + */ + public function buildModelCriteria() + { + $search = BlockGroupQuery::create(); + + $this->configureI18nProcessing($search, ['TITLE', 'JSON_CONTENT']); + + $id = $this->getId(); + + if (null !== $id) { + $search->filterById($id, Criteria::IN); + } + + $slug = $this->getSlug(); + + if (null !== $slug) { + $search->filterBySlug($slug, Criteria::IN); + } + + $itemType = $this->getItemType(); + $itemId = $this->getItemId(); + + if (null !== $itemType && null !== $itemId) { + $search->useItemBlockGroupQuery() + ->filterByItemType($itemType) + ->filterByItemId($itemId) + ->endUse(); + } + + $visible = $this->getVisible(); + + if ($visible !== BooleanOrBothType::ANY) { + $search->filterByVisible($visible ? 1 : 0); + } + + return $search; + } + + public function parseResults(LoopResult $loopResult) + { + /** @var \TheliaBlocks\Model\BlockGroup $entry */ + foreach ($loopResult->getResultDataCollection() as $entry) { + + if (!$entry->getVirtualColumn('i18n_JSON_CONTENT')) { + continue; + } + + $htmlRender = $this->container->get('theliablocks.json.block')->renderJsonBlocks($entry->getVirtualColumn('i18n_JSON_CONTENT')); + + $content = json_decode($entry->getVirtualColumn('i18n_JSON_CONTENT'), true); + + $row = new LoopResultRow($entry); + $row + ->set('ID', $entry->getId()) + ->set('SLUG', $entry->getSlug()) + ->set('VISIBLE', $entry->getVisible()) + ->set('TITLE', $entry->getVirtualColumn('i18n_TITLE')) + ->set('CONTENT', $content) + ->set('RENDER', $htmlRender) + ; + + $this->addOutputFields($row, $entry); + + $loopResult->addRow($row); + } + + return $loopResult; + } +} diff --git a/domokits/local/modules/TheliaBlocks/Model/Api/BlockGroup.php b/domokits/local/modules/TheliaBlocks/Model/Api/BlockGroup.php new file mode 100755 index 0000000..5ab495e --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/Api/BlockGroup.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model\Api; + +use OpenApi\Annotations as OA; +use OpenApi\Constraint; +use OpenApi\Exception\OpenApiException; +use OpenApi\Model\Api\BaseApiModel; +use OpenApi\Model\Api\Error; +use OpenApi\OpenApi; +use Propel\Runtime\ActiveQuery\Criteria; +use Thelia\Core\Translation\Translator; +use Thelia\Model\LangQuery; +use TheliaBlocks\Model\BlockGroupI18nQuery; +use TheliaBlocks\Model\BlockGroupQuery; + +/** + * Class BlockGroup. + * + * @OA\Schema( + * schema="BlockGroup", + * title="BlockGroup", + * ) + */ +class BlockGroup extends BaseApiModel +{ + /** + * @var int + * @OA\Property( + * type="integer", + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $id; + + /** + * @var bool + * @OA\Property( + * type="boolean", + * ) + */ + protected $visible; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $title; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $slug = null; + + /** + * @var array + * @OA\Property( + * readOnly=true, + * type="array", + * @OA\Items( + * ref="#/components/schemas/ItemBlockGroup" + * ) + * ) + */ + protected $itemBlockGroups = []; + + /** + * @var string + * @OA\Property( + * description="All blocks json encoded", + * type="string" + * ) + */ + protected $jsonContent; + + /** + * @var array + * @OA\Property( + * type="array", + * @OA\Items() + * ) + */ + protected $locales; + + /** + * @param $groups + * + * @throws OpenApiException + * + * @return BlockGroup + */ + public function validate($groups, $recursively = true) + { + parent::validate($groups, $recursively); + + $violations = []; + + if (null !== $this->getSlug()) { + $sameSlugQuery = BlockGroupQuery::create() + ->filterBySlug($this->getSlug()); + + if (null !== $this->getId()) { + $sameSlugQuery->filterById($this->getId(), Criteria::NOT_EQUAL); + } + + if (null !== $sameSlugQuery->findOne()) { + $violations[] = $this->modelFactory->buildModel( + 'SchemaViolation', + [ + 'key' => 'slug', + 'error' => Translator::getInstance()->trans('Slug must be unique', [], OpenApi::DOMAIN_NAME), + ] + ); + } + } + + if (!empty($violations)) { + /** @var Error $error */ + $error = $this->modelFactory->buildModel( + 'Error', + ['title' => Translator::getInstance()->trans('Invalid data', [], OpenApi::DOMAIN_NAME)] + ); + + $error->setSchemaViolations($violations); + + throw new OpenApiException($error); + } + + return $this; + } + + /** + * @return int + */ + public function getId(): ?int + { + return $this->id; + } + + public function setId(int $id): self + { + $this->id = $id; + + return $this; + } + + public function isVisible(): bool + { + return $this->visible; + } + + public function setVisible(bool $visible): self + { + $this->visible = $visible; + + return $this; + } + + /** + * @return string + */ + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(?string $title): self + { + $this->title = $title; + + return $this; + } + + /** + * @return string + */ + public function getSlug(): ?string + { + return $this->slug; + } + + /** + * @param string $slug + */ + public function setSlug(?string $slug): self + { + $this->slug = $slug; + + return $this; + } + + /** + * @return string + */ + public function getJsonContent(): ?string + { + return $this->jsonContent; + } + + public function setJsonContent(?string $jsonContent): self + { + $this->jsonContent = $jsonContent; + + return $this; + } + + public function getItemBlockGroups(): array + { + return $this->itemBlockGroups; + } + + public function setItemBlockGroups(array $itemBlockGroups): self + { + $this->itemBlockGroups = $itemBlockGroups; + + return $this; + } + + public function getLocales(): array|null + { + return $this->locales; + } + + public function setLocales(array $locales): self + { + $this->locales = $locales; + + return $this; + } + + protected function getTheliaModel($propelModelName = null) + { + return parent::getTheliaModel(\TheliaBlocks\Model\BlockGroup::class); + } + + public function createFromTheliaModel($theliaModel, $locale = null): void + { + parent::createFromTheliaModel($theliaModel, $locale); + + $locales = array_map( + function ($item) { + return LangQuery::create()->findOneByLocale($item['Locale'])->getLocale(); + }, + BlockGroupI18nQuery::create() + ->filterById($this->getId()) + ->find() + ->toArray() + ); + + $this->setLocales($locales); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Model/Api/ItemBlockGroup.php b/domokits/local/modules/TheliaBlocks/Model/Api/ItemBlockGroup.php new file mode 100644 index 0000000..4a7df18 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/Api/ItemBlockGroup.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model\Api; + +use OpenApi\Annotations as OA; +use OpenApi\Constraint; +use OpenApi\Model\Api\BaseApiModel; +use Thelia\Tools\URL; +use TheliaMain\PropelResolver; + +/** + * Class ItemBlockGroup. + * + * @OA\Schema( + * schema="ItemBlockGroup", + * title="ItemBlockGroup", + * ) + */ +class ItemBlockGroup extends BaseApiModel +{ + /** + * @var int + * @OA\Property( + * type="integer", + * ) + */ + protected $id; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $itemType; + + /** + * @var int + * @OA\Property( + * type="integer", + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $itemId; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $itemTitle; + + /** + * @var string + * @OA\Property( + * type="string", + * ) + */ + protected $itemUrl; + + /** + * @var int + * @OA\Property( + * type="integer", + * ) + * @Constraint\NotBlank(groups={"read"}) + */ + protected $blockGroupId; + + /** + * @return int + */ + public function getId(): ?int + { + return $this->id; + } + + public function setId(int $id): self + { + $this->id = $id; + + return $this; + } + + public function getItemType(): string + { + return $this->itemType; + } + + public function setItemType(string $itemType): self + { + $this->itemType = $itemType; + + return $this; + } + + public function getItemId(): int + { + return $this->itemId; + } + + public function setItemId(int $itemId): self + { + $this->itemId = $itemId; + + return $this; + } + + /** + * @return int + */ + public function getBlockGroupId(): ?int + { + return $this->blockGroupId; + } + + public function setBlockGroupId(int $blockGroupId): self + { + $this->blockGroupId = $blockGroupId; + + return $this; + } + + public function getItemTitle(): string + { + return $this->itemTitle; + } + + public function setItemTitle(string $itemTitle): self + { + $this->itemTitle = $itemTitle; + + return $this; + } + + public function getItemUrl(): string + { + return $this->itemUrl; + } + + public function setItemUrl(string $itemUrl): self + { + $this->itemUrl = $itemUrl; + + return $this; + } + + protected function getTheliaModel($propelModelName = null) + { + return parent::getTheliaModel(\TheliaBlocks\Model\ItemBlockGroup::class); + } + + public function createFromTheliaModel($theliaModel, $locale = null) + { + parent::createFromTheliaModel($theliaModel, $locale); + + if (!$this->getItemType()) { + return $this; + } + + try { + $tableMapClass = PropelResolver::getTableMapByTableName($this->getItemType()); + + if (!$tableMapClass) { + return $this; + } + + $tableMap = new $tableMapClass(); + $queryClass = $tableMap->getClassName().'Query'; + + if (!class_exists($queryClass)) { + return $this; + } + + $query = $queryClass::create(); + + if (null === $query) { + return $this; + } + + $item = $query->findOneById($this->getItemId()); + + if ($item === null) { + return $this; + } + + if (method_exists($item, 'getTitle')) { + $this->setItemTitle($item->getTitle()); + } + + switch ($this->getItemType()) { + case 'product': + $this->setItemUrl(URL::getInstance()->absoluteUrl("/admin/products/update?product_id={$this->getItemId()}")); + break; + case 'category': + $this->setItemUrl(URL::getInstance()->absoluteUrl("/admin/categories/update?category_id={$this->getItemId()}")); + break; + case 'content': + $this->setItemUrl(URL::getInstance()->absoluteUrl("/admin/content/update/{$this->getItemId()}")); + break; + case 'brand': + $this->setItemUrl(URL::getInstance()->absoluteUrl("/admin/brands/update/{$this->getItemId()}")); + break; + case 'folder': + $this->setItemUrl(URL::getInstance()->absoluteUrl("/admin/folders/update/{$this->getItemId()}")); + break; + default: + if (method_exists($item, 'getUrl')) { + $this->setItemUrl($item->getUrl()); + } + break; + } + } catch (\Throwable $th) { + // throw $th; + } + } +} diff --git a/domokits/local/modules/TheliaBlocks/Model/BlockGroup.php b/domokits/local/modules/TheliaBlocks/Model/BlockGroup.php new file mode 100644 index 0000000..76aea66 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/BlockGroup.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use Propel\Runtime\ActiveQuery\Criteria; +use Propel\Runtime\Connection\ConnectionInterface; +use TheliaBlocks\Model\Base\BlockGroup as BaseBlockGroup; + +/** + * Skeleton subclass for representing a row from the 'block_group' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class BlockGroup extends BaseBlockGroup +{ + public const SLUG_MAX_LENGTH = 45; + + /** + * Code to be run before inserting to database. + * + * @param ConnectionInterface $con + * + * @return bool + */ + public function preSave(ConnectionInterface $con = null) + { + if (null === $this->getSlug()) { + $this->setSlug($this->slugify($this->getTitle())); + } + + $this->setSlug($this->findUnusedSlug(substr($this->getSlug(), 0, self::SLUG_MAX_LENGTH))); + + return parent::preInsert($con); + } + + protected function findUnusedSlug($baseSlug, $iteration = 0) + { + $iteratedSlug = $baseSlug; + if ($iteration !== 0) { + $iterationSuffix = '_'.$iteration; + $iteratedSlug = substr($baseSlug, 0, self::SLUG_MAX_LENGTH - mb_strlen($iterationSuffix)).$iterationSuffix; + } + + $alreadyExistForAnotherGroupQuery = BlockGroupQuery::create()->filterBySlug($iteratedSlug); + if (null !== $this->getId()) { + $alreadyExistForAnotherGroupQuery->filterById($this->getId(), Criteria::NOT_EQUAL); + } + + if (null === $alreadyExistForAnotherGroupQuery->findOne()) { + return $iteratedSlug; + } + + ++$iteration; + + return $this->findUnusedSlug($baseSlug, $iteration); + } + + protected function slugify($text) + { + $table = [ + 'Š' => 'S', 'š' => 's', 'Đ' => 'Dj', 'đ' => 'dj', 'Ž' => 'Z', 'ž' => 'z', 'Č' => 'C', 'č' => 'c', 'Ć' => 'C', 'ć' => 'c', + 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'A', 'Ç' => 'C', 'È' => 'E', 'É' => 'E', + 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', + 'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ý' => 'Y', 'Þ' => 'B', 'ß' => 'Ss', + 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'a', 'ç' => 'c', 'è' => 'e', 'é' => 'e', + 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'o', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', + 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ý' => 'y', 'ý' => 'y', 'þ' => 'b', + 'ÿ' => 'y', 'Ŕ' => 'R', 'ŕ' => 'r', '/' => '_', ' ' => '_', + ]; + + // -- Remove duplicated spaces + $text = preg_replace(['/\s{2,}/', '/[\t\n]/'], '_', $text); + + $text = preg_replace('~[^\pL\d]+~u', '_', $text); + // -- Returns the slug + return trim(strtolower(strtr($text, $table)), '_'); + } +} diff --git a/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18n.php b/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18n.php new file mode 100644 index 0000000..fc54129 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18n.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use TheliaBlocks\Model\Base\BlockGroupI18n as BaseBlockGroupI18n; + +/** + * Skeleton subclass for representing a row from the 'block_group_i18n' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class BlockGroupI18n extends BaseBlockGroupI18n +{ +} diff --git a/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18nQuery.php b/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18nQuery.php new file mode 100644 index 0000000..a5fafe8 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/BlockGroupI18nQuery.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use TheliaBlocks\Model\Base\BlockGroupI18nQuery as BaseBlockGroupI18nQuery; + +/** + * Skeleton subclass for performing query and update operations on the 'block_group_i18n' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class BlockGroupI18nQuery extends BaseBlockGroupI18nQuery +{ +} diff --git a/domokits/local/modules/TheliaBlocks/Model/BlockGroupQuery.php b/domokits/local/modules/TheliaBlocks/Model/BlockGroupQuery.php new file mode 100644 index 0000000..24fa313 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/BlockGroupQuery.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use TheliaBlocks\Model\Base\BlockGroupQuery as BaseBlockGroupQuery; + +/** + * Skeleton subclass for performing query and update operations on the 'block_group' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class BlockGroupQuery extends BaseBlockGroupQuery +{ +} diff --git a/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroup.php b/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroup.php new file mode 100644 index 0000000..5124d09 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroup.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use TheliaBlocks\Model\Base\ItemBlockGroup as BaseItemBlockGroup; + +/** + * Skeleton subclass for representing a row from the 'item_block_group' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class ItemBlockGroup extends BaseItemBlockGroup +{ +} diff --git a/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroupQuery.php b/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroupQuery.php new file mode 100644 index 0000000..c98a8d8 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Model/ItemBlockGroupQuery.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace TheliaBlocks\Model; + +use TheliaBlocks\Model\Base\ItemBlockGroupQuery as BaseItemBlockGroupQuery; + +/** + * Skeleton subclass for performing query and update operations on the 'item_block_group' table. + * + * You should add additional methods to this class to meet the + * application requirements. This class will only be generated as + * long as it does not already exist in the output directory. + */ +class ItemBlockGroupQuery extends BaseItemBlockGroupQuery +{ +} diff --git a/domokits/local/modules/TheliaBlocks/Readme.md b/domokits/local/modules/TheliaBlocks/Readme.md new file mode 100755 index 0000000..903d8e0 --- /dev/null +++ b/domokits/local/modules/TheliaBlocks/Readme.md @@ -0,0 +1,306 @@ +# Création d'un plugin pour Thelia Blocks + +## Exemple : Création d'un plugin de citation + +### Introduction + +Ce plugin devra pouvoir afficher un champ pour indiquer le nom de l'auteur, et un second champ permettant d'insérer la citation en question. + +Dans cet exemple, nous allons créer le plugin depuis un module Thelia. +Si vous ne connaissez pas encore le fonctionnement des modules Thelia, nous vous conseillons vivement d'aller lire la [documentation officielle sur les modules Thelia](https://doc.thelia.net/en/documentation/modules/index.html). + +### Architecture du module + +Lors de cet exemple, nous utiliserons une architecture bien spécifique. +Vous êtes évidemment libre de structurer votre module comme vous le souhaitez. + +``` +. +├── ... +├── local/modules/ModuleCitation +│ ├── Config/ +│ │ ├── module.xml +│ │ └── config.xml +│ ├── Hook/ +│ │ └── BackHook.php +│ └── templates/ +│ │ ├── frontOffice/default/blocks/ +│ │ │ ├── blockCitation.html +│ │ │ └── ... +│ │ └── backOffice/default/ +│ │ │ ├── src/ +│ │ │ │ └── Citation.jsx +│ │ │ ├── tsup.config.js +│ │ │ └── index.js +│ ├── package.json +│ └── ModuleCitation.php +└── ... +``` + +### Installation des dépendances : + +```bash +npm install react tsup @openstudio/blocks-editor +``` + +### 1 - Création du composant + +Commençons par créer un fichier `Citation.jsx` et par définir les données initiales du plugin : + +```js +// ./templates/backOffice/default/src/Citation.jsx + +const initialData = { + author: "", + quote: "", +}; +``` + +Ensuite, nous allons pouvoir écrire le composant React permettant de visualiser le plugin dans l'éditeur de Thelia Blocks. + +:warning: Attention : un plugin Thelia Blocks prends toujours deux `props` : + +| Prop | Type | Description | +| :--------- | :--------- | :--------------------------------------------------------- | +| `data` | `any` | Objet contenant les données du plugin | +| `onUpdate` | `Function` | Fonction permettant de mettre à jour les données du plugin | + +Exemple : + +```jsx +// ./templates/backOffice/default/src/Citation.jsx + +const BlockQuoteComponent = ({ data, onUpdate }) => { + return ( +
+
+ + onUpdate({ ...data, author: e.target.value })} + /> +
+
+ + '; + break; + case 'view': + if (isset($_GET['type'])) { + $_SESSION['RF']['view_type'] = $_GET['type']; + } else { + response(trans('view type number missing').AddErrorLocation())->send(); + exit; + } + break; + case 'filter': + if (isset($_GET['type'])) { + if (isset($remember_text_filter) && $remember_text_filter) { + $_SESSION['RF']['filter'] = $_GET['type']; + } + } else { + response(trans('view type number missing').AddErrorLocation())->send(); + exit; + } + break; + case 'sort': + if (isset($_GET['sort_by'])) { + $_SESSION['RF']['sort_by'] = $_GET['sort_by']; + } + + if (isset($_GET['descending'])) { + $_SESSION['RF']['descending'] = $_GET['descending']; + } + break; + case 'image_size': // not used + $pos = strpos($_POST['path'], $upload_dir); + if ($pos !== false) { + $info = getimagesize(substr_replace($_POST['path'], $current_path, $pos, strlen($upload_dir))); + response($info)->send(); + exit; + } + break; + case 'save_img': + $info = pathinfo($_POST['name']); + + if ( + strpos($_POST['path'], '/') === 0 + || strpos($_POST['path'], '../') !== false + || strpos($_POST['path'], '..\\') !== false + || strpos($_POST['path'], './') === 0 + || (strpos($_POST['url'], 'http://s3.amazonaws.com/feather') !== 0 && strpos($_POST['url'], 'https://s3.amazonaws.com/feather') !== 0) + || $_POST['name'] != fix_filename($_POST['name'], $config) + || !in_array(strtolower($info['extension']), ['jpg', 'jpeg', 'png', 'svg']) + ) { + response(trans('wrong data').AddErrorLocation())->send(); + exit; + } + $image_data = get_file_by_url($_POST['url']); + if ($image_data === false) { + response(trans('Aviary_No_Save').AddErrorLocation())->send(); + exit; + } + + if (!checkresultingsize(strlen($image_data))) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + if ($ftp) { + $temp = tempnam('/tmp', 'RF'); + unlink($temp); + $temp .= '.'.substr(strrchr($_POST['url'], '.'), 1); + file_put_contents($temp, $image_data); + + $ftp->put($ftp_base_folder.$upload_dir.$_POST['path'].$_POST['name'], $temp, \FTP_BINARY); + + create_img($temp, $temp, 122, 91); + $ftp->put($ftp_base_folder.$ftp_thumbs_dir.$_POST['path'].$_POST['name'], $temp, \FTP_BINARY); + + unlink($temp); + } else { + file_put_contents($current_path.$_POST['path'].$_POST['name'], $image_data); + create_img($current_path.$_POST['path'].$_POST['name'], $thumbs_base_path.$_POST['path'].$_POST['name'], 122, 91); + // TODO something with this function cause its blowing my mind + new_thumbnails_creation( + $current_path.$_POST['path'], + $current_path.$_POST['path'].$_POST['name'], + $_POST['name'], + $current_path, + $relative_image_creation, + $relative_path_from_current_pos, + $relative_image_creation_name_to_prepend, + $relative_image_creation_name_to_append, + $relative_image_creation_width, + $relative_image_creation_height, + $relative_image_creation_option, + $fixed_image_creation, + $fixed_path_from_filemanager, + $fixed_image_creation_name_to_prepend, + $fixed_image_creation_to_append, + $fixed_image_creation_width, + $fixed_image_creation_height, + $fixed_image_creation_option + ); + } + break; + case 'extract': + if (strpos($_POST['path'], '/') === 0 + || strpos($_POST['path'], '../') !== false + || strpos($_POST['path'], '..\\') !== false + || strpos($_POST['path'], './') === 0) { + response(trans('wrong path'.AddErrorLocation()))->send(); + exit; + } + + if ($ftp) { + $path = $ftp_base_url.$upload_dir.$_POST['path']; + $base_folder = $ftp_base_url.$upload_dir.fix_dirname($_POST['path']).'/'; + } else { + $path = $current_path.$_POST['path']; + $base_folder = $current_path.fix_dirname($_POST['path']).'/'; + } + + $info = pathinfo($path); + + if ($ftp) { + $tempDir = tempdir(); + $temp = tempnam($tempDir, 'RF'); + unlink($temp); + $temp .= '.'.$info['extension']; + $handle = fopen($temp, 'w'); + fwrite($handle, file_get_contents($path)); + fclose($handle); + $path = $temp; + $base_folder = $tempDir.'/'; + } + + $info = pathinfo($path); + + switch ($info['extension']) { + case 'zip': + $zip = new ZipArchive(); + if ($zip->open($path) === true) { + // get total size + $sizeTotalFinal = 0; + for ($i = 0; $i < $zip->numFiles; ++$i) { + $aStat = $zip->statIndex($i); + $sizeTotalFinal += $aStat['size']; + } + if (!checkresultingsize($sizeTotalFinal)) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + + // make all the folders + for ($i = 0; $i < $zip->numFiles; ++$i) { + $OnlyFileName = $zip->getNameIndex($i); + $FullFileName = $zip->statIndex($i); + if (substr($FullFileName['name'], -1, 1) == '/') { + create_folder($base_folder.$FullFileName['name']); + } + } + // unzip into the folders + for ($i = 0; $i < $zip->numFiles; ++$i) { + $OnlyFileName = $zip->getNameIndex($i); + $FullFileName = $zip->statIndex($i); + + if (!(substr($FullFileName['name'], -1, 1) == '/')) { + $fileinfo = pathinfo($OnlyFileName); + if (in_array(strtolower($fileinfo['extension']), $ext)) { + copy('zip://'.$path.'#'.$OnlyFileName, $base_folder.$FullFileName['name']); + } + } + } + $zip->close(); + } else { + response(trans('Zip_No_Extract').AddErrorLocation())->send(); + exit; + } + + break; + case 'gz': + // No resulting size pre-control available + $p = new PharData($path); + $p->decompress(); // creates files.tar + + break; + case 'tar': + // No resulting size pre-control available + // unarchive from the tar + $phar = new PharData($path); + $phar->decompressFiles(); + $files = []; + check_files_extensions_on_phar($phar, $files, '', $ext); + $phar->extractTo($base_folder, $files, true); + + break; + default: + response(trans('Zip_Invalid').AddErrorLocation())->send(); + exit; + } + + if ($ftp) { + unlink($path); + $ftp->putAll($base_folder, '/'.$ftp_base_folder.$upload_dir.fix_dirname($_POST['path']), \FTP_BINARY); + deleteDir($base_folder); + } + + break; + case 'media_preview': + if ($ftp) { + $preview_file = $ftp_base_url.$upload_dir.$_GET['file']; + } else { + $preview_file = $current_path.$_GET['file']; + } + $info = pathinfo($preview_file); + ob_start(); + ?> + + + + + + + + + + send(); + exit; + + break; + case 'copy_cut': + if ($_POST['sub_action'] != 'copy' && $_POST['sub_action'] != 'cut') { + response(trans('wrong sub-action').AddErrorLocation())->send(); + exit; + } + + if (strpos($_POST['path'], '../') !== false + || strpos($_POST['path'], './') !== false + || strpos($_POST['path'], '..\\') !== false + || strpos($_POST['path'], '.\\') !== false) { + response(trans('wrong path'.AddErrorLocation()))->send(); + exit; + } + + if (trim($_POST['path']) == '') { + response(trans('no path').AddErrorLocation())->send(); + exit; + } + + $msg_sub_action = ($_POST['sub_action'] == 'copy' ? trans('Copy') : trans('Cut')); + $path = $current_path.$_POST['path']; + + if (is_dir($path)) { + // can't copy/cut dirs + if ($copy_cut_dirs === false) { + response(sprintf(trans('Copy_Cut_Not_Allowed'), $msg_sub_action, trans('Folders')).AddErrorLocation())->send(); + exit; + } + + [$sizeFolderToCopy,$fileNum,$foldersCount] = folder_info($path, false); + // size over limit + if ($copy_cut_max_size !== false && is_int($copy_cut_max_size)) { + if (($copy_cut_max_size * 1024 * 1024) < $sizeFolderToCopy) { + response(sprintf(trans('Copy_Cut_Size_Limit'), $msg_sub_action, $copy_cut_max_size).AddErrorLocation())->send(); + exit; + } + } + + // file count over limit + if ($copy_cut_max_count !== false && is_int($copy_cut_max_count)) { + if ($copy_cut_max_count < $fileNum) { + response(sprintf(trans('Copy_Cut_Count_Limit'), $msg_sub_action, $copy_cut_max_count).AddErrorLocation())->send(); + exit; + } + } + + if (!checkresultingsize($sizeFolderToCopy)) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + } else { + // can't copy/cut files + if ($copy_cut_files === false) { + response(sprintf(trans('Copy_Cut_Not_Allowed'), $msg_sub_action, trans('Files')).AddErrorLocation())->send(); + exit; + } + } + + $_SESSION['RF']['clipboard']['path'] = $_POST['path']; + $_SESSION['RF']['clipboard_action'] = $_POST['sub_action']; + break; + case 'clear_clipboard': + $_SESSION['RF']['clipboard'] = null; + $_SESSION['RF']['clipboard_action'] = null; + break; + case 'chmod': + if ($ftp) { + $path = $ftp_base_url.$upload_dir.$_POST['path']; + if ( + ($_POST['folder'] == 1 && $chmod_dirs === false) + || ($_POST['folder'] == 0 && $chmod_files === false) + || (is_function_callable('chmod') === false)) { + response(sprintf(trans('File_Permission_Not_Allowed'), is_dir($path) ? trans('Folders') : trans('Files'), 403).AddErrorLocation())->send(); + exit; + } + $info = $_POST['permissions']; + } else { + $path = $current_path.$_POST['path']; + if ( + (is_dir($path) && $chmod_dirs === false) + || (is_file($path) && $chmod_files === false) + || (is_function_callable('chmod') === false)) { + response(sprintf(trans('File_Permission_Not_Allowed'), is_dir($path) ? trans('Folders') : trans('Files'), 403).AddErrorLocation())->send(); + exit; + } + + $perms = fileperms($path) & 0777; + + $info = '-'; + + // Owner + $info .= (($perms & 0x0100) ? 'r' : '-'); + $info .= (($perms & 0x0080) ? 'w' : '-'); + $info .= (($perms & 0x0040) ? + (($perms & 0x0800) ? 's' : 'x') : + (($perms & 0x0800) ? 'S' : '-')); + + // Group + $info .= (($perms & 0x0020) ? 'r' : '-'); + $info .= (($perms & 0x0010) ? 'w' : '-'); + $info .= (($perms & 0x0008) ? + (($perms & 0x0400) ? 's' : 'x') : + (($perms & 0x0400) ? 'S' : '-')); + + // World + $info .= (($perms & 0x0004) ? 'r' : '-'); + $info .= (($perms & 0x0002) ? 'w' : '-'); + $info .= (($perms & 0x0001) ? + (($perms & 0x0200) ? 't' : 'x') : + (($perms & 0x0200) ? 'T' : '-')); + } + + $ret = '
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
r  w  x  
'.trans('User').'
'.trans('Group').'
'.trans('All').'
'; + + if (!$ftp && is_dir($path)) { + $ret .= '
'.trans('File_Permission_Recursive').'

+
    +
  • +
  • +
  • +
  • +
+
'; + } + + $ret .= '
'; + + response($ret)->send(); + exit; + + break; + case 'get_lang': + if (!file_exists('lang/languages.php')) { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; + } + + $languages = include 'lang/languages.php'; + if (!isset($languages) || !is_array($languages)) { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; + } + + $curr = $_SESSION['RF']['language']; + + $ret = ''; + + response($ret)->send(); + exit; + + break; + case 'change_lang': + $choosen_lang = (!empty($_POST['choosen_lang'])) ? $_POST['choosen_lang'] : 'en_EN'; + + if (array_key_exists($choosen_lang, $languages)) { + if (!file_exists('lang/'.$choosen_lang.'.php')) { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; + } + $_SESSION['RF']['language'] = $choosen_lang; + } + + break; + case 'cad_preview': + if ($ftp) { + $selected_file = $ftp_base_url.$upload_dir.$_GET['file']; + } else { + $selected_file = $current_path.$_GET['file']; + + if (!file_exists($selected_file)) { + response(trans('File_Not_Found').AddErrorLocation())->send(); + exit; + } + } + if ($ftp) { + $url_file = $selected_file; + } else { + $url_file = $base_url.$upload_dir.str_replace($current_path, '', $_GET['file']); + } + + $cad_url = urlencode($url_file); + $cad_html = ''; + $ret = $cad_html; + response($ret)->send(); + break; + case 'get_file': // preview or edit + $sub_action = $_GET['sub_action']; + $preview_mode = $_GET['preview_mode']; + + if ($sub_action != 'preview' && $sub_action != 'edit') { + response(trans('wrong action').AddErrorLocation())->send(); + exit; + } + + if ($ftp) { + $selected_file = ($sub_action == 'preview' ? $ftp_base_url.$upload_dir.$_GET['file'] : $ftp_base_url.$upload_dir.$_POST['path']); + } else { + $selected_file = ($sub_action == 'preview' ? $current_path.$_GET['file'] : $current_path.$_POST['path']); + + if (!file_exists($selected_file)) { + response(trans('File_Not_Found').AddErrorLocation())->send(); + exit; + } + } + + $info = pathinfo($selected_file); + + if ($preview_mode == 'text') { + $is_allowed = ($sub_action == 'preview' ? $preview_text_files : $edit_text_files); + $allowed_file_exts = ($sub_action == 'preview' ? $previewable_text_file_exts : $editable_text_file_exts); + } elseif ($preview_mode == 'viewerjs') { + $is_allowed = $viewerjs_enabled; + $allowed_file_exts = $viewerjs_file_exts; + } elseif ($preview_mode == 'google') { + $is_allowed = $googledoc_enabled; + $allowed_file_exts = $googledoc_file_exts; + } + + if (!isset($allowed_file_exts) || !is_array($allowed_file_exts)) { + $allowed_file_exts = []; + } + + if (!in_array($info['extension'], $allowed_file_exts) + || !isset($is_allowed) + || $is_allowed === false + || (!$ftp && !is_readable($selected_file)) + ) { + response(sprintf(trans('File_Open_Edit_Not_Allowed'), $sub_action == 'preview' ? strtolower(trans('Open')) : strtolower(trans('Edit'))).AddErrorLocation())->send(); + exit; + } + if ($sub_action == 'preview') { + if ($preview_mode == 'text') { + // get and sanities + $data = file_get_contents($selected_file); + $data = htmlspecialchars(htmlspecialchars_decode($data)); + $ret = ''; + + if (!in_array($info['extension'], $previewable_text_file_exts_no_prettify)) { + $ret .= ''; + $ret .= '
'.$data.'
'; + } else { + $ret .= '
'.$data.'
'; + } + } elseif ($preview_mode == 'google' || $preview_mode == 'viewerjs') { + if ($ftp) { + $url_file = $selected_file; + } else { + $url_file = $base_url.$upload_dir.str_replace($current_path, '', $_GET['file']); + } + + $googledoc_url = urlencode($url_file); + $googledoc_html = ''; + $ret = $googledoc_html; + } + } else { + $data = stripslashes(htmlspecialchars(file_get_contents($selected_file))); + $ret = ''; + } + + response($ret)->send(); + exit; + + break; + default: + response(trans('no action passed').AddErrorLocation())->send(); + exit; + } +} else { + response(trans('no action passed').AddErrorLocation())->send(); + exit; +} +?> diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess new file mode 100755 index 0000000..14249c5 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php new file mode 100755 index 0000000..1306aa6 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/config/config.php @@ -0,0 +1,593 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +mb_internal_encoding('UTF-8'); +mb_http_output('UTF-8'); +mb_language('uni'); +mb_regex_encoding('UTF-8'); +ob_start('mb_output_handler'); +//date_default_timezone_set('Europe/Rome'); + +use Symfony\Component\Filesystem\Filesystem; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Thelia; +use Thelia\Model\ConfigQuery; + +function generateFolder($env): void +{ + $webMediaPath = THELIA_WEB_DIR.'media'; + $webMediaEnvPath = null; + if ($env !== 'prod') { + //Remove separtion between dev and prod in particular environment + $env = str_replace('_dev', '', $env); + $webMediaEnvPath = $webMediaPath.DS.$env; + } + + $fileSystem = new Filesystem(); + + // Create the media directory in the web root , if required + if (null !== $webMediaEnvPath) { + if (false === $fileSystem->exists($webMediaEnvPath)) { + $fileSystem->mkdir($webMediaEnvPath.DS.'upload'); + $fileSystem->mkdir($webMediaEnvPath.DS.'thumbs'); + } + } else { + if (false === $fileSystem->exists($webMediaPath)) { + $fileSystem->mkdir($webMediaPath.DS.'upload'); + $fileSystem->mkdir($webMediaPath.DS.'thumbs'); + } + } +} + +$env = 'prod'; + +if (file_exists(__DIR__.'/../../../../../../../../bootstrap.php')) { + // Symlinked with thelia-project + require_once __DIR__.'/../../../../../../../../bootstrap.php'; +} elseif (file_exists(__DIR__.'/../../../../bootstrap.php')) { + // Hard copy with thelia-project + require_once __DIR__.'/../../../../bootstrap.php'; +} elseif (file_exists(__DIR__.'/../../../../../../../../vendor/autoload.php')) { + // Symlinked with std install + require_once __DIR__.'/../../../../../../../../vendor/autoload.php'; +} elseif (file_exists(__DIR__.'/../../../../vendor/autoload.php')) { + // Hard copy with std install + require_once __DIR__.'/../../../../vendor/autoload.php'; +} + +(new \Symfony\Component\Dotenv\Dotenv())->bootEnv(__DIR__.'/../../../../../../../../.env'); + +$thelia = new App\Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); +$request = Request::createFromGlobals(); +$thelia->boot(); + +/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */ +$container = $thelia->getContainer(); + +$eventDispatcher = $container->get('event_dispatcher'); +$container->get('thelia.translator'); +$container->get('thelia.url.manager'); +$container->get('request_stack')->push($request); +$event = new \Thelia\Core\Event\SessionEvent(THELIA_CACHE_DIR.$env, false, $env); + +$eventDispatcher->dispatch($event, \Thelia\Core\TheliaKernelEvents::SESSION); +$session = $event->getSession(); +$session->start(); +$request->setSession($session); + +/** @var \Thelia\Core\Security\SecurityContext $securityContext */ +$securityContext = $container->get('thelia.securityContext'); + +// We just check the current user has the ADMIN role. +$isGranted = $securityContext->isGranted(['ADMIN'], [], [], []); + +if (false === $isGranted) { + echo "Sorry, it seems that you're not allowed to use this function. ADMIN role is required."; + + exit; +} + +//------------------------------------------------------------------------------ +// DO NOT COPY THESE VARIABLES IN FOLDERS config.php FILES +//------------------------------------------------------------------------------ + +//********************** +//Path configuration +//********************** + +// In this configuration the media folder is located in the /web directory. + +// base url of site (without final /). if you prefer relative urls leave empty. +$base_url = rtrim(ConfigQuery::getConfiguredShopUrl(), '/'); + +// Argh, url_site is not defined ?! +if (empty($base_url)) { + // A we did not used the router to access this dialog, we cannot use the URL class. Use the good old method. + $base_url = $request->getSchemeAndHttpHost().preg_replace('!/tinymce/filemanager/dialog.php.*$!', '', $_SERVER['REQUEST_URI']); +} + +//Check for backward compatibility +if ($env !== 'prod') { + // path from base_url to base of upload folder for current env (with start and final /) + $upload_dir = '/media/'.$env.'/upload/'; + + // path from base_url to base of upload folder for current env (with start and final /) + $thumbs_dir = '/media/'.$env.'/thumbs/'; + + // path to file manager folder to upload folder for current env (with final /) + $current_path = THELIA_WEB_DIR.'media'.DS.$env.DS.'upload'.DS; + + // path to file manager folder to thumbs folder for current env (with final /) + // WARNING: thumbs folder should not be inside the upload folder + $thumbs_base_path = THELIA_WEB_DIR.'media'.DS.$env.DS.'thumbs'.DS; +} else { + // path from base_url to base of upload folder (with start and final /) + $upload_dir = '/media/upload/'; + + // path from base_url to base of upload folder (with start and final /) + $thumbs_dir = '/media/thumbs/'; + + // path to file manager folder to upload folder (with final /) + $current_path = THELIA_WEB_DIR.'media'.DS.'upload'.DS; + + // path to file manager folder to thumbs folder (with final /) + // WARNING: thumbs folder should not be inside the upload folder + $thumbs_base_path = THELIA_WEB_DIR.'media'.DS.'thumbs'.DS; +} + +generateFolder($env); + +// path from base_url to filemanager folder (with start and final /) +$filemanager_dir = '/tinymce/filemanager/'; + +// Set the language to the back-office current language, if it is available +$current_locale = $request->getSession()->getLang()->getLocale(); + +if (file_exists(__DIR__.DS.'..'.DS.'lang.'.DS.$current_locale.'.php')) { + $default_language = $current_locale; +} else { + $default_language = 'en_EN'; +} + +/* +|-------------------------------------------------------------------------- +| Optional security +|-------------------------------------------------------------------------- +| +| if set to true only those will access RF whose url contains the access key(akey) like: +| +| in tinymce a new parameter added: filemanager_access_key:"myPrivateKey" +| example tinymce config: +| +| tiny init ... +| external_filemanager_path:"../filemanager/", +| filemanager_title:"Filemanager" , +| filemanager_access_key:"myPrivateKey" , +| ... +| +*/ + +define('USE_ACCESS_KEYS', false); // TRUE or FALSE + +/* +|-------------------------------------------------------------------------- +| DON'T COPY THIS VARIABLES IN FOLDERS config.php FILES +|-------------------------------------------------------------------------- +*/ + +define('DEBUG_ERROR_MESSAGE', false); // TRUE or FALSE + +/* +|-------------------------------------------------------------------------- +| Path configuration +|-------------------------------------------------------------------------- +| In this configuration the folder tree is +| root +| |- source <- upload folder +| |- thumbs <- thumbnail folder [must have write permission (755)] +| |- filemanager +| |- js +| | |- tinymce +| | | |- plugins +| | | | |- responsivefilemanager +| | | | | |- plugin.min.js +*/ + +$config = [ + /* + |-------------------------------------------------------------------------- + | DON'T TOUCH (base url (only domain) of site). + |-------------------------------------------------------------------------- + | + | without final / (DON'T TOUCH) + | + */ + 'base_url' => $base_url, + + /* + |-------------------------------------------------------------------------- + | path from base_url to base of upload folder + |-------------------------------------------------------------------------- + | + | with start and final / + | + */ + 'upload_dir' => $upload_dir, + /* + |-------------------------------------------------------------------------- + | relative path from filemanager folder to upload folder + |-------------------------------------------------------------------------- + | + | with final / + | + */ + 'current_path' => $current_path, + + /* + |-------------------------------------------------------------------------- + | relative path from filemanager folder to thumbs folder + |-------------------------------------------------------------------------- + | + | with final / + | DO NOT put inside upload folder + | + */ + 'thumbs_base_path' => $thumbs_base_path, + + /* + |-------------------------------------------------------------------------- + | FTP configuration BETA VERSION + |-------------------------------------------------------------------------- + | + | If you want enable ftp use write these parametres otherwise leave empty + | Remember to set base_url properly to point in the ftp server domain and + | upload dir will be ftp_base_folder + upload_dir so without final / + | + */ + 'ftp_host' => false, + 'ftp_user' => 'user', + 'ftp_pass' => 'pass', + 'ftp_base_folder' => 'base_folder', + 'ftp_base_url' => 'http://site to ftp root', + /* -------------------------------------------------------------------------- + | path from ftp_base_folder to base of thumbs folder with start and final | + |--------------------------------------------------------------------------*/ + 'ftp_thumbs_dir' => '/thumbs/', + 'ftp_ssl' => false, + 'ftp_port' => 21, + + // 'ftp_host' => "s108707.gridserver.com", + // 'ftp_user' => "test@responsivefilemanager.com", + // 'ftp_pass' => "Test.1234", + // 'ftp_base_folder' => "/domains/responsivefilemanager.com/html", + + /* + |-------------------------------------------------------------------------- + | Access keys + |-------------------------------------------------------------------------- + | + | add access keys eg: array('myPrivateKey', 'someoneElseKey'); + | keys should only containt (a-z A-Z 0-9 \ . _ -) characters + | if you are integrating lets say to a cms for admins, i recommend making keys randomized something like this: + | $username = 'Admin'; + | $salt = 'dsflFWR9u2xQa' (a hard coded string) + | $akey = md5($username.$salt); + | DO NOT use 'key' as access key! + | Keys are CASE SENSITIVE! + | + */ + + 'access_keys' => [], + + //-------------------------------------------------------------------------------------------------------- + // YOU CAN COPY AND CHANGE THESE VARIABLES INTO FOLDERS config.php FILES TO CUSTOMIZE EACH FOLDER OPTIONS + //-------------------------------------------------------------------------------------------------------- + + /* + |-------------------------------------------------------------------------- + | Maximum size of all files in source folder + |-------------------------------------------------------------------------- + | + | in Megabytes + | + */ + 'MaxSizeTotal' => false, + + /* + |-------------------------------------------------------------------------- + | Maximum upload size + |-------------------------------------------------------------------------- + | + | in Megabytes + | + */ + 'MaxSizeUpload' => 100, + + /* + |-------------------------------------------------------------------------- + | File and Folder permission + |-------------------------------------------------------------------------- + | + */ + 'fileFolderPermission' => 0755, + + /* + |-------------------------------------------------------------------------- + | default language file name + |-------------------------------------------------------------------------- + */ + 'default_language' => $default_language, + + /* + |-------------------------------------------------------------------------- + | Icon theme + |-------------------------------------------------------------------------- + | + | Default available: ico and ico_dark + | Can be set to custom icon inside filemanager/img + | + */ + 'icon_theme' => 'ico', + + //Show or not total size in filemanager (is possible to greatly increase the calculations) + 'show_total_size' => false, + //Show or not show folder size in list view feature in filemanager (is possible, if there is a large folder, to greatly increase the calculations) + 'show_folder_size' => false, + //Show or not show sorting feature in filemanager + 'show_sorting_bar' => true, + //Show or not show filters button in filemanager + 'show_filter_buttons' => true, + //Show or not language selection feature in filemanager + 'show_language_selection' => true, + //active or deactive the transliteration (mean convert all strange characters in A..Za..z0..9 characters) + 'transliteration' => false, + //convert all spaces on files name and folders name with $replace_with variable + 'convert_spaces' => false, + //convert all spaces on files name and folders name this value + 'replace_with' => '_', + //convert to lowercase the files and folders name + 'lower_case' => false, + + //Add ?484899493349 (time value) to returned images to prevent cache + 'add_time_to_img' => false, + + // -1: There is no lazy loading at all, 0: Always lazy-load images, 0+: The minimum number of the files in a directory + // when lazy loading should be turned on. + 'lazy_loading_file_number_threshold' => -1, + + //******************************************* + //Images limit and resizing configuration + //******************************************* + + // set maximum pixel width and/or maximum pixel height for all images + // If you set a maximum width or height, oversized images are converted to those limits. Images smaller than the limit(s) are unaffected + // if you don't need a limit set both to 0 + 'image_max_width' => 0, + 'image_max_height' => 0, + 'image_max_mode' => 'auto', + /* + # $option: 0 / exact = defined size; + # 1 / portrait = keep aspect set height; + # 2 / landscape = keep aspect set width; + # 3 / auto = auto; + # 4 / crop= resize and crop; + */ + + //Automatic resizing // + // If you set $image_resizing to TRUE the script converts all uploaded images exactly to image_resizing_width x image_resizing_height dimension + // If you set width or height to 0 the script automatically calculates the other dimension + // Is possible that if you upload very big images the script not work to overcome this increase the php configuration of memory and time limit + 'image_resizing' => false, + 'image_resizing_width' => 0, + 'image_resizing_height' => 0, + 'image_resizing_mode' => 'auto', // same as $image_max_mode + 'image_resizing_override' => false, + // If set to TRUE then you can specify bigger images than $image_max_width & height otherwise if image_resizing is + // bigger than $image_max_width or height then it will be converted to those values + + //****************** + // + // WATERMARK IMAGE + // + //Watermark url or false + 'image_watermark' => false, + // Could be a pre-determined position such as: + // tl = top left, + // t = top (middle), + // tr = top right, + // l = left, + // m = middle, + // r = right, + // bl = bottom left, + // b = bottom (middle), + // br = bottom right + // Or, it could be a co-ordinate position such as: 50x100 + 'image_watermark_position' => 'br', + // padding: If using a pre-determined position you can + // adjust the padding from the edges by passing an amount + // in pixels. If using co-ordinates, this value is ignored. + 'image_watermark_padding' => 0, + + //****************** + // Default layout setting + // + // 0 => boxes + // 1 => detailed list (1 column) + // 2 => columns list (multiple columns depending on the width of the page) + // YOU CAN ALSO PASS THIS PARAMETERS USING SESSION VAR => $_SESSION['RF']["VIEW"]= + // + //****************** + 'default_view' => 0, + + //set if the filename is truncated when overflow first row + 'ellipsis_title_after_first_row' => true, + + //************************* + //Permissions configuration + //****************** + 'delete_files' => true, + 'create_folders' => true, + 'delete_folders' => true, + 'upload_files' => true, + 'rename_files' => true, + 'rename_folders' => true, + 'duplicate_files' => true, + 'copy_cut_files' => true, // for copy/cut files + 'copy_cut_dirs' => true, // for copy/cut directories + 'chmod_files' => true, // change file permissions + 'chmod_dirs' => true, // change folder permissions + 'preview_text_files' => true, // eg.: txt, log etc. + 'edit_text_files' => true, // eg.: txt, log etc. + 'create_text_files' => true, // only create files with exts. defined in $editable_text_file_exts + + // you can preview these type of files if $preview_text_files is true + 'previewable_text_file_exts' => ['bsh', 'c', 'css', 'cc', 'cpp', 'cs', 'csh', 'cyc', 'cv', 'htm', 'html', 'java', 'js', 'm', 'mxml', 'perl', 'pl', 'pm', 'py', 'rb', 'sh', 'xhtml', 'xml', 'xsl'], + 'previewable_text_file_exts_no_prettify' => ['txt', 'log'], + + // you can edit these type of files if $edit_text_files is true (only text based files) + // you can create these type of files if $create_text_files is true (only text based files) + // if you want you can add html,css etc. + // but for security reasons it's NOT RECOMMENDED! + 'editable_text_file_exts' => ['txt', 'log', 'xml', 'html', 'css', 'htm', 'js'], + + // Preview with Google Documents + 'googledoc_enabled' => true, + 'googledoc_file_exts' => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'], + + // Preview with Viewer.js + 'viewerjs_enabled' => true, + 'viewerjs_file_exts' => ['pdf', 'odt', 'odp', 'ods'], + + // defines size limit for paste in MB / operation + // set 'FALSE' for no limit + 'copy_cut_max_size' => 100, + // defines file count limit for paste / operation + // set 'FALSE' for no limit + 'copy_cut_max_count' => 200, + //IF any of these limits reached, operation won't start and generate warning + + //********************** + //Allowed extensions (lowercase insert) + //********************** + 'ext_img' => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'svg'], //Images + 'ext_file' => ['svg', 'doc', 'docx', 'rtf', 'pdf', 'xls', 'xlsx', 'txt', 'csv', 'html', 'xhtml', 'psd', 'sql', 'log', 'fla', 'xml', 'ade', 'adp', 'mdb', 'accdb', 'ppt', 'pptx', 'odt', 'ots', 'ott', 'odb', 'odg', 'otp', 'otg', 'odf', 'ods', 'odp', 'css', 'ai', 'kmz', 'dwg', 'dxf', 'hpgl', 'plt', 'spl', 'step', 'stp', 'iges', 'igs', 'sat', 'cgm'], //Files + 'ext_video' => ['mov', 'mpeg', 'm4v', 'mp4', 'avi', 'mpg', 'wma', 'flv', 'webm'], //Video + 'ext_music' => ['mp3', 'mpga', 'm4a', 'ac3', 'aiff', 'mid', 'ogg', 'wav'], //Audio + 'ext_misc' => ['zip', 'rar', 'gz', 'tar', 'iso', 'dmg'], //Archives + + /****************** + * AVIARY config + *******************/ + 'aviary_active' => true, + 'aviary_apiKey' => '2444282ef4344e3dacdedc7a78f8877d', + 'aviary_language' => 'en', + 'aviary_theme' => 'light', + 'aviary_tools' => 'all', + 'aviary_maxSize' => '1400', + // Add or modify the Aviary options below as needed - they will be json encoded when added to the configuration so arrays can be utilized as needed + + //The filter and sorter are managed through both javascript and php scripts because if you have a lot of + //file in a folder the javascript script can't sort all or filter all, so the filemanager switch to php script. + //The plugin automatic swich javascript to php when the current folder exceeds the below limit of files number + 'file_number_limit_js' => 500, + + //********************** + // Hidden files and folders + //********************** + // set the names of any folders you want hidden (eg "hidden_folder1", "hidden_folder2" ) Remember all folders with these names will be hidden (you can set any exceptions in config.php files on folders) + 'hidden_folders' => [], + // set the names of any files you want hidden. Remember these names will be hidden in all folders (eg "this_document.pdf", "that_image.jpg" ) + 'hidden_files' => ['config.php'], + + /******************* + * URL upload + *******************/ + 'url_upload' => true, + + /******************* + * JAVA upload + *******************/ + 'java_upload' => true, + 'JAVAMaxSizeUpload' => 200, //Gb + + //************************************ + //Thumbnail for external use creation + //************************************ + + // New image resized creation with fixed path from filemanager folder after uploading (thumbnails in fixed mode) + // If you want create images resized out of upload folder for use with external script you can choose this method, + // You can create also more than one image at a time just simply add a value in the array + // Remember than the image creation respect the folder hierarchy so if you are inside source/test/test1/ the new image will create at + // path_from_filemanager/test/test1/ + // PS if there isn't write permission in your destination folder you must set it + // + 'fixed_image_creation' => false, //activate or not the creation of one or more image resized with fixed path from filemanager folder + 'fixed_path_from_filemanager' => ['../test/', '../test1/'], //fixed path of the image folder from the current position on upload folder + 'fixed_image_creation_name_to_prepend' => ['', 'test_'], //name to prepend on filename + 'fixed_image_creation_to_append' => ['_test', ''], //name to appendon filename + 'fixed_image_creation_width' => [300, 400], //width of image (you can leave empty if you set height) + 'fixed_image_creation_height' => [200, ''], //height of image (you can leave empty if you set width) + /* + # $option: 0 / exact = defined size; + # 1 / portrait = keep aspect set height; + # 2 / landscape = keep aspect set width; + # 3 / auto = auto; + # 4 / crop= resize and crop; + */ + 'fixed_image_creation_option' => ['crop', 'auto'], //set the type of the crop + + // New image resized creation with relative path inside to upload folder after uploading (thumbnails in relative mode) + // With Responsive filemanager you can create automatically resized image inside the upload folder, also more than one at a time + // just simply add a value in the array + // The image creation path is always relative so if i'm inside source/test/test1 and I upload an image, the path start from here + // + 'relative_image_creation' => false, //activate or not the creation of one or more image resized with relative path from upload folder + 'relative_path_from_current_pos' => ['./', './'], //relative path of the image folder from the current position on upload folder + 'relative_image_creation_name_to_prepend' => ['', ''], //name to prepend on filename + 'relative_image_creation_name_to_append' => ['_thumb', '_thumb1'], //name to append on filename + 'relative_image_creation_width' => [300, 400], //width of image (you can leave empty if you set height) + 'relative_image_creation_height' => [200, ''], //height of image (you can leave empty if you set width) + /* + # $option: 0 / exact = defined size; + # 1 / portrait = keep aspect set height; + # 2 / landscape = keep aspect set width; + # 3 / auto = auto; + # 4 / crop= resize and crop; + */ + 'relative_image_creation_option' => ['crop', 'crop'], //set the type of the crop + + // Remember text filter after close filemanager for future session + 'remember_text_filter' => false, +]; + +return array_merge( + $config, + [ + 'MaxSizeUpload' => ((int) (ini_get('post_max_size')) < $config['MaxSizeUpload']) + ? (int) (ini_get('post_max_size')) : $config['MaxSizeUpload'], + 'ext' => array_merge( + $config['ext_img'], + $config['ext_file'], + $config['ext_misc'], + $config['ext_video'], + $config['ext_music'] + ), + // For a list of options see: https://developers.aviary.com/docs/web/setup-guide#constructor-config + 'aviary_defaults_config' => [ + 'apiKey' => $config['aviary_apiKey'], + 'language' => $config['aviary_language'], + 'theme' => $config['aviary_theme'], + 'tools' => $config['aviary_tools'], + 'maxSize' => $config['aviary_maxSize'], + ], + ] +); diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css new file mode 100644 index 0000000..bdda797 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/css/style.css @@ -0,0 +1,36 @@ +/*! + * Bootstrap v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none}html{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto;outline-offset:-2px}a:active,a:hover{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{max-width:100%;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button,input[type=button],input[type=checkbox],input[type=radio],input[type=reset],input[type=submit],label,select{cursor:pointer}input[type=search]{box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{overflow:auto}@media print{*{text-shadow:none!important;color:#000!important;background:0 0!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{line-height:20px;color:#333;background-color:#fff}a:focus,a:hover{color:#005580;text-decoration:underline}.img-rounded{border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.1)}.img-circle{border-radius:500px}.row{margin-left:-20px}.row:after,.row:before{display:table;content:"";line-height:0}.row:after{clear:both}[class*=span]{float:left;min-height:1px;margin-left:20px}.container,.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container,.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%}.row-fluid:after,.row-fluid:before{display:table;content:"";line-height:0}.row-fluid:after{clear:both}.row-fluid [class*=span]{display:block;width:100%;min-height:30px;box-sizing:border-box;float:left;margin-left:2.12765957%}.row-fluid [class*=span]:first-child{margin-left:0}.row-fluid .controls-row [class*=span]+[class*=span]{margin-left:2.12765957%}.row-fluid .span12{width:100%}.row-fluid .span11{width:91.4893617%}.row-fluid .span10{width:82.9787234%}.row-fluid .span9{width:74.46808511%}.row-fluid .span8{width:65.95744681%}.row-fluid .span7{width:57.44680851%}.row-fluid .span6{width:48.93617021%}.row-fluid .span5{width:40.42553191%}.row-fluid .span4{width:31.91489362%}.row-fluid .span3{width:23.40425532%}.row-fluid .span2{width:14.89361702%}.row-fluid .span1{width:6.38297872%}.row-fluid .offset12{margin-left:104.25531915%}.row-fluid .offset12:first-child{margin-left:102.12765957%}.row-fluid .offset11{margin-left:95.74468085%}.row-fluid .offset11:first-child{margin-left:93.61702128%}.row-fluid .offset10{margin-left:87.23404255%}.row-fluid .offset10:first-child{margin-left:85.10638298%}.row-fluid .offset9{margin-left:78.72340426%}.row-fluid .offset9:first-child{margin-left:76.59574468%}.row-fluid .offset8{margin-left:70.21276596%}.row-fluid .offset8:first-child{margin-left:68.08510638%}.row-fluid .offset7{margin-left:61.70212766%}.row-fluid .offset7:first-child{margin-left:59.57446809%}.row-fluid .offset6{margin-left:53.19148936%}.row-fluid .offset6:first-child{margin-left:51.06382979%}.row-fluid .offset5{margin-left:44.68085106%}.row-fluid .offset5:first-child{margin-left:42.55319149%}.row-fluid .offset4{margin-left:36.17021277%}.row-fluid .offset4:first-child{margin-left:34.04255319%}.row-fluid .offset3{margin-left:27.65957447%}.row-fluid .offset3:first-child{margin-left:25.53191489%}.row-fluid .offset2{margin-left:19.14893617%}.row-fluid .offset2:first-child{margin-left:17.0212766%}.row-fluid .offset1{margin-left:10.63829787%}.row-fluid .offset1:first-child{margin-left:8.5106383%}.row-fluid [class*=span].hide,[class*=span].hide{display:none}.row-fluid [class*=span].pull-right,[class*=span].pull-right{float:right}.container{margin-right:auto;margin-left:auto}.container:after,.container:before{display:table;content:"";line-height:0}.container:after{clear:both}.container-fluid:after,.container-fluid:before{display:table;content:"";line-height:0}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:700}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:focus,a.muted:hover{color:grey}.text-warning{color:#c09853}a.text-warning:focus,a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:focus,a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:focus,a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:focus,a.text-success:hover{color:#356635}.text-left{text-align:left}.text-right{text-align:right}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:700;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:400;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small,h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ol,ul{padding:0;margin:0 0 10px 25px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}li{line-height:20px}ol.inline,ol.unstyled,ul.inline,ul.unstyled{margin-left:0;list-style:none}ol.inline>li,ul.inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-bottom:20px}dd,dt{line-height:20px}dt{font-weight:700}dd{margin-left:10px}.dl-horizontal:after,.dl-horizontal:before{display:table;content:"";line-height:0}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}blockquote:after,blockquote:before,q:after,q:before{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}button,input,label,select,textarea{font-size:14px;font-weight:400;line-height:20px}button,input,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}.uneditable-input,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;border-radius:4px;vertical-align:middle}.uneditable-input,input,textarea{width:206px}textarea{height:auto}.uneditable-input,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],textarea{background-color:#fff;border:1px solid #ccc;box-shadow:inset 0 1px 1px rgba(0,0,0,.075);transition:border linear .2s,box-shadow linear .2s}.uneditable-input:focus,input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus,textarea:focus{border-color:rgba(82,168,236,.8);outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(82,168,236,.6)}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}input[type=button],input[type=checkbox],input[type=file],input[type=image],input[type=radio],input[type=reset],input[type=submit]{width:auto}input[type=file],select{height:30px;line-height:30px}select{width:220px;border:1px solid #ccc;background-color:#fff}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus,select:focus{outline:#333 dotted thin;outline:-webkit-focus-ring-color auto;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;box-shadow:inset 0 1px 2px rgba(0,0,0,.025);cursor:not-allowed}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.checkbox,.radio{min-height:20px;padding-left:20px}.checkbox input[type=checkbox],.radio input[type=radio]{float:left;margin-left:-20px}.controls>.checkbox:first-child,.controls>.radio:first-child{padding-top:5px}.checkbox.inline,.radio.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.checkbox.inline+.checkbox.inline,.radio.inline+.radio.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}.row-fluid .uneditable-input[class*=span],.row-fluid input[class*=span],.row-fluid select[class*=span],.row-fluid textarea[class*=span],.uneditable-input[class*=span],input[class*=span],select[class*=span],textarea[class*=span]{float:none;margin-left:0}.input-append .uneditable-input[class*=span],.input-append input[class*=span],.input-prepend .uneditable-input[class*=span],.input-prepend input[class*=span],.row-fluid .input-append [class*=span],.row-fluid .input-prepend [class*=span],.row-fluid .uneditable-input[class*=span],.row-fluid input[class*=span],.row-fluid select[class*=span],.row-fluid textarea[class*=span]{display:inline-block}.uneditable-input,input,textarea{margin-left:0}.controls-row [class*=span]+[class*=span]{margin-left:20px}.uneditable-input.span12,input.span12,textarea.span12{width:926px}.uneditable-input.span11,input.span11,textarea.span11{width:846px}.uneditable-input.span10,input.span10,textarea.span10{width:766px}.uneditable-input.span9,input.span9,textarea.span9{width:686px}.uneditable-input.span8,input.span8,textarea.span8{width:606px}.uneditable-input.span7,input.span7,textarea.span7{width:526px}.uneditable-input.span6,input.span6,textarea.span6{width:446px}.uneditable-input.span5,input.span5,textarea.span5{width:366px}.uneditable-input.span4,input.span4,textarea.span4{width:286px}.uneditable-input.span3,input.span3,textarea.span3{width:206px}.uneditable-input.span2,input.span2,textarea.span2{width:126px}.uneditable-input.span1,input.span1,textarea.span1{width:46px}.controls-row:after,.controls-row:before{display:table;content:"";line-height:0}.controls-row:after{clear:both}.controls-row [class*=span],.row-fluid .controls-row [class*=span]{float:left}.controls-row .checkbox[class*=span],.controls-row .radio[class*=span]{padding-top:5px}input[disabled],input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type=checkbox][disabled],input[type=checkbox][readonly],input[type=radio][disabled],input[type=radio][readonly]{background-color:transparent}.control-group.warning .checkbox,.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e}.control-group.warning .input-append .add-on,.control-group.warning .input-prepend .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .checkbox,.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392}.control-group.error .input-append .add-on,.control-group.error .input-prepend .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .checkbox,.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b}.control-group.success .input-append .add-on,.control-group.success .input-prepend .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .checkbox,.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7ab5d3}.control-group.info .input-append .add-on,.control-group.info .input-prepend .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e9322d;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5}.form-actions:after,.form-actions:before{display:table;content:"";line-height:0}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;vertical-align:middle;padding-left:5px}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append .dropdown-menu,.input-append .popover,.input-append .uneditable-input,.input-append input,.input-append select,.input-prepend .dropdown-menu,.input-prepend .popover,.input-prepend .uneditable-input,.input-prepend input,.input-prepend select{font-size:14px}.input-append .uneditable-input,.input-append input,.input-append select,.input-prepend .uneditable-input,.input-prepend input,.input-prepend select{position:relative;margin-bottom:0;vertical-align:top;border-radius:0 4px 4px 0}.input-append .uneditable-input:focus,.input-append input:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-prepend input:focus,.input-prepend select:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:400;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-append .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .add-on,.input-prepend .btn,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-append .uneditable-input,.input-append input,.input-append select,.input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px}.input-append .uneditable-input+.btn-group .btn:last-child,.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child{border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-prepend.input-append .uneditable-input,.input-prepend.input-append input,.input-prepend.input-append select{border-radius:0}.input-prepend.input-append .uneditable-input+.btn-group .btn,.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn{border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-left:14px;margin-bottom:0;border-radius:15px}.form-search .input-append .search-query{border-radius:14px 0 0 14px}.form-search .input-append .btn,.form-search .input-prepend .search-query{border-radius:0 14px 14px 0}.form-search .input-prepend .btn{border-radius:14px 0 0 14px}.form-horizontal .help-inline,.form-horizontal .input-append,.form-horizontal .input-prepend,.form-horizontal .uneditable-input,.form-horizontal input,.form-horizontal select,.form-horizontal textarea,.form-inline .help-inline,.form-inline .input-append,.form-inline .input-prepend,.form-inline .uneditable-input,.form-inline input,.form-inline select,.form-inline textarea,.form-search .help-inline,.form-search .input-append,.form-search .input-prepend,.form-search .uneditable-input,.form-search input,.form-search select,.form-search textarea{display:inline-block;margin-bottom:0;vertical-align:middle}.form-horizontal .hide,.form-inline .hide,.form-search .hide{display:none}.form-inline .btn-group,.form-inline label,.form-search .btn-group,.form-search label{display:inline-block}.form-inline .input-append,.form-inline .input-prepend,.form-search .input-append,.form-search .input-prepend{margin-bottom:0}.form-inline .checkbox,.form-inline .radio,.form-search .checkbox,.form-search .radio{padding-left:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio],.form-search .checkbox input[type=checkbox],.form-search .radio input[type=radio]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px}.form-horizontal .control-group:after,.form-horizontal .control-group:before{display:table;content:"";line-height:0}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{margin-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal .input-append+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table td,.table th{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:700}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child td,.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child td,.table thead:first-child tr:first-child th{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed td,.table-condensed th{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;border-left:0;border-radius:4px}.table-bordered td,.table-bordered th{border-left:1px solid #ddd}.table-bordered caption+tbody tr:first-child td,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+thead tr:first-child th,.table-bordered tbody:first-child tr:first-child td,.table-bordered tbody:first-child tr:first-child th,.table-bordered thead:first-child tr:first-child th{border-top:0}.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child,.table-bordered thead:first-child tr:first-child>th:first-child{border-top-left-radius:4px}.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child,.table-bordered thead:first-child tr:first-child>th:last-child{border-top-right-radius:4px}.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child,.table-bordered thead:last-child tr:last-child>th:first-child{border-bottom-left-radius:4px}.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child,.table-bordered thead:last-child tr:last-child>th:last-child{border-bottom-right-radius:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{border-bottom-left-radius:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{border-bottom-right-radius:0}.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered caption+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child{border-top-left-radius:4px}.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered caption+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child{border-top-right-radius:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}.row-fluid table td[class*=span],.row-fluid table th[class*=span],table td[class*=span],table th[class*=span]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class*=" icon-"],[class^=icon-]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url(../img/glyphicons-halflings.png);background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-menu>.active>a>[class^=icon-],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>li>a:focus>[class^=icon-],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^=icon-],.dropdown-submenu:focus>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class^=icon-],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^=icon-],.icon-white,.nav-list>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^=icon-],.nav-pills>.active>a>[class*=" icon-"],.nav-pills>.active>a>[class^=icon-],.navbar-inverse .nav>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^=icon-]{background-image:url(../img/glyphicons-halflings-white.png)}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{background-position:-216px -120px;width:16px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px;width:16px}.icon-folder-open{background-position:-408px -120px;width:16px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropdown,.dropup{position:relative}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 5px 10px rgba(0,0,0,.2);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover,.dropdown-submenu:focus>a,.dropdown-submenu:hover>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#999}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:default}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}.typeahead{z-index:1051;margin-top:2px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-large{padding:24px;border-radius:6px}.well-small{padding:9px;border-radius:3px}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:700;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.btn{display:inline-block;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;background-color:#f5f5f5;background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border:1px solid #ccc}.btn.active,.btn.disabled,.btn:active,.btn:focus,.btn:hover,.btn[disabled]{color:#333;background-color:#e6e6e6}.btn:focus,.btn:hover{color:#333;text-decoration:none;background-position:0 -15px;transition:background-position .1s linear}.btn:focus{outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;border-radius:6px}.btn-large [class*=" icon-"],.btn-large [class^=icon-]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;border-radius:3px}.btn-small [class*=" icon-"],.btn-small [class^=icon-]{margin-top:0}.btn-mini [class*=" icon-"],.btn-mini [class^=icon-]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary.active,.btn-primary.disabled,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.btn-primary[disabled]{color:#fff}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#faa732;background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning.active,.btn-warning.disabled,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.btn-warning[disabled]{color:#fff;background-color:#f89406}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#da4f49;background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger.active,.btn-danger.disabled,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.btn-danger[disabled]{color:#fff;background-color:#bd362f}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#5bb75b;background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success.active,.btn-success.disabled,.btn-success:active,.btn-success:focus,.btn-success:hover,.btn-success[disabled]{color:#fff;background-color:#51a351}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#49afcd;background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info.active,.btn-info.disabled,.btn-info:active,.btn-info:focus,.btn-info:hover,.btn-info[disabled]{color:#fff;background-color:#2f96b4}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#363636;background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse.active,.btn-inverse.disabled,.btn-inverse:active,.btn-inverse:focus,.btn-inverse:hover,.btn-inverse[disabled]{color:#fff;background-color:#222}button.btn::-moz-focus-inner,input[type=submit].btn::-moz-focus-inner{padding:0;border:0}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;box-shadow:none}.btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0}.btn-link:focus,.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;font-size:0;vertical-align:middle;white-space:nowrap}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn{margin-left:5px}.btn-group>.btn{position:relative;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{border-top-right-radius:4px;border-bottom-right-radius:4px}.btn-group>.btn.large:first-child{margin-left:0;border-top-left-radius:6px;border-bottom-left-radius:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{border-top-right-radius:6px;border-bottom-right-radius:6px}.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;box-shadow:inset 1px 0 0 rgba(255,255,255,.125),inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px}.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px;border-left-width:5px;border-right-width:5px;border-top-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-danger .caret,.btn-info .caret,.btn-inverse .caret,.btn-primary .caret,.btn-success .caret,.btn-warning .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0}.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}.btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px}.alert{text-shadow:0 1px 0 rgba(255,255,255,.5);background-color:#fcf8e3}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}.alert-success h4{color:#468847}.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-left:0;margin-bottom:20px;list-style:none}.nav>li>a{display:block}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:700;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}.nav-list .nav-header,.nav-list>li>a{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:focus,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.2);background-color:#08c}.nav-list [class*=" icon-"],.nav-list [class^=icon-]{margin-right:2px}.nav-list .divider{height:1px;margin:9px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-pills:after,.nav-pills:before,.nav-tabs:after,.nav-tabs:before{display:table;content:"";line-height:0}.nav-pills:after,.nav-tabs:after{clear:both}.nav-pills>li,.nav-tabs>li{float:left}.nav-pills>li>a,.nav-tabs>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:focus,.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:focus,.nav-tabs>.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:focus,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{border-top-right-radius:4px;border-top-left-radius:4px}.nav-tabs.nav-stacked>li:last-child>a{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.nav-tabs.nav-stacked>li>a:focus,.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{border-radius:6px}.nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}.nav .dropdown-toggle:focus .caret,.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:focus,.nav>.dropdown.active>a:hover{cursor:pointer}.nav-pills .open .dropdown-toggle,.nav-tabs .open .dropdown-toggle,.nav>li.dropdown.open.active>a:focus,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open a:focus .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open.active .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:focus,.tabs-stacked .open>a:hover{border-color:#999}.tabbable:after,.tabbable:before{display:table;content:"";line-height:0}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-left>.nav-tabs,.tabs-right>.nav-tabs{border-bottom:0}.pill-content>.pill-pane,.tab-content>.tab-pane{display:none}.pill-content>.active,.tab-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:focus,.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:focus,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:focus,.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:focus,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:focus,.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:focus,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent}.nav>.disabled>a{color:#999}.nav>.disabled>a:focus,.nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default}.navbar{overflow:visible}.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;border-radius:4px;box-shadow:0 1px 4px rgba(0,0,0,.065)}.navbar-inner:after,.navbar-inner:before{display:table;content:"";line-height:0}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{float:left;display:block;padding:10px 20px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:focus,.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:focus,.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-append .btn,.navbar .input-append .btn-group,.navbar .input-prepend .btn,.navbar .input-prepend .btn-group{margin-top:0}.navbar-form{margin-bottom:0}.navbar-form:after,.navbar-form:before{display:table;content:"";line-height:0}.navbar-form:after{clear:both}.navbar-form .checkbox,.navbar-form .radio,.navbar-form input,.navbar-form select{margin-top:5px}.navbar-form .btn,.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0}.navbar-form input[type=checkbox],.navbar-form input[type=image],.navbar-form input[type=radio]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:400;line-height:1;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-bottom .navbar-inner,.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;border-radius:0}.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{box-shadow:0 1px 10px rgba(0,0,0,.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{box-shadow:0 -1px 10px rgba(0,0,0,.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}.navbar .nav>.active>a,.navbar .nav>.active>a:focus,.navbar .nav>.active>a:hover{color:#555;text-decoration:none;background-color:#e5e5e5;box-shadow:inset 0 3px 8px rgba(0,0,0,.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#ededed;background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar:active,.navbar .btn-navbar:focus,.navbar .btn-navbar:hover,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;border-radius:1px;box-shadow:0 1px 0 rgba(0,0,0,.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:9px}.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-bottom:0;bottom:-7px;top:auto}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}.navbar .nav li.dropdown>a:focus .caret,.navbar .nav li.dropdown>a:hover .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle,.navbar .nav li.dropdown.open>.dropdown-toggle{background-color:#e5e5e5;color:#555}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav>li>.dropdown-menu.pull-right,.navbar .pull-right>li>.dropdown-menu{left:auto;right:0}.navbar .nav>li>.dropdown-menu.pull-right:before,.navbar .pull-right>li>.dropdown-menu:before{left:auto;right:12px}.navbar .nav>li>.dropdown-menu.pull-right:after,.navbar .pull-right>li>.dropdown-menu:after{left:auto;right:13px}.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu,.navbar .pull-right>li>.dropdown-menu .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-inverse .brand:focus,.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .brand,.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:focus,.navbar-inverse .nav .active>a:hover{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:focus,.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open>.dropdown-toggle{background-color:#111;color:#fff}.navbar-inverse .nav li.dropdown>a:focus .caret,.navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;box-shadow:inset 0 1px 2px rgba(0,0,0,.1),0 1px 0 rgba(255,255,255,.15);transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query.focused,.navbar-inverse .navbar-search .search-query:focus{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;box-shadow:0 0 3px rgba(0,0,0,.15);outline:0}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e0e0e;background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;margin-left:0;margin-bottom:0;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>.active>a,.pagination ul>.active>span,.pagination ul>li>a:focus,.pagination ul>li>a:hover{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>a,.pagination ul>.disabled>a:focus,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>span{color:#999;background-color:transparent;cursor:default}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-mini ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>a,.pagination-small ul>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-mini ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>a,.pagination-small ul>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;list-style:none;text-align:center}.pager:after,.pager:before{display:table;content:"";line-height:0}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal{left:50%;z-index:1050;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.3);border-radius:6px;box-shadow:0 3px 7px rgba(0,0,0,.3);background-clip:padding-box}.modal-header{border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;border-radius:0 0 6px 6px;box-shadow:inset 0 1px 0 #fff}.modal-footer:after,.modal-footer:before{display:table;content:"";line-height:0}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.thumbnails{margin-left:-20px;list-style:none}.thumbnails:after,.thumbnails:before{display:table;content:"";line-height:0}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.055);transition:all .2s ease-in-out}a.thumbnail:focus,a.thumbnail:hover{border-color:#08c;box-shadow:0 1px 4px rgba(0,105,214,.25)}.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.badge,.label{display:inline-block;padding:2px 4px;font-size:11.84px;font-weight:700;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#999}.label{border-radius:3px}.badge{padding-left:9px;padding-right:9px;border-radius:9px}.badge:empty,.label:empty{display:none}a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.badge-important,.label-important{background-color:#b94a48}.badge-important[href],.label-important[href]{background-color:#953b39}.badge-warning,.label-warning{background-color:#f89406}.badge-warning[href],.label-warning[href]{background-color:#c67605}.badge-success,.label-success{background-color:#468847}.badge-success[href],.label-success[href]{background-color:#356635}.badge-info,.label-info{background-color:#3a87ad}.badge-info[href],.label-info[href]{background-color:#2d6987}.badge-inverse,.label-inverse{background-color:#333}.badge-inverse[href],.label-inverse[href]{background-color:#1a1a1a}.btn .badge,.btn .label{position:relative;top:-1px}.btn-mini .badge,.btn-mini .label{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);box-shadow:inset 0 1px 2px rgba(0,0,0,.1);border-radius:4px}.progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#0e90d2;background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-sizing:border-box;transition:width .6s ease}.progress .bar+.bar{box-shadow:inset 1px 0 0 rgba(0,0,0,.15),inset 0 -1px 0 rgba(0,0,0,.15)}.progress-striped .bar{background-color:#149bdf;background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress .bar-danger,.progress-danger .bar{background-color:#dd514c;background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-success,.progress-success .bar{background-color:#5eb95e;background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}.progress-striped .bar-success,.progress-success.progress-striped .bar{background-color:#62c462;background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-info,.progress-info .bar{background-color:#4bb1cf;background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress .bar-warning,.progress-warning .bar{background-color:#faa732;background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}.progress-striped .bar-warning,.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{overflow:hidden;width:100%;position:relative}.carousel-inner>.item{display:none;position:relative;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,.75)}.carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}/*! + * Bootstrap Responsive v2.3.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix:after,.clearfix:before{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.hidden-desktop,.visible-phone,.visible-tablet{display:none!important}.visible-desktop{display:inherit!important}@media (min-width:768px) and (max-width:839px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media (max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media (min-width:1200px){.row{margin-left:-30px}.row:after,.row:before{display:table;content:"";line-height:0}.row:after{clear:both}[class*=span]{float:left;min-height:1px;margin-left:30px}.container,.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container,.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%}.row-fluid:after,.row-fluid:before{display:table;content:"";line-height:0}.row-fluid:after{clear:both}.row-fluid [class*=span]{display:block;width:100%;min-height:30px;box-sizing:border-box;float:left;margin-left:2.56410256%}.row-fluid [class*=span]:first-child{margin-left:0}.row-fluid .controls-row [class*=span]+[class*=span]{margin-left:2.56410256%}.row-fluid .span12{width:100%}.row-fluid .span11{width:91.45299145%}.row-fluid .span10{width:82.90598291%}.row-fluid .span9{width:74.35897436%}.row-fluid .span8{width:65.81196581%}.row-fluid .span7{width:57.26495726%}.row-fluid .span6{width:48.71794872%}.row-fluid .span5{width:40.17094017%}.row-fluid .span4{width:31.62393162%}.row-fluid .span3{width:23.07692308%}.row-fluid .span2{width:14.52991453%}.row-fluid .span1{width:5.98290598%}.row-fluid .offset12{margin-left:105.12820513%}.row-fluid .offset12:first-child{margin-left:102.56410256%}.row-fluid .offset11{margin-left:96.58119658%}.row-fluid .offset11:first-child{margin-left:94.01709402%}.row-fluid .offset10{margin-left:88.03418803%}.row-fluid .offset10:first-child{margin-left:85.47008547%}.row-fluid .offset9{margin-left:79.48717949%}.row-fluid .offset9:first-child{margin-left:76.92307692%}.row-fluid .offset8{margin-left:70.94017094%}.row-fluid .offset8:first-child{margin-left:68.37606838%}.row-fluid .offset7{margin-left:62.39316239%}.row-fluid .offset7:first-child{margin-left:59.82905983%}.row-fluid .offset6{margin-left:53.84615385%}.row-fluid .offset6:first-child{margin-left:51.28205128%}.row-fluid .offset5{margin-left:45.2991453%}.row-fluid .offset5:first-child{margin-left:42.73504274%}.row-fluid .offset4{margin-left:36.75213675%}.row-fluid .offset4:first-child{margin-left:34.18803419%}.row-fluid .offset3{margin-left:28.20512821%}.row-fluid .offset3:first-child{margin-left:25.64102564%}.row-fluid .offset2{margin-left:19.65811966%}.row-fluid .offset2:first-child{margin-left:17.09401709%}.row-fluid .offset1{margin-left:11.11111111%}.row-fluid .offset1:first-child{margin-left:8.54700855%}.uneditable-input,input,textarea{margin-left:0}.controls-row [class*=span]+[class*=span]{margin-left:30px}.uneditable-input.span12,input.span12,textarea.span12{width:1156px}.uneditable-input.span11,input.span11,textarea.span11{width:1056px}.uneditable-input.span10,input.span10,textarea.span10{width:956px}.uneditable-input.span9,input.span9,textarea.span9{width:856px}.uneditable-input.span8,input.span8,textarea.span8{width:756px}.uneditable-input.span7,input.span7,textarea.span7{width:656px}.uneditable-input.span6,input.span6,textarea.span6{width:556px}.uneditable-input.span5,input.span5,textarea.span5{width:456px}.uneditable-input.span4,input.span4,textarea.span4{width:356px}.uneditable-input.span3,input.span3,textarea.span3{width:256px}.uneditable-input.span2,input.span2,textarea.span2{width:156px}.uneditable-input.span1,input.span1,textarea.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:839px){.row{margin-left:-20px}.row:after,.row:before{display:table;content:"";line-height:0}.row:after{clear:both}[class*=span]{float:left;min-height:1px;margin-left:20px}.container,.navbar-fixed-bottom .container,.navbar-fixed-top .container,.navbar-static-top .container,.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%}.row-fluid:after,.row-fluid:before{display:table;content:"";line-height:0}.row-fluid:after{clear:both}.row-fluid [class*=span]{display:block;width:100%;min-height:30px;box-sizing:border-box;float:left;margin-left:2.76243094%}.row-fluid [class*=span]:first-child{margin-left:0}.row-fluid .controls-row [class*=span]+[class*=span]{margin-left:2.76243094%}.row-fluid .span12{width:100%}.row-fluid .span11{width:91.43646409%}.row-fluid .span10{width:82.87292818%}.row-fluid .span9{width:74.30939227%}.row-fluid .span8{width:65.74585635%}.row-fluid .span7{width:57.18232044%}.row-fluid .span6{width:48.61878453%}.row-fluid .span5{width:40.05524862%}.row-fluid .span4{width:31.49171271%}.row-fluid .span3{width:22.9281768%}.row-fluid .span2{width:14.36464088%}.row-fluid .span1{width:5.80110497%}.row-fluid .offset12{margin-left:105.52486188%}.row-fluid .offset12:first-child{margin-left:102.76243094%}.row-fluid .offset11{margin-left:96.96132597%}.row-fluid .offset11:first-child{margin-left:94.19889503%}.row-fluid .offset10{margin-left:88.39779006%}.row-fluid .offset10:first-child{margin-left:85.63535912%}.row-fluid .offset9{margin-left:79.83425414%}.row-fluid .offset9:first-child{margin-left:77.0718232%}.row-fluid .offset8{margin-left:71.27071823%}.row-fluid .offset8:first-child{margin-left:68.50828729%}.row-fluid .offset7{margin-left:62.70718232%}.row-fluid .offset7:first-child{margin-left:59.94475138%}.row-fluid .offset6{margin-left:54.14364641%}.row-fluid .offset6:first-child{margin-left:51.38121547%}.row-fluid .offset5{margin-left:45.5801105%}.row-fluid .offset5:first-child{margin-left:42.81767956%}.row-fluid .offset4{margin-left:37.01657459%}.row-fluid .offset4:first-child{margin-left:34.25414365%}.row-fluid .offset3{margin-left:28.45303867%}.row-fluid .offset3:first-child{margin-left:25.69060773%}.row-fluid .offset2{margin-left:19.88950276%}.row-fluid .offset2:first-child{margin-left:17.12707182%}.row-fluid .offset1{margin-left:11.32596685%}.row-fluid .offset1:first-child{margin-left:8.56353591%}.uneditable-input,input,textarea{margin-left:0}.controls-row [class*=span]+[class*=span]{margin-left:20px}.uneditable-input.span12,input.span12,textarea.span12{width:710px}.uneditable-input.span11,input.span11,textarea.span11{width:648px}.uneditable-input.span10,input.span10,textarea.span10{width:586px}.uneditable-input.span9,input.span9,textarea.span9{width:524px}.uneditable-input.span8,input.span8,textarea.span8{width:462px}.uneditable-input.span7,input.span7,textarea.span7{width:400px}.uneditable-input.span6,input.span6,textarea.span6{width:338px}.uneditable-input.span5,input.span5,textarea.span5{width:276px}.uneditable-input.span4,input.span4,textarea.span4{width:214px}.uneditable-input.span3,input.span3,textarea.span3{width:152px}.uneditable-input.span2,input.span2,textarea.span2{width:90px}.uneditable-input.span1,input.span1,textarea.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{margin-left:-20px;margin-right:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;clear:none;width:auto;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}.row-fluid [class*=span],.uneditable-input[class*=span],[class*=span]{float:none;display:block;width:100%;margin-left:0;box-sizing:border-box}.row-fluid .span12,.span12{width:100%;box-sizing:border-box}.row-fluid [class*=offset]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,.uneditable-input,input[class*=span],select[class*=span],textarea[class*=span]{display:block;width:100%;min-height:30px;box-sizing:border-box}.input-append input,.input-append input[class*=span],.input-prepend input,.input-prepend input[class*=span]{display:inline-block;width:auto}.controls-row [class*=span]+[class*=span]{margin-left:0}.modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type=checkbox],input[type=radio]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-left:10px;padding-right:10px}.media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;left:10px;right:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media (max-width:839px){body{padding-top:0}.navbar-fixed-bottom,.navbar-fixed-top{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-bottom .navbar-inner,.navbar-fixed-top .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .dropdown-menu a,.nav-collapse .nav>li>a{padding:9px 15px;font-weight:700;color:#777;border-radius:3px}.nav-collapse .btn{padding:4px 10px;font-weight:400;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .dropdown-menu a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .nav>li>a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .dropdown-menu a,.navbar-inverse .nav-collapse .nav>li>a{color:#999}.navbar-inverse .nav-collapse .dropdown-menu a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .nav>li>a:hover{background-color:#111}.nav-collapse.in .btn-group{margin-top:5px;padding:0}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;border-radius:0;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu .divider,.nav-collapse .dropdown-menu:after,.nav-collapse .dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after,.nav-collapse .nav>li>.dropdown-menu:before{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:839px + 1){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}.lightbox{background-color:transparent;text-align:center;line-height:0;z-index:1050;position:relative;top:70px;outline:0}.lightbox .hide{display:none}.lightbox .in{display:block}.lightbox-content{display:inline-block;background-color:#fff}.lightbox-content .lightbox-caption{padding:2%;position:absolute;left:11px;right:12px;bottom:11px;background:#000;background:rgba(0,0,0,.6);color:#fff;text-align:center;text-shadow:0 -1px 0 #000;text-shadow:0 -1px 0 rgba(0,0,0,.3);font-size:14px;line-height:18px}.lightbox-header .close{color:#fff;margin-right:-16px;margin-top:-16px;font-size:2em;opacity:.8;filter:alpha(opacity=80)}.lightbox-header .close :hover{opacity:.4;filter:alpha(opacity=40)}/*! + * Bootstrap Modal + * + * Copyright Jordan Schroter + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */.modal-open{overflow:hidden}.modal-open.page-overflow .modal-scrollable,.modal-open.page-overflow .page-container,.modal-open.page-overflow .page-container .navbar-fixed-bottom,.modal-open.page-overflow .page-container .navbar-fixed-top{overflow-y:scroll}@media (max-width:979px){.modal-open.page-overflow .page-container .navbar-fixed-bottom,.modal-open.page-overflow .page-container .navbar-fixed-top{overflow-y:visible}}.modal-scrollable{position:fixed;top:0;bottom:0;left:0;right:0;overflow:auto}.modal{outline:0;position:absolute;margin-top:0;top:50%;overflow:visible}.modal.fade{top:-100%;-webkit-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out;transition:opacity .3s linear,top .3s ease-out,bottom .3s ease-out,margin-top .3s ease-out}.modal.fade.in{top:50%}.modal-body{max-height:none;overflow:visible}.modal.modal-absolute{position:absolute;z-index:950}.modal .loading-mask{position:absolute;top:0;bottom:0;left:0;right:0;background:#fff;border-radius:6px}.modal-backdrop.modal-absolute{position:absolute;z-index:940}.modal-backdrop,.modal-backdrop.fade.in{opacity:.7;filter:alpha(opacity=70);background:#fff}.modal.container{width:940px;margin-left:-470px}.modal-overflow.modal{top:1%}.modal-overflow.modal.fade{top:-100%}.modal-overflow.modal.fade.in{top:1%}.modal-overflow .modal-body{overflow:auto;-webkit-overflow-scrolling:touch}@media (min-width:1200px){.modal.container{width:1170px;margin-left:-585px}}@media (max-width:979px){.modal,.modal.container,.modal.modal-overflow{top:1%;right:1%;left:1%;bottom:auto;width:auto!important;height:auto!important;margin:0!important;padding:0!important}.modal.container.fade.in,.modal.fade.in,.modal.modal-overflow.fade.in{top:1%;bottom:auto}.modal-body,.modal-overflow .modal-body{position:static;margin:0;height:auto!important;max-height:none!important;overflow:visible!important}.modal-footer,.modal-overflow .modal-footer{position:static}}.loading-spinner{position:absolute;top:50%;left:50%;margin:-12px 0 0 -12px}.animated{-webkit-animation-duration:1s;-moz-animation-duration:1s;-o-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;-o-animation-fill-mode:both;animation-fill-mode:both}@-webkit-keyframes shake{0%,100%{-webkit-transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px)}}@-moz-keyframes shake{0%,100%{-moz-transform:translateX(0)}10%,30%,50%,70%,90%{-moz-transform:translateX(-10px)}20%,40%,60%,80%{-moz-transform:translateX(10px)}}@-o-keyframes shake{0%,100%{-o-transform:translateX(0)}10%,30%,50%,70%,90%{-o-transform:translateX(-10px)}20%,40%,60%,80%{-o-transform:translateX(10px)}}@keyframes shake{0%,100%{transform:translateX(0)}10%,30%,50%,70%,90%{transform:translateX(-10px)}20%,40%,60%,80%{transform:translateX(10px)}}.shake{-webkit-animation-name:shake;-moz-animation-name:shake;-o-animation-name:shake;animation-name:shake}@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom,#eee,#ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;-ms-transition:opacity .2s linear;-o-transition:opacity .2s linear;transition:opacity .2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:rgba(255,255,255,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05,1.05);-moz-transform:scale(1.05,1.05);-ms-transform:scale(1.05,1.05);-o-transform:scale(1.05,1.05);transform:scale(1.05,1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(.77,0,.175,1);-moz-animation:passing-through 3s cubic-bezier(.77,0,.175,1);-ms-animation:passing-through 3s cubic-bezier(.77,0,.175,1);-o-animation:passing-through 3s cubic-bezier(.77,0,.175,1);animation:passing-through 3s cubic-bezier(.77,0,.175,1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(.77,0,.175,1);-moz-animation:slide-in 3s cubic-bezier(.77,0,.175,1);-ms-animation:slide-in 3s cubic-bezier(.77,0,.175,1);-o-animation:slide-in 3s cubic-bezier(.77,0,.175,1);animation:slide-in 3s cubic-bezier(.77,0,.175,1)}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-error-mark svg,.dropzone .dz-preview .dz-success-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all .2s linear;-moz-transition:all .2s linear;-ms-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity .4s ease-in;-moz-transition:opacity .4s ease-in;-ms-transition:opacity .4s ease-in;-o-transition:opacity .4s ease-in;transition:opacity .4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom,#666,#444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity .3s ease;-moz-transition:opacity .3s ease;-ms-transition:opacity .3s ease;-o-transition:opacity .3s ease;transition:opacity .3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom,#be2626,#a92222);padding:.5em 1.2em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626}/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: 1.6.6 + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */.context-menu-list{min-width:120px;max-width:250px;display:inline-block;position:absolute;list-style-type:none;border:1px solid #DDD;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.5);-moz-box-shadow:0 2px 5px rgba(0,0,0,.5);-ms-box-shadow:0 2px 5px rgba(0,0,0,.5);-o-box-shadow:0 2px 5px rgba(0,0,0,.5);box-shadow:0 2px 5px rgba(0,0,0,.5)}.context-menu-item>label>input,.context-menu-item>label>textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.context-menu-item.hover{cursor:pointer}.context-menu-item.disabled{color:#666}.context-menu-submenu:after{content:">";color:#666;position:absolute;top:0;right:3px;z-index:1}.context-menu-item.icon{min-height:18px;background-repeat:no-repeat}.context-menu-input>label>*{vertical-align:top}.context-menu-input>label>input[type=checkbox],.context-menu-input>label>input[type=radio]{margin-left:-17px}.context-menu-input>label>span{margin-left:5px}.context-menu-input>label,.context-menu-input>label>input[type=text],.context-menu-input>label>select,.context-menu-input>label>textarea{display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box}.context-menu-input>label>textarea{height:100px}.context-menu-item>.context-menu-list{display:none;right:-5px;top:5px}.context-menu-item.hover>.context-menu-list{display:block}.context-menu-accesskey{text-decoration:underline}*,:after,:before{box-sizing:border-box}body,html{font-family:'Open Sans',sans-serif;font-size:100%;padding:0;margin:0}body{padding-top:32px;font-weight:200;background:#ececec;overflow:-moz-scrollbars-vertical}.btn{background-image:none!important;text-shadow:none!important;border-color:none!important;box-shadow:none!important}.btn:focus{outline:0}.btn-inverse{background-image:none!important;background:#333}pre.no-prettify,pre.prettyprint{height:300px;margin:0!important;width:100%!important;overflow:scroll;border-radius:0!important}.input-append .add-on:last-child,.input-append .btn-group:last-child>.dropdown-toggle,.input-append .btn:last-child{border-radius:0!important}[class*=" rficon-"],[class^=rficon-]{display:inline-block;width:16px;height:16px;margin-top:1px;line-height:16px;vertical-align:text-top;background-position:0 0;background-repeat:no-repeat}.rficon-clipboard-apply{background-image:url(../img/clipboard_apply.png)}.rficon-clipboard-clear{background-image:url(../img/clipboard_clear.png)}.rficon-upload{background-image:url(../img/upload.png)}.btn{border-radius:0}.container-fluid{margin-top:10px!important}.img-precontainer{margin:auto;width:100%;text-align:center;background:#fff;border:none}.img-container{height:91px;width:122px;padding:0;border:none;overflow:hidden;display:table-cell;text-align:center;vertical-align:middle;margin:auto;background-image:url(../img/trans.jpg);background-size:13px}.img-container img{max-width:122px;max-height:91px}ul.breadcrumb{margin-bottom:5px;border-radius:0;padding-bottom:4px;padding-top:6px;background:#f0f0f0;box-shadow:0 1px 4px rgba(0,0,0,.065);border-bottom:1px solid #bbb}ul.breadcrumb .pull-left i{margin-top:2px}.alert{padding:8px 35px 8px 14px;margin-bottom:2px;border:1px solid #aaa;color:#666;font-weight:200;font-size:13px;border-radius:0;background:#fff}.img-container *,.img-container-mini *{vertical-align:middle}#help{display:none}.text-center{text-align:center}iframe{overflow:auto;-webkit-overflow-scrolling:touch}.upload-help{font-size:11px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff;text-align:center}.upload-tabbable{margin-left:5px;margin-right:5px}.upload-tabbable .nav{margin:0}.upload-tabbable .nav li a{font-size:13px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.upload-tabbable .tab-content{padding:5px;border-bottom:1px solid #ddd;border-left:1px solid #ddd;border-right:1px solid #ddd;background:#fff;margin-bottom:5px;height:400px;overflow-y:scroll}input#filter-input{margin:0 0 2px;width:84px;height:26px;vertical-align:bottom;border-radius:0;font-size:12px;font-weight:200;position:relative;left:1px}.qq-uploader .span9{margin-left:14px!important;width:690px!important}.space10{clear:both;height:10px}h4{font-size:12px;font-weight:200;margin:6px 0 0;text-align:center;padding:0;line-height:18px}h3{font-size:14px;font-weight:200}.boxes{border:1px solid #CCC;word-wrap:break-word;background:#fff;box-shadow:1px 1px 2px 0 rgba(0,0,0,.2);min-height:115px;text-align:center}.container-fluid{padding:0 10px!important}body .avpw .avpw_primary_button,body .avpw .avpw_primary_button:active,body .avpw .avpw_primary_button:link,body .avpw .avpw_primary_button:visited{color:#fff;background:#999;border:none}body .avpw .avpw_primary_button:hover{border:none;background:#666}.uploader{position:fixed;top:50px;left:14px;margin:auto;width:100%;z-index:9999;overflow:hidden;background:#eee;padding-top:20px;border:1px solid #ccc;display:none;box-shadow:0 0 10px 0 rgba(1,1,1,.5)}.download-form{margin-bottom:25px}.grid li i{margin-left:2px;margin-right:2px;z-index:0}.box,.boxx{word-wrap:break-word;vertical-align:top;text-align:left;position:relative;border:none;box-shadow:none;z-index:100;padding:4px}.box .btn{width:100%;background:0 0;box-shadow:none;border:none;z-index:200}.navbar{margin-bottom:0;border-bottom:1px solid #bbb}.navbar .navbar-inner{border:none;min-height:35px;border-radius:0;padding-bottom:2px;margin:0;padding-right:8px;padding-left:8px}.navbar .navbar-inner .container-fluid{margin:0;margin-top:0!important;padding:0}.navbar .navbar-inner .container-fluid .brand{display:none}.navbar .navbar-inner .container-fluid .filters span{margin-top:0;font-size:13px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}ul.sorting{position:absolute;left:-25px;top:20px;min-width:0;background:#eee}ul.sorting li a:hover{background:#aaa}.btn-group .dropdown-toggle.sorting-btn{background:0 0;border:none;box-shadow:none;position:relative;-webkit-box-shadow:none;top:-5px;font-size:13px}.btn-group .dropdown-toggle.sorting-btn:hover{background:0 0;border:none;box-shadow:none;-webkit-box-shadow:none}ul.sorting.dropdown-menu>li>a{font-size:12px;text-shadow:none}ul.sorting.dropdown-menu>li>a.descending{background-image:url(../img/down.png);background-repeat:no-repeat;background-position:6px 8px}ul.sorting.dropdown-menu>li>a.ascending{background-image:url(../img/up.png);background-repeat:no-repeat;background-position:6px 8px}.sorter-container{margin-top:5px;margin-bottom:0;border-radius:0;padding-bottom:4px;padding-top:6px;box-shadow:0 1px 4px rgba(0,0,0,.065);background-color:#f5f5f5;position:relative;border-bottom:1px solid #bbb;height:24px}.sorter-container a.sorter{color:#000}.sorter-container a.descending{padding-left:9px;background-image:url(../img/down.png);background-repeat:no-repeat;background-position:0 3px}.sorter-container a.ascending{padding-left:9px;background-image:url(../img/up.png);background-repeat:no-repeat;background-position:0 4px}.sorter-container .file-date,.sorter-container .file-extension,.sorter-container .file-name,.sorter-container .file-operations,.sorter-container .file-size,.sorter-container .img-dimension{display:block;position:absolute;top:0;z-index:100;box-shadow:none;text-align:left;font-size:13px;margin-top:1px;color:#999}.sorter-container .file-operations{width:110px;right:0}.sorter-container .img-dimension{width:65px;right:123px}.sorter-container .file-date{width:70px;right:188px}.sorter-container .file-size{width:55px;right:258px}.sorter-container .file-extension{width:40px;right:313px}.sorter-container .file-name{width:50px;left:52px}.file-date,.file-extension,.file-name,.file-operations,.file-size,.img-dimension{font-size:12px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff;display:none}.view-controller{text-align:left}.view-controller .btn-group>.btn:first-child,.view-controller .btn-group>.btn:last-child{border-radius:0}.navbar .filters .btn{margin-bottom:2px;padding:2px 8px;margin-top:5px}.filters .types{text-align:right}@media (max-width:780px){#view2{display:none}}@media (min-width:840px){.mobile-inline-visible{display:none!important}}@media (max-width:839px){body{padding-top:0}.mobile-inline-visible{display:inline!important}.filters .types{text-align:left}.navbar .navbar-inner .container-fluid .brand{display:block}.navbar .navbar-inner{padding-bottom:4px}.filters div.span2.half,.filters div.span3.half,.filters div.span4.half{float:left;width:auto;margin-right:10px}.filters div.entire{float:none;width:100%;clear:both}.container-fluid{margin:0!important;padding:0}#qLbar{height:50px!important}}@media (min-width:400px) and (max-width:839px){.filters .row-fluid .half{width:48.61878453038674%;float:left}}.tooltip.in{z-index:10000;opacity:1;filter:alpha(opacity=1);font-weight:700}.tooltip{font-weight:700;z-index:10000}.grid{padding:0;margin:0 auto;list-style:none;-webkit-overflow-scrolling:touch}.ui-draggable-helper{z-index:10}.grid li{display:inline-block;width:124px;border:none;margin:4px 4px 8px;padding:0;vertical-align:top}.grid figure{position:relative;display:block;width:122px;margin:auto}.grid figure:hover{background:#e0e0e0!important}.list-view1.grid li,.list-view1.grid li figure{width:100%}.grid figcaption{text-align:center;padding:8px 2px 2px;color:#fff;height:30px;width:122px;margin-left:0;margin-right:0;position:absolute;top:auto;bottom:0;box-shadow:inset 0 0 8px 0 rgba(41,41,41,.5)}.grid figcaption a{margin:0;padding:3px}.grid figcaption h3{margin:0;padding:0;color:#fff}.grid h4{text-align:center;color:#000;padding:0;margin-bottom:4px;margin-top:4px}.grid figure .box{box-sizing:content-box;cursor:pointer}.list-view0.grid figure .box,.list-view1.grid figure .box,.list-view2.grid figure .box{max-width:100%;display:block;position:relative;overflow:hidden;z-index:1}.list-view0.grid figure .box h4.ellipsis,.list-view1.grid figure .box h4.ellipsis,.list-view2.grid figure .box h4.ellipsis{height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-view0.grid figure .box h4,.list-view0.grid figure .box h4 a,.list-view1.grid figure .box h4,.list-view1.grid figure .box h4 a,.list-view2.grid figure .box h4,.list-view2.grid figure .box h4 a{z-index:1}.no-touch .list-view0 figure .box{z-index:1;transition:-webkit-transform .3s;transition:transform .3s}.list-view0.grid .ui-state-highlight .img-precontainer{background:grey!important}.list-view0.grid .ui-state-highlight .img-precontainer .img-container{background:repeating-linear-gradient(45deg,transparent,transparent 5px,rgba(255,255,255,.4) 5px,rgba(255,255,255,.3) 10px);border:none;overflow:hidden}.list-view0.grid .ui-state-hover .img-precontainer .img-container{background:#666}.list-view1.grid .ui-state-highlight:nth-child(odd) figure,.list-view2.grid .ui-state-highlight:nth-child(odd) figure{background:#ddd!important;border-bottom-color:#444!important}.list-view1.grid .ui-state-highlight:nth-child(even) figure,.list-view2.grid .ui-state-highlight:nth-child(even) figure{background:#ccc!important;border-bottom-color:#aaa!important}.list-view1.grid .ui-state-highlight.ui-state-hover figure,.list-view2.grid .ui-state-highlight.ui-state-hover figure{background-color:#aaa!important}.no-touch .list-view0 figure.cs-hover .box,.no-touch .list-view0 figure:hover .box{box-shadow:0 0 4px 0 rgba(1,1,1,.5);-webkit-transform:translateY(-26px);transform:translateY(-26px)}.list-view0 figure.cs-hover .box.no-effect,.list-view0 figure:hover .box.no-effect,.no-effect{box-shadow:none;-webkit-transform:none;transform:none}.list-view0 .img-precontainer-mini{display:none;background:0 0}a,a:hover{color:#000;text-decoration:none}.back-directory .box,.back-directory .img-precontainer,.back-directory .img-precontainer-mini{background:0 0}form{margin:0;padding:0}.google-iframe,.viewer-iframe{width:100%;height:500px;border:none}.modal{width:60%;margin-left:-30%}.modal-body{padding:6px}.modal-body form,.modal-body input,.modal-body textarea{margin:0;border-radius:0}.modal-body .text-center{padding-bottom:6px}.modal-footer{padding:7px}.modal-header{padding:7px 8px!important}.modal-header h3{font-weight:300;font-size:20px}.list-view1.sorter-container{display:block}.list-view0.sorter-container,.list-view2.sorter-container{display:none}.list-view0.grid .img-precontainer .img-container img{max-width:122px!important;max-height:91px!important}.list-view0.grid .img-precontainer .img-container img.icon{width:122px;margin-top:0}.list-view0.grid .img-precontainer .filetype{position:absolute;top:0;width:122px;text-align:center;color:#fff;font-size:13px;line-height:22px}.list-view0.grid .cover{background:rgba(255,255,255,.25);width:122px;position:absolute;top:22px;right:0;height:69px}.list-view0.grid .box{background:#fff}.list-view0.grid .directory{background:#ddd}.list-view0.grid figure.back-directory .directory{background:#bbb}.list-view0.grid figcaption{background:#fff}.list-view0.grid .selected figure{border:none;height:126px}.list-view0.grid .selected figure .box,.list-view0.grid .selected figure figcaption,.list-view0.grid .selected figure>a{display:none}.list-view1.grid li,.list-view2.grid li{margin:0}.list-view1.grid li.back figure.back-directory,.list-view2.grid li.back figure.back-directory{height:34px}.list-view1.grid li:nth-child(odd) figure,.list-view2.grid li:nth-child(odd) figure{background:#f9f9f9}.list-view1.grid li:nth-child(odd) figure.directory,.list-view2.grid li:nth-child(odd) figure.directory{background:#eaeaea}.list-view1.grid li figure,.list-view2.grid li figure{border-bottom:1px solid #aaa;background:#fff}.list-view1.grid li figure.back-directory,.list-view2.grid li figure.back-directory{background:#bbb}.list-view1.grid li figure.back-directory .box,.list-view2.grid li figure.back-directory .box{background:0 0}.list-view1.grid li figure.directory,.list-view2.grid li figure.directory{background:#efefef}.list-view1.grid li figure.directory box,.list-view2.grid li figure.directory box{padding:0;min-height:10px}.list-view1.grid li figure .box,.list-view2.grid li figure .box{margin-left:50px;transition:none}.list-view1.grid li figure .box h4,.list-view2.grid li figure .box h4{padding-top:1px;font-size:13px;text-align:left}.list-view1.grid .img-precontainer-mini,.list-view2.grid .img-precontainer-mini{display:block;position:absolute;width:45px;height:34px;overflow:hidden;text-align:center}.list-view1.grid .img-precontainer-mini img,.list-view2.grid .img-precontainer-mini img{max-width:45px}.list-view1.grid .img-precontainer-mini .filetype,.list-view2.grid .img-precontainer-mini .filetype{position:absolute;top:1px;text-align:center;left:0;padding:1px 2px;font-size:13px;line-height:32px;width:45px;height:32px;color:#fff;background:#333}.list-view1.grid .cover,.list-view2.grid .cover{display:none}.list-view1.grid .img-container-mini,.list-view2.grid .img-container-mini{width:45px;height:34px;border:none;overflow:hidden;display:table-cell;text-align:center;vertical-align:middle;margin:auto}.list-view1.grid .img-precontainer-mini.original-thumb,.list-view2.grid .img-precontainer-mini.original-thumb{padding:0}.list-view1.grid .img-precontainer-mini.original-thumb img,.list-view2.grid .img-precontainer-mini.original-thumb img{width:auto;max-height:32px}.list-view1.grid .img-precontainer-mini.original-thumb img.original,.list-view2.grid .img-precontainer-mini.original-thumb img.original{width:auto;height:auto}.list-view1.grid .img-precontainer,.list-view2.grid .img-precontainer{display:none}.list-view1.grid figcaption,.list-view2.grid figcaption{background:0 0;width:120px;position:absolute;right:0;top:0;z-index:1;bottom:0;box-shadow:none;text-align:right}.list-view1.grid .selected figure,.list-view2.grid .selected figure{background:#ccc!important}.list-view1.grid .file-date,.list-view1.grid .file-extension,.list-view1.grid .file-size,.list-view1.grid .img-dimension{overflow:hidden;display:block;position:absolute;top:0;z-index:1;box-shadow:none;text-align:left;margin-top:7px}.list-view1.grid .img-dimension{width:65px;right:120px}.list-view1.grid .file-date{width:70px;right:185px}.list-view1.grid .file-size{width:55px;right:255px}.list-view1.grid .file-extension{width:40px;right:310px}.list-view1.grid figure .box{padding-right:352px}.list-view2.grid figure .box{padding-right:115px}@media (max-width:610px){.list-view1.grid figure .box{padding-right:312px}.list-view1.grid figure .file-extension,.sorter-container .file-extension{display:none}}@media (max-width:565px){.list-view1.grid figure .box{padding-right:257px}.list-view1.grid figure .file-size,.sorter-container .file-size{display:none}}@media (max-width:495px){.list-view1.grid figure .box{padding-right:187px}.list-view1.grid figure .file-date,.sorter-container .file-date{display:none}}@media (max-width:430px){.list-view1.grid figure .box{padding-right:115px}.list-view1.grid figure .img-dimension,.sorter-container .img-dimension{display:none}.breadcrumb{margin-left:0;margin-right:0}}.list-view1.grid .img-precontainer-mini .filetype.pdf,.list-view2.grid .img-precontainer-mini .filetype.pdf{background:#CB0011}.list-view1.grid .img-precontainer-mini .filetype.ai,.list-view2.grid .img-precontainer-mini .filetype.ai{background:#D6772F}.list-view1.grid .img-precontainer-mini .filetype.psd,.list-view2.grid .img-precontainer-mini .filetype.psd{background:#0960A4}.list-view1.grid .img-precontainer-mini .filetype.html,.list-view1.grid .img-precontainer-mini .filetype.xhtml,.list-view2.grid .img-precontainer-mini .filetype.html,.list-view2.grid .img-precontainer-mini .filetype.xhtml{background:#035BC4}.list-view1.grid .img-precontainer-mini .filetype.fla,.list-view1.grid .img-precontainer-mini .filetype.flv,.list-view2.grid .img-precontainer-mini .filetype.fla,.list-view2.grid .img-precontainer-mini .filetype.flv{background:#CF302E}.list-view1.grid .img-precontainer-mini .filetype.ppt,.list-view1.grid .img-precontainer-mini .filetype.pptx,.list-view2.grid .img-precontainer-mini .filetype.ppt,.list-view2.grid .img-precontainer-mini .filetype.pptx{background:#DA5B00}.list-view1.grid .img-precontainer-mini .filetype.css,.list-view1.grid .img-precontainer-mini .filetype.xls,.list-view1.grid .img-precontainer-mini .filetype.xlsx,.list-view2.grid .img-precontainer-mini .filetype.css,.list-view2.grid .img-precontainer-mini .filetype.xls,.list-view2.grid .img-precontainer-mini .filetype.xlsx{background:#1A712C}.list-view1.grid .img-precontainer-mini .filetype.doc,.list-view1.grid .img-precontainer-mini .filetype.docx,.list-view1.grid .img-precontainer-mini .filetype.rts,.list-view2.grid .img-precontainer-mini .filetype.doc,.list-view2.grid .img-precontainer-mini .filetype.docx,.list-view2.grid .img-precontainer-mini .filetype.rts{background:#002093}.list-view1.grid .img-precontainer-mini .filetype.gzip,.list-view1.grid .img-precontainer-mini .filetype.rar,.list-view1.grid .img-precontainer-mini .filetype.zip,.list-view2.grid .img-precontainer-mini .filetype.gzip,.list-view2.grid .img-precontainer-mini .filetype.rar,.list-view2.grid .img-precontainer-mini .filetype.zip{background:#FE9221}.list-view1.grid .img-precontainer-mini .filetype.avi,.list-view1.grid .img-precontainer-mini .filetype.mov,.list-view1.grid .img-precontainer-mini .filetype.mp4,.list-view1.grid .img-precontainer-mini .filetype.mpeg,.list-view1.grid .img-precontainer-mini .filetype.mpg,.list-view1.grid .img-precontainer-mini .filetype.webm,.list-view1.grid .img-precontainer-mini .filetype.wma,.list-view2.grid .img-precontainer-mini .filetype.avi,.list-view2.grid .img-precontainer-mini .filetype.mov,.list-view2.grid .img-precontainer-mini .filetype.mp4,.list-view2.grid .img-precontainer-mini .filetype.mpeg,.list-view2.grid .img-precontainer-mini .filetype.mpg,.list-view2.grid .img-precontainer-mini .filetype.webm,.list-view2.grid .img-precontainer-mini .filetype.wma{background:#31231E}.list-view1.grid .img-precontainer-mini .filetype.ac3,.list-view1.grid .img-precontainer-mini .filetype.aiff,.list-view1.grid .img-precontainer-mini .filetype.m4a,.list-view1.grid .img-precontainer-mini .filetype.mid,.list-view1.grid .img-precontainer-mini .filetype.mp3,.list-view1.grid .img-precontainer-mini .filetype.ogg,.list-view1.grid .img-precontainer-mini .filetype.wav,.list-view2.grid .img-precontainer-mini .filetype.ac3,.list-view2.grid .img-precontainer-mini .filetype.aiff,.list-view2.grid .img-precontainer-mini .filetype.m4a,.list-view2.grid .img-precontainer-mini .filetype.mid,.list-view2.grid .img-precontainer-mini .filetype.mp3,.list-view2.grid .img-precontainer-mini .filetype.ogg,.list-view2.grid .img-precontainer-mini .filetype.wav{background:#9F008B}.list-view1.grid .img-precontainer-mini .filetype.odb,.list-view1.grid .img-precontainer-mini .filetype.odf,.list-view1.grid .img-precontainer-mini .filetype.odg,.list-view1.grid .img-precontainer-mini .filetype.odp,.list-view1.grid .img-precontainer-mini .filetype.ods,.list-view1.grid .img-precontainer-mini .filetype.odt,.list-view1.grid .img-precontainer-mini .filetype.otg,.list-view1.grid .img-precontainer-mini .filetype.otp,.list-view1.grid .img-precontainer-mini .filetype.ots,.list-view1.grid .img-precontainer-mini .filetype.ott,.list-view2.grid .img-precontainer-mini .filetype.odb,.list-view2.grid .img-precontainer-mini .filetype.odf,.list-view2.grid .img-precontainer-mini .filetype.odg,.list-view2.grid .img-precontainer-mini .filetype.odp,.list-view2.grid .img-precontainer-mini .filetype.ods,.list-view2.grid .img-precontainer-mini .filetype.odt,.list-view2.grid .img-precontainer-mini .filetype.otg,.list-view2.grid .img-precontainer-mini .filetype.otp,.list-view2.grid .img-precontainer-mini .filetype.ots,.list-view2.grid .img-precontainer-mini .filetype.ott{background:#367BBE}.list-view1.grid .img-precontainer-mini .filetype.bmp,.list-view1.grid .img-precontainer-mini .filetype.gif,.list-view1.grid .img-precontainer-mini .filetype.jpeg,.list-view1.grid .img-precontainer-mini .filetype.jpg,.list-view1.grid .img-precontainer-mini .filetype.png,.list-view1.grid .img-precontainer-mini .filetype.svg,.list-view1.grid .img-precontainer-mini .filetype.tiff,.list-view2.grid .img-precontainer-mini .filetype.bmp,.list-view2.grid .img-precontainer-mini .filetype.gif,.list-view2.grid .img-precontainer-mini .filetype.jpeg,.list-view2.grid .img-precontainer-mini .filetype.jpg,.list-view2.grid .img-precontainer-mini .filetype.png,.list-view2.grid .img-precontainer-mini .filetype.svg,.list-view2.grid .img-precontainer-mini .filetype.tiff{background:#CFA554}.list-view1.grid .img-precontainer-mini .filetype.dmg,.list-view1.grid .img-precontainer-mini .filetype.iso,.list-view1.grid .img-precontainer-mini .filetype.log,.list-view1.grid .img-precontainer-mini .filetype.sql,.list-view1.grid .img-precontainer-mini .filetype.txt,.list-view1.grid .img-precontainer-mini .filetype.xml,.list-view2.grid .img-precontainer-mini .filetype.dmg,.list-view2.grid .img-precontainer-mini .filetype.iso,.list-view2.grid .img-precontainer-mini .filetype.log,.list-view2.grid .img-precontainer-mini .filetype.sql,.list-view2.grid .img-precontainer-mini .filetype.txt,.list-view2.grid .img-precontainer-mini .filetype.xml{background:#CACACA}.list-view1.grid .img-precontainer-mini .filetype.accdb,.list-view1.grid .img-precontainer-mini .filetype.ade,.list-view1.grid .img-precontainer-mini .filetype.adp,.list-view1.grid .img-precontainer-mini .filetype.mdb,.list-view2.grid .img-precontainer-mini .filetype.accdb,.list-view2.grid .img-precontainer-mini .filetype.ade,.list-view2.grid .img-precontainer-mini .filetype.adp,.list-view2.grid .img-precontainer-mini .filetype.mdb{background:#B61C19}.lightbox-content{overflow:hidden;padding:0;background:0 0;box-shadow:none;border-radius:0;border:0}.context-menu-list{font-family:'Open Sans',sans-serif;width:200px;background:#fff;font-size:12px;margin:0;padding:5px}.context-menu-item{background-color:#fff;position:relative;height:auto;word-wrap:break-word;-webkit-user-select:none;-moz-user-select:0;-ms-user-select:none;user-select:none;padding:5px 5px 5px 30px}.context-menu-item:last-child{border:none}.context-menu-separator{padding-bottom:0;border-bottom:1px solid #ddd}.context-menu-item.hover{background-color:#ddd}.context-menu-input.hover,.context-menu-item.disabled.hover{cursor:default;background-color:#eee}.context-menu-item.icon{vertical-align:middle;background-position:4px 5px;width:auto;display:list-item}.context-menu-item.icon-edit{background-image:url(../img/file_edit.png)}.context-menu-item.icon-cut{background-image:url(../img/cut.png)}.context-menu-item.icon-copy{background-image:url(../img/copy.png)}.context-menu-item.icon-rename{background-image:url(../img/rename.png)}.context-menu-item.icon-preview{background-image:url(../img/preview.png)}.context-menu-item.icon-dimension{background-image:url(../img/dimension.png)}.context-menu-item.icon-date{background-image:url(../img/date.png)}.context-menu-item.icon-label{background-image:url(../img/label.png)}.context-menu-item.icon-size{background-image:url(../img/size.png)}.context-menu-item.icon-download{background-image:url(../img/download.png)}.context-menu-item.icon-paste{background-image:url(../img/page_white_paste.png)}.context-menu-item.icon-clipboard-apply{background-image:url(../img/clipboard_apply.png)}.context-menu-item.icon-delete{background-image:url(../img/page_white_delete.png)}.context-menu-item.icon-add{background-image:url(../img/page_white_add.png)}.context-menu-item.icon-quit{background-image:url(../img/door.png)}.context-menu-item.icon-info{background-image:url(../img/info.png)}.context-menu-item.icon-extract{background-image:url(../img/zip.png)}.context-menu-item.icon-url{background-image:url(../img/url.png)}.context-menu-item.icon-edit_img{background-image:url(../img/edit_img.png)}.context-menu-item.icon-duplicate{background-image:url(../img/duplicate.png)}.context-menu-item.icon-key{background-image:url(../img/key.png)}.dropzone{border:1px solid rgba(0,0,0,.03);min-height:360px;border-radius:3px;background:rgba(0,0,0,.03);padding:23px}.dropzone .dz-success *{cursor:pointer!important}.dropzone .dz-default.dz-message{opacity:1;-ms-filter:none;-webkit-filter:none;filter:none;transition:opacity .3s ease-in-out;background-repeat:no-repeat;background-position:0 0;position:absolute;width:428px;height:123px;margin-left:-214px;margin-top:-61.5px;top:50%;left:50%}.btn-primary,.btn-primary.disabled,.btn-primary[disabled]{background-color:#333}.btn-primary.active,.btn-primary:active,.btn-primary:focus,.btn-primary:hover{background-color:#222} \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php new file mode 100755 index 0000000..d34ec9b --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/dialog.php @@ -0,0 +1,1262 @@ +isDir($ftp_base_folder.$upload_dir.$rfm_subfolder.$subdir)) || (!$ftp && !file_exists($current_path.$rfm_subfolder.$subdir))) { + $subdir = ''; + $rfm_subfolder = ''; +} + +if (trim($rfm_subfolder) == '') { + $cur_dir = $upload_dir.$subdir; + $cur_path = $current_path.$subdir; + $thumbs_path = $thumbs_base_path; + $parent = $subdir; +} else { + $cur_dir = $upload_dir.$rfm_subfolder.$subdir; + $cur_path = $current_path.$rfm_subfolder.$subdir; + $thumbs_path = $thumbs_base_path.$rfm_subfolder; + $parent = $rfm_subfolder.$subdir; +} + +if ($ftp) { + $cur_dir = $ftp_base_folder.$cur_dir; + $cur_path = str_replace(['/..', '..'], '', $cur_dir); + $thumbs_path = str_replace(['/..', '..'], '', $ftp_base_folder.$ftp_thumbs_dir.$rfm_subfolder); + $parent = $ftp_base_folder.$parent; +} + +if (!$ftp) { + $cycle = true; + $max_cycles = 50; + $i = 0; + while ($cycle && $i < $max_cycles) { + ++$i; + if ($parent == './') { + $parent = ''; + } + + if (file_exists($current_path.$parent.'config.php')) { + require_once $current_path.$parent.'config.php'; + $cycle = false; + } + + if ($parent == '') { + $cycle = false; + } else { + $parent = fix_dirname($parent).'/'; + } + } + + if (!is_dir($thumbs_path.$subdir)) { + create_folder(false, $thumbs_path.$subdir); + } +} +if (isset($_GET['callback'])) { + $callback = strip_tags($_GET['callback']); +} else { + $callback = 0; +} +if (isset($_GET['popup'])) { + $popup = strip_tags($_GET['popup']); +} else { + $popup = 0; +} +// Sanitize popup +$popup = (bool) $popup; + +if (isset($_GET['crossdomain'])) { + $crossdomain = strip_tags($_GET['crossdomain']); +} else { + $crossdomain = 0; +} + +// Sanitize crossdomain +$crossdomain = (bool) $crossdomain; + +// view type +if (!isset($_SESSION['RF']['view_type'])) { + $view = $default_view; + $_SESSION['RF']['view_type'] = $view; +} + +if (isset($_GET['view'])) { + $view = fix_get_params($_GET['view']); + $_SESSION['RF']['view_type'] = $view; +} + +$view = $_SESSION['RF']['view_type']; + +// filter +$filter = ''; +if (isset($_SESSION['RF']['filter'])) { + $filter = $_SESSION['RF']['filter']; +} + +if (isset($_GET['filter'])) { + $filter = fix_get_params($_GET['filter']); +} + +if (!isset($_SESSION['RF']['sort_by'])) { + $_SESSION['RF']['sort_by'] = 'name'; +} + +if (isset($_GET['sort_by'])) { + $sort_by = $_SESSION['RF']['sort_by'] = fix_get_params($_GET['sort_by']); +} else { + $sort_by = $_SESSION['RF']['sort_by']; +} + +if (!isset($_SESSION['RF']['descending'])) { + $_SESSION['RF']['descending'] = true; +} + +if (isset($_GET['descending'])) { + $descending = $_SESSION['RF']['descending'] = fix_get_params($_GET['descending']) == 1; +} else { + $descending = $_SESSION['RF']['descending']; +} + +$boolarray = [false => 'false', true => 'true']; + +$return_relative_url = isset($_GET['relative_url']) && $_GET['relative_url'] == '1' ? true : false; + +if (!isset($_GET['type'])) { + $_GET['type'] = 0; +} + +if ($_GET['type'] == 1 || $_GET['type'] == 3) { + $filter = ''; +} + +$extensions = null; +if (isset($_GET['extensions'])) { + $extensions = json_decode(urldecode($_GET['extensions'])); + if ($extensions) { + $ext = $extensions; + $show_filter_buttons = false; + } +} + +if (isset($_GET['editor'])) { + $editor = strip_tags($_GET['editor']); +} else { + if ($_GET['type'] == 0) { + $editor = false; + } else { + $editor = 'tinymce'; + } +} + +if (!isset($_GET['field_id'])) { + $_GET['field_id'] = ''; +} + +$field_id = isset($_GET['field_id']) ? fix_get_params($_GET['field_id']) : ''; +$type_param = fix_get_params($_GET['type']); + +if ($type_param == 1) { + $apply = 'apply_img'; +} elseif ($type_param == 2) { + $apply = 'apply_link'; +} elseif ($type_param == 0 && $_GET['field_id'] == '') { + $apply = 'apply_none'; +} elseif ($type_param == 3) { + $apply = 'apply_video'; +} else { + $apply = 'apply'; +} + +$get_params = [ + 'editor' => $editor, + 'type' => $type_param, + 'lang' => $lang, + 'popup' => $popup, + 'crossdomain' => $crossdomain, + 'extensions' => ($extensions) ? urlencode(json_encode($extensions)) : null, + 'field_id' => $field_id, + 'relative_url' => $return_relative_url, + 'akey' => (isset($_GET['akey']) && $_GET['akey'] != '' ? $_GET['akey'] : 'key'), +]; +if (isset($_GET['CKEditorFuncNum'])) { + $get_params['CKEditorFuncNum'] = $_GET['CKEditorFuncNum']; + $get_params['CKEditor'] = ($_GET['CKEditor'] ?? ''); +} +$get_params['fldr'] = ''; + +$get_params = http_build_query($get_params); +?> + + + + + + + + Responsive FileManager + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ +
+
+
+ + +
+

:


+ + + + + + + + + + +
+
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+ + +
+
+
+
+ +
+
+ +
+ + + +
+ +scanDir('/'.$ftp_base_folder.$upload_dir.$rfm_subfolder.$subdir); + if (!$ftp->isDir('/'.$ftp_base_folder.$ftp_thumbs_dir.$rfm_subfolder.$subdir)) { + create_folder(false, '/'.$ftp_base_folder.$ftp_thumbs_dir.$rfm_subfolder.$subdir, $ftp, $config); + } + } catch (FtpClient\FtpException $e) { + echo 'Error: '; + echo $e->getMessage(); + echo '
Please check configurations'; + exit; + } +} else { + $files = scandir($current_path.$rfm_subfolder.$subdir); +} + +$n_files = count($files); + +// php sorting +$sorted = []; +// $current_folder=array(); +// $prev_folder=array(); +$current_files_number = 0; +$current_folders_number = 0; + +foreach ($files as $k => $file) { + if ($ftp) { + $date = strtotime($file['day'].' '.$file['month'].' '.date('Y').' '.$file['time']); + $size = $file['size']; + if ($file['type'] == 'file') { + ++$current_files_number; + $file_ext = substr(strrchr($file['name'], '.'), 1); + } else { + ++$current_folders_number; + $file_ext = trans('Type_dir'); + } + $sorted[$k] = [ + 'file' => $file['name'], + 'file_lcase' => strtolower($file['name']), + 'date' => $date, + 'size' => $size, + 'permissions' => $file['permissions'], + 'extension' => strtolower($file_ext), + ]; + } else { + if ($file != '.' && $file != '..') { + if (is_dir($current_path.$rfm_subfolder.$subdir.$file)) { + $date = filemtime($current_path.$rfm_subfolder.$subdir.$file); + ++$current_folders_number; + if ($show_folder_size) { + [$size,$nfiles,$nfolders] = folder_info($current_path.$rfm_subfolder.$subdir.$file, false); + } else { + $size = 0; + } + $file_ext = trans('Type_dir'); + $sorted[$k] = [ + 'file' => $file, + 'file_lcase' => strtolower($file), + 'date' => $date, + 'size' => $size, + 'permissions' => '', + 'extension' => strtolower($file_ext), + ]; + if ($show_folder_size) { + $sorted[$k]['nfiles'] = $nfiles; + $sorted[$k]['nfolders'] = $nfolders; + } + } else { + ++$current_files_number; + $file_path = $current_path.$rfm_subfolder.$subdir.$file; + $date = filemtime($file_path); + $size = filesize($file_path); + $file_ext = substr(strrchr($file, '.'), 1); + $sorted[$k] = [ + 'file' => $file, + 'file_lcase' => strtolower($file), + 'date' => $date, + 'size' => $size, + 'permissions' => '', + 'extension' => strtolower($file_ext), + ]; + } + } + } +} + +// Should lazy loading be enabled +$lazy_loading_enabled = ($lazy_loading_file_number_threshold == 0 || $lazy_loading_file_number_threshold != -1 && $n_files > $lazy_loading_file_number_threshold) ? true : false; + +function filenameSort($x, $y) +{ + return $x['file_lcase'] < $y['file_lcase']; +} +function dateSort($x, $y) +{ + return $x['date'] < $y['date']; +} +function sizeSort($x, $y) +{ + return $x['size'] < $y['size']; +} +function extensionSort($x, $y) +{ + return $x['extension'] < $y['extension']; +} + +switch ($sort_by) { + case 'date': + usort($sorted, 'dateSort'); + break; + case 'size': + usort($sorted, 'sizeSort'); + break; + case 'extension': + usort($sorted, 'extensionSort'); + break; + default: + usort($sorted, 'filenameSort'); + break; +} + +if (!$descending) { + $sorted = array_reverse($sorted); +} + +if ($subdir != '') { + $sorted = array_merge([['file' => '..']], $sorted); +} +$files = $sorted; + +?> + + + + + + + +
+ + +
+ +
+
+ isDir($ftp_base_folder.$upload_dir.$rfm_subfolder.$subdir)) || (!$ftp && @opendir($current_path.$rfm_subfolder.$subdir) === false)) { ?> +
+
There is an error! The upload folder there isn't. Check your config.php file.
+ +

+ +
+ + + +
+
+
+
+
+
+
+
+ + + + +
    + $file_number_limit_js && $file != '..' && stripos($file, $filter) === false)) { + continue; + } + $new_name = fix_filename($file, $config); + if ($ftp && $file != '..' && $file != $new_name) { + // rename + rename_folder($current_path.$subdir.$file, $new_name, $ftp, $config); + $file = $new_name; + } + // add in thumbs folder if not exist + if ($file != '..') { + if (!$ftp && !file_exists($thumbs_path.$subdir.$file)) { + create_folder(false, $thumbs_path.$subdir.$file, $ftp, $config); + } + } + + $class_ext = 3; + if ($file == '..' && trim($subdir) != '') { + $src = explode('/', $subdir); + unset($src[count($src) - 2]); + $src = implode('/', $src); + if ($src == '') { + $src = '/'; + } + } elseif ($file != '..') { + $src = $subdir.$file.'/'; + } ?> + + $file_array) { + $file = $file_array['file']; + + if ($file == '.' || $file == '..' || $file_array['extension'] == trans('Type_dir') || in_array($file, $hidden_files) || !in_array(fix_strtolower($file_array['extension']), $ext) || ($filter != '' && $n_files > $file_number_limit_js && stripos($file, $filter) === false)) { + continue; + } + $filename = substr($file, 0, '-'.(strlen($file_array['extension']) + 1)); + if (!$ftp) { + $file_path = $current_path.$rfm_subfolder.$subdir.$file; + // check if file have illegal caracter + + if ($file != fix_filename($file, $config)) { + $file1 = fix_filename($file, $config); + $file_path1 = ($current_path.$rfm_subfolder.$subdir.$file1); + if (file_exists($file_path1)) { + $i = 1; + $info = pathinfo($file1); + while (file_exists($current_path.$rfm_subfolder.$subdir.$info['filename'].'.['.$i.'].'.$info['extension'])) { + ++$i; + } + $file1 = $info['filename'].'.['.$i.'].'.$info['extension']; + $file_path1 = ($current_path.$rfm_subfolder.$subdir.$file1); + } + + $filename = substr($file1, 0, '-'.(strlen($file_array['extension']) + 1)); + rename_file($file_path, fix_filename($filename, $config), $ftp, $config); + $file = $file1; + $file_array['extension'] = fix_filename($file_array['extension'], $config); + $file_path = $file_path1; + } + } else { + $file_path = $config['ftp_base_url'].$upload_dir.$rfm_subfolder.$subdir.$file; + } + + $is_img = false; + $is_video = false; + $is_audio = false; + $show_original = false; + $show_original_mini = false; + $mini_src = ''; + $src_thumb = ''; + if (in_array($file_array['extension'], $ext_img)) { + $src = $base_url.$cur_dir.$file; + $is_img = true; + + $img_width = $img_height = ''; + if ($ftp) { + $mini_src = $src_thumb = $config['ftp_base_url'].$ftp_thumbs_dir.$subdir.$file; + $creation_thumb_path = '/'.$config['ftp_base_folder'].$ftp_thumbs_dir.$subdir.$file; + } else { + $creation_thumb_path = $mini_src = $src_thumb = $thumbs_path.$subdir.$file; + + if (!file_exists($src_thumb)) { + if (!create_img($file_path, $creation_thumb_path, 122, 91, 'crop', $ftp, $config)) { + $src_thumb = $mini_src = ''; + } else { + new_thumbnails_creation($current_path.$rfm_subfolder.$subdir, $file_path, $file, $current_path, '', '', '', '', '', '', '', $fixed_image_creation, $fixed_path_from_filemanager, $fixed_image_creation_name_to_prepend, $fixed_image_creation_to_append, $fixed_image_creation_width, $fixed_image_creation_height, $fixed_image_creation_option); + } + } + // check if is smaller than thumb + [$img_width, $img_height, $img_type, $attr] = @getimagesize($file_path); + if ($img_width < 122 && $img_height < 91) { + $src_thumb = $file_path; + $show_original = true; + } + + if ($img_width < 45 && $img_height < 38) { + $mini_src = $current_path.$rfm_subfolder.$subdir.$file; + $show_original_mini = true; + } + } + } + $is_icon_thumb = false; + $is_icon_thumb_mini = false; + $no_thumb = false; + if ($src_thumb == '') { + $no_thumb = true; + if (file_exists('img/'.$icon_theme.'/'.$file_array['extension'].'.jpg')) { + $src_thumb = 'img/'.$icon_theme.'/'.$file_array['extension'].'.jpg'; + } else { + $src_thumb = 'img/'.$icon_theme.'/default.jpg'; + } + $is_icon_thumb = true; + } else { + $src_thumb = $base_url.$thumbs_dir.$subdir.$file; + } + if ($mini_src == '') { + $is_icon_thumb_mini = false; + } else { + $mini_src = $src_thumb; + } + + $class_ext = 0; + if (in_array($file_array['extension'], $ext_video)) { + $class_ext = 4; + $is_video = true; + } elseif (in_array($file_array['extension'], $ext_img)) { + $class_ext = 2; + } elseif (in_array($file_array['extension'], $ext_music)) { + $class_ext = 5; + $is_audio = true; + } elseif (in_array($file_array['extension'], $ext_misc)) { + $class_ext = 3; + } else { + $class_ext = 1; + } + if ((!($_GET['type'] == 1 && !$is_img) && !(($_GET['type'] == 3 && !$is_video) && ($_GET['type'] == 3 && !$is_audio))) && $class_ext > 0) { + ?> + +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/execute.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/execute.php new file mode 100755 index 0000000..703c62b --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/execute.php @@ -0,0 +1,505 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$config = include 'config/config.php'; +// TODO switch to array +extract($config, \EXTR_OVERWRITE); + +include 'include/utils.php'; + +if ($_SESSION['RF']['verify'] != 'RESPONSIVEfilemanager') { + response(trans('forbiden').AddErrorLocation())->send(); + exit; +} + +if (strpos($_POST['path'], '/') === 0 + || strpos($_POST['path'], '../') !== false + || strpos($_POST['path'], './') === 0 + || strpos($_POST['path'], '..\\') !== false + || strpos($_POST['path'], '.\\') === 0) { + response(trans('wrong path'.AddErrorLocation()))->send(); + exit; +} + +if (isset($_SESSION['RF']['language']) && file_exists('lang/'.basename($_SESSION['RF']['language']).'.php')) { + $languages = include 'lang/languages.php'; + if (array_key_exists($_SESSION['RF']['language'], $languages)) { + include 'lang/'.basename($_SESSION['RF']['language']).'.php'; + } else { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; + } +} else { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; +} + +$ftp = ftp_con($config); + +$base = $current_path; +$path = $base.$_POST['path']; +$cycle = true; +$max_cycles = 50; +$i = 0; +while ($cycle && $i < $max_cycles) { + ++$i; + if ($path == $base) { + $cycle = false; + } + + if (file_exists($path.'config.php')) { + require_once $path.'config.php'; + $cycle = false; + } + $path = fix_dirname($path).'/'; +} + +$path = $current_path.$_POST['path']; +$path_thumb = $thumbs_base_path.$_POST['path']; + +if ($ftp) { + $path = $ftp_base_folder.$upload_dir.$_POST['path']; + $path_thumb = $ftp_base_folder.$ftp_thumbs_dir.$_POST['path']; +} + +if (isset($_POST['name'])) { + $name = fix_filename($_POST['name'], $config); + if (strpos($name, '../') !== false || strpos($name, '..\\') !== false) { + response(trans('wrong name').AddErrorLocation())->send(); + exit; + } +} + +$info = pathinfo($path); +if (isset($info['extension']) && !(isset($_GET['action']) && $_GET['action'] == 'delete_folder') && !in_array(strtolower($info['extension']), $ext) && $_GET['action'] != 'create_file') { + response(trans('wrong extension').AddErrorLocation())->send(); + exit; +} + +if (isset($_GET['action'])) { + switch ($_GET['action']) { + case 'delete_file': + if ($delete_files) { + if ($ftp) { + try { + $ftp->delete('/'.$path); + @$ftp->delete('/'.$path_thumb); + } catch (FtpClient\FtpException $e) { + return; + } + } else { + unlink($path); + if (file_exists($path_thumb)) { + unlink($path_thumb); + } + } + + $info = pathinfo($path); + if (!$ftp && $relative_image_creation) { + foreach ($relative_path_from_current_pos as $k => $path) { + if ($path != '' && $path[strlen($path) - 1] != '/') { + $path .= '/'; + } + + if (file_exists($info['dirname'].'/'.$path.$relative_image_creation_name_to_prepend[$k].$info['filename'].$relative_image_creation_name_to_append[$k].'.'.$info['extension'])) { + unlink($info['dirname'].'/'.$path.$relative_image_creation_name_to_prepend[$k].$info['filename'].$relative_image_creation_name_to_append[$k].'.'.$info['extension']); + } + } + } + + if (!$ftp && $fixed_image_creation) { + foreach ($fixed_path_from_filemanager as $k => $path) { + if ($path != '' && $path[strlen($path) - 1] != '/') { + $path .= '/'; + } + + $base_dir = $path.substr_replace($info['dirname'].'/', '', 0, strlen($current_path)); + if (file_exists($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'])) { + unlink($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension']); + } + } + } + } + break; + case 'delete_folder': + if ($delete_folders) { + if ($ftp) { + deleteDir($path, $ftp, $config); + deleteDir($path_thumb, $ftp, $config); + } else { + if (is_dir($path_thumb)) { + deleteDir($path_thumb); + } + + if (is_dir($path)) { + deleteDir($path); + if ($fixed_image_creation) { + foreach ($fixed_path_from_filemanager as $k => $paths) { + if ($paths != '' && $paths[strlen($paths) - 1] != '/') { + $paths .= '/'; + } + + $base_dir = $paths.substr_replace($path, '', 0, strlen($current_path)); + if (is_dir($base_dir)) { + deleteDir($base_dir); + } + } + } + } + } + } + break; + case 'create_folder': + if ($create_folders) { + $name = fix_filename($_POST['name'], $config); + $path .= $name; + $path_thumb .= $name; + create_folder(fix_path($path, $config), fix_path($path_thumb, $config), $ftp, $config); + } + break; + case 'rename_folder': + if ($rename_folders) { + $name = fix_filename($name, $config); + $name = str_replace('.', '', $name); + + if (!empty($name)) { + if (!rename_folder($path, $name, $ftp, $config)) { + response(trans('Rename_existing_folder').AddErrorLocation())->send(); + exit; + } + rename_folder($path_thumb, $name, $ftp, $config); + if (!$ftp && $fixed_image_creation) { + foreach ($fixed_path_from_filemanager as $k => $paths) { + if ($paths != '' && $paths[strlen($paths) - 1] != '/') { + $paths .= '/'; + } + + $base_dir = $paths.substr_replace($path, '', 0, strlen($current_path)); + rename_folder($base_dir, $name, $ftp, $config); + } + } + } else { + response(trans('Empty_name').AddErrorLocation())->send(); + exit; + } + } + break; + case 'create_file': + if ($create_text_files === false) { + response(sprintf(trans('File_Open_Edit_Not_Allowed'), strtolower(trans('Edit'))).AddErrorLocation())->send(); + exit; + } + + if (!isset($editable_text_file_exts) || !is_array($editable_text_file_exts)) { + $editable_text_file_exts = []; + } + + // check if user supplied extension + if (strpos($name, '.') === false) { + response(trans('No_Extension').' '.sprintf(trans('Valid_Extensions'), implode(', ', $editable_text_file_exts)).AddErrorLocation())->send(); + exit; + } + + // correct name + $old_name = $name; + $name = fix_filename($name, $config); + if (empty($name)) { + response(trans('Empty_name').AddErrorLocation())->send(); + exit; + } + + // check extension + $parts = explode('.', $name); + if (!in_array(end($parts), $editable_text_file_exts)) { + response(trans('Error_extension').' '.sprintf(trans('Valid_Extensions'), implode(', ', $editable_text_file_exts)), 400)->send(); + exit; + } + + $content = $_POST['new_content']; + + if ($ftp) { + $tmp = time().$name; + file_put_contents($tmp, $content); + $ftp->put('/'.$path.$name, $tmp, \FTP_BINARY); + unlink($tmp); + response(trans('File_Save_OK'))->send(); + } else { + if (!checkresultingsize(strlen($content))) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + // file already exists + if (file_exists($path.$name)) { + response(trans('Rename_existing_file').AddErrorLocation())->send(); + exit; + } + + if (@file_put_contents($path.$name, $content) === false) { + response(trans('File_Save_Error').AddErrorLocation())->send(); + exit; + } + if (is_function_callable('chmod') !== false) { + chmod($path.$name, 0644); + } + response(trans('File_Save_OK'))->send(); + exit; + } + + break; + case 'rename_file': + if ($rename_files) { + $name = fix_filename($name, $config); + if (!empty($name)) { + if (!rename_file($path, $name, $ftp, $config)) { + response(trans('Rename_existing_file').AddErrorLocation())->send(); + exit; + } + + rename_file($path_thumb, $name, $ftp, $config); + + if ($fixed_image_creation) { + $info = pathinfo($path); + + foreach ($fixed_path_from_filemanager as $k => $paths) { + if ($paths != '' && $paths[strlen($paths) - 1] != '/') { + $paths .= '/'; + } + + $base_dir = $paths.substr_replace($info['dirname'].'/', '', 0, strlen($current_path)); + if (file_exists($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'])) { + rename_file($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'], $fixed_image_creation_name_to_prepend[$k].$name.$fixed_image_creation_to_append[$k], $ftp, $config); + } + } + } + } else { + response(trans('Empty_name').AddErrorLocation())->send(); + exit; + } + } + break; + case 'duplicate_file': + if ($duplicate_files) { + $name = fix_filename($name, $config); + if (!empty($name)) { + if (!$ftp && !checkresultingsize(filesize($path))) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + if (!duplicate_file($path, $name, $ftp, $config)) { + response(trans('Rename_existing_file').AddErrorLocation())->send(); + exit; + } + + duplicate_file($path_thumb, $name, $ftp, $config); + + if (!$ftp && $fixed_image_creation) { + $info = pathinfo($path); + foreach ($fixed_path_from_filemanager as $k => $paths) { + if ($paths != '' && $paths[strlen($paths) - 1] != '/') { + $paths .= '/'; + } + + $base_dir = $paths.substr_replace($info['dirname'].'/', '', 0, strlen($current_path)); + + if (file_exists($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'])) { + duplicate_file($base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'], $fixed_image_creation_name_to_prepend[$k].$name.$fixed_image_creation_to_append[$k]); + } + } + } + } else { + response(trans('Empty_name').AddErrorLocation())->send(); + exit; + } + } + break; + case 'paste_clipboard': + if (!isset($_SESSION['RF']['clipboard_action'], $_SESSION['RF']['clipboard']['path']) + || $_SESSION['RF']['clipboard_action'] == '' + || $_SESSION['RF']['clipboard']['path'] == '') { + response()->send(); + exit; + } + + $action = $_SESSION['RF']['clipboard_action']; + $data = $_SESSION['RF']['clipboard']; + + if ($ftp) { + if ($_POST['path'] != '') { + $path .= \DIRECTORY_SEPARATOR; + $path_thumb .= \DIRECTORY_SEPARATOR; + } + $path_thumb .= basename($data['path']); + $path .= basename($data['path']); + $data['path_thumb'] = \DIRECTORY_SEPARATOR.$config['ftp_base_folder'].$config['ftp_thumbs_dir'].$data['path']; + $data['path'] = \DIRECTORY_SEPARATOR.$config['ftp_base_folder'].$config['upload_dir'].$data['path']; + } else { + $data['path_thumb'] = $thumbs_base_path.$data['path']; + $data['path'] = $current_path.$data['path']; + } + + $pinfo = pathinfo($data['path']); + + // user wants to paste to the same dir. nothing to do here... + if ($pinfo['dirname'] == rtrim($path, \DIRECTORY_SEPARATOR)) { + response()->send(); + exit; + } + + // user wants to paste folder to it's own sub folder.. baaaah. + if (is_dir($data['path']) && strpos($path, $data['path']) !== false) { + response()->send(); + exit; + } + + // something terribly gone wrong + if ($action != 'copy' && $action != 'cut') { + response(trans('wrong action').AddErrorLocation())->send(); + exit; + } + if ($ftp) { + if ($action == 'copy') { + $tmp = time().basename($data['path']); + $ftp->get($tmp, $data['path'], \FTP_BINARY); + $ftp->put(\DIRECTORY_SEPARATOR.$path, $tmp, \FTP_BINARY); + unlink($tmp); + + if (url_exists($data['path_thumb'])) { + $tmp = time().basename($data['path_thumb']); + @$ftp->get($tmp, $data['path_thumb'], \FTP_BINARY); + @$ftp->put(\DIRECTORY_SEPARATOR.$path_thumb, $tmp, \FTP_BINARY); + unlink($tmp); + } + } elseif ($action == 'cut') { + $ftp->rename($data['path'], \DIRECTORY_SEPARATOR.$path); + if (url_exists($data['path_thumb'])) { + @$ftp->rename($data['path_thumb'], \DIRECTORY_SEPARATOR.$path_thumb); + } + } + } else { + // check for writability + if (is_really_writable($path) === false || is_really_writable($path_thumb) === false) { + response(trans('Dir_No_Write').'
'.str_replace('../', '', $path).'
'.str_replace('../', '', $path_thumb).AddErrorLocation())->send(); + exit; + } + + // check if server disables copy or rename + if (is_function_callable($action == 'copy' ? 'copy' : 'rename') === false) { + response(sprintf(trans('Function_Disabled'), $action == 'copy' ? (trans('Copy')) : (trans('Cut'))).AddErrorLocation())->send(); + exit; + } + if ($action == 'copy') { + [$sizeFolderToCopy,$fileNum,$foldersCount] = folder_info($path, false); + if (!checkresultingsize($sizeFolderToCopy)) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + rcopy($data['path'], $path); + rcopy($data['path_thumb'], $path_thumb); + } elseif ($action == 'cut') { + rrename($data['path'], $path); + rrename($data['path_thumb'], $path_thumb); + + // cleanup + if (is_dir($data['path']) === true) { + rrename_after_cleaner($data['path']); + rrename_after_cleaner($data['path_thumb']); + } + } + } + + // cleanup + $_SESSION['RF']['clipboard']['path'] = null; + $_SESSION['RF']['clipboard_action'] = null; + + break; + case 'chmod': + $mode = $_POST['new_mode']; + $rec_option = $_POST['is_recursive']; + $valid_options = ['none', 'files', 'folders', 'both']; + $chmod_perm = ($_POST['folder'] ? $chmod_dirs : $chmod_files); + + // check perm + if ($chmod_perm === false) { + response(sprintf(trans('File_Permission_Not_Allowed'), is_dir($path) ? (trans('Folders')) : (trans('Files'))).AddErrorLocation())->send(); + exit; + } + // check mode + if (!preg_match('/^[0-7]{3}$/', $mode)) { + response(trans('File_Permission_Wrong_Mode').AddErrorLocation())->send(); + exit; + } + // check recursive option + if (!in_array($rec_option, $valid_options)) { + response(trans('wrong option').AddErrorLocation())->send(); + exit; + } + // check if server disabled chmod + if (!$ftp && is_function_callable('chmod') === false) { + response(sprintf(trans('Function_Disabled'), 'chmod').AddErrorLocation())->send(); + exit; + } + + $mode = '0'.$mode; + $mode = octdec($mode); + if ($ftp) { + $ftp->chmod($mode, '/'.$path); + } else { + rchmod($path, $mode, $rec_option); + } + + break; + case 'save_text_file': + $content = $_POST['new_content']; + // $content = htmlspecialchars($content); not needed + // $content = stripslashes($content); + + if ($ftp) { + $tmp = time(); + file_put_contents($tmp, $content); + try { + $ftp->put('/'.$path, $tmp, \FTP_BINARY); + } catch (FtpClient\FtpException $e) { + echo $e->getMessage(); + } + unlink($tmp); + response(trans('File_Save_OK'))->send(); + } else { + // no file + if (!file_exists($path)) { + response(trans('File_Not_Found').AddErrorLocation())->send(); + exit; + } + + // not writable or edit not allowed + if (!is_writable($path) || $edit_text_files === false) { + response(sprintf(trans('File_Open_Edit_Not_Allowed'), strtolower(trans('Edit'))).AddErrorLocation())->send(); + exit; + } + + if (!checkresultingsize(strlen($content))) { + response(sprintf(trans('max_size_reached'), $MaxSizeTotal).AddErrorLocation())->send(); + exit; + } + if (@file_put_contents($path, $content) === false) { + response(trans('File_Save_Error').AddErrorLocation())->send(); + exit; + } + response(trans('File_Save_OK'))->send(); + exit; + } + + break; + default: + response(trans('wrong action').AddErrorLocation())->send(); + exit; + } +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/force_download.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/force_download.php new file mode 100755 index 0000000..fde5e83 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/force_download.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$config = include 'config/config.php'; + +// TODO switch to array +extract($config, \EXTR_OVERWRITE); + +include 'include/utils.php'; + +$ftp = ftp_con($config); + +if ($_SESSION['RF']['verify'] != 'RESPONSIVEfilemanager') { + response(trans('forbiden').AddErrorLocation(), 403)->send(); + exit; +} + +include 'include/mime_type_lib.php'; + +if ( + strpos($_POST['path'], '/') === 0 + || strpos($_POST['path'], '../') !== false + || strpos($_POST['path'], './') === 0 + || strpos($_POST['path'], '..\\') !== false + || strpos($_POST['path'], '.\\') === 0 +) { + response(trans('wrong path'.AddErrorLocation()), 400)->send(); + exit; +} + +if (strpos($_POST['name'], '/') !== false) { + response(trans('wrong path'.AddErrorLocation()), 400)->send(); + exit; +} +if ($ftp) { + $path = $ftp_base_url.$upload_dir.$_POST['path']; +} else { + $path = $current_path.$_POST['path']; +} + +$name = $_POST['name']; + +$info = pathinfo($name); + +if (!in_array(fix_strtolower($info['extension']), $ext)) { + response(trans('wrong extension'.AddErrorLocation()), 400)->send(); + exit; +} + +$file_name = $info['basename']; +$file_ext = $info['extension']; +$file_path = $path.$name; + +// make sure the file exists +if ($ftp) { + $file_url = 'http://www.myremoteserver.com/file.exe'; + header('Content-Type: application/octet-stream'); + header('Content-Transfer-Encoding: Binary'); + header('Content-disposition: attachment; filename="'.$file_name.'"'); + readfile($file_path); +} elseif (is_file($file_path) && is_readable($file_path)) { + if (!file_exists($path.$name)) { + response(trans('File_Not_Found'.AddErrorLocation()), 404)->send(); + exit; + } + + $size = filesize($file_path); + $file_name = rawurldecode($file_name); + if (function_exists('mime_content_type')) { + $mime_type = mime_content_type($file_path); + } elseif (function_exists('finfo_open')) { + $finfo = finfo_open(\FILEINFO_MIME_TYPE); + $mime_type = finfo_file($finfo, $file_path); + } else { + include 'include/mime_type_lib.php'; + $mime_type = get_file_mime_type($file_path); + } + + @ob_end_clean(); + if (ini_get('zlib.output_compression')) { + ini_set('zlib.output_compression', 'Off'); + } + header('Content-Type: '.$mime_type); + header('Content-Disposition: attachment; filename="'.$file_name.'"'); + header('Content-Transfer-Encoding: binary'); + header('Accept-Ranges: bytes'); + + if (isset($_SERVER['HTTP_RANGE'])) { + [$a, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); + [$range] = explode(',', $range, 2); + [$range, $range_end] = explode('-', $range); + $range = (int) $range; + if (!$range_end) { + $range_end = $size - 1; + } else { + $range_end = (int) $range_end; + } + + $new_length = $range_end - $range + 1; + header('HTTP/1.1 206 Partial Content'); + header("Content-Length: $new_length"); + header("Content-Range: bytes $range-$range_end/$size"); + } else { + $new_length = $size; + header('Content-Length: '.$size); + } + + $chunksize = 1 * (1024 * 1024); + $bytes_send = 0; + if ($file = fopen($file_path, 'r')) { + if (isset($_SERVER['HTTP_RANGE'])) { + fseek($file, $range); + } + + while (!feof($file) && + (!connection_aborted()) && + ($bytes_send < $new_length) + ) { + $buffer = fread($file, $chunksize); + echo $buffer; + flush(); + $bytes_send += strlen($buffer); + } + fclose($file); + } else { + exit('Error - can not open file.'); + } + + exit; +} else { + // file does not exist + header('HTTP/1.0 404 Not Found'); + exit; +} + +exit; diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_apply.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_apply.png new file mode 100644 index 0000000000000000000000000000000000000000..d470c4434ba88711588dbca8762cfc42e1781759 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPHV5AX?bRZ~;@|NlRbgn;N1pN{~g zSW1HYf*BZQo@qRE6QnfK)5S5QBF^;WL*51jo|cQs77YuyCm1kzS~py}U9T2><-Pmo zB3I3)5_K}{mQ1zE>t_a-{!ZdmfB3P?#r{dNBlDq+2?8m43{nq1Bp#f!Z-GI;)On_F cYz;0mA2Akl@XGwZ31|s}r>mdKI;Vst00Uz{t^fc4 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_clear.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/clipboard_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..e7fb9031bbaae2e99b053798a1a674cac64bf0b6 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPE^3h)VW6&4m&Q&ao@|38p~fZcD7 zumELQOM?7@f%MEXAFOs(0vXYsE{-7;alU5{avm_?V7;(r!41Z&ORQWwuQz|c^y1&@ zD=r#;*(*CfaT}X=3TC{!?sEUm`^KeOM~|H=vT*ssc}8c(EIkfRRR$rp1)NV>6fT$l ksbBwU;))x;j~o#Hxm@;>+u}8OKx-I0UHx3vIVCg!0Ckf|LI3~& literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/copy.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d89116d3fb4a7fb0874d9ab6d5f5b502d44f3b GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDURZ~+lHa7kb0}>Jvl9G}T zQd3h?OH0eh$OxzaC<0O0o?5R3)XQ5EiYG43ltY(aU2^428 z3GxeOn0e-edbJpk>+9*_7*Y|(du$_bgMx_bMQx+R8w2xS*Dn3Pe^z z1Ef+_RTanpiU0wS0n`NnKyg(KRj@FSR0RqG1t3yDE)W2vAc7ECAP>R-3c?v`AVD|+ zYJsqU=0J>sGJxVh7iw#3ZROYc2lTLiNswPK10xd)D;ql}7Z)#|kg$lTgrtmuqLQ+T zimIBrhM|e6rInq%qmyrHc1~_?US57tSwmw}OG{gS|CBlN<}X-!{^G@pmu}v=cmLs| zM=xHz{w*nQ`Uq(B1y2{pkcv3p?(2L_0U|8o(p?2>6}tA8vx>gqU3%mH|Lm6E33E~= zO+G1C(R1A1HcR_)ir(~P?{7wg7T#U`Ebw~&zGb`i9}qNn#b|qBIn}b0!^kX$^H;i)T>p_Li=96;b^Ka$rfhdkWmvn1b8=wf@4peL7Z*4- zeUlTqu6lU8Tl^-EsU905cqRpLMedrh&+5;^1LbkSyCz(`XS(yJ&AmI@6mM^s^g}uG w;XN;HFS~G!C!e||<=x#_X|-McT=8Gl&qtMB9C>mi3zSeiUHx3vIVCg!0Ev;nq5uE@ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/dimension.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/dimension.png new file mode 100755 index 0000000000000000000000000000000000000000..43dcc10155703666c47b845df93feebcf8b7d21d GIT binary patch literal 489 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfx&WUL*Z=?j1DQhw>^s?#0(7fo zNswPK1EUCwa_H~-z48IayIMMa-ae;rEB4m~Pw69uPd=)>z03OLp0WQ2lkmrvF5Wry zprN%b#9TNk@|aoo>K98yfQD@Jba4!+hzsq%I_anZkMq?fo~O=KOiYyg^xuBl<9mD7 z#OutJ?9I6lap3joO$mQaUA*|H3Gcx%1wQ2QuH%bW2&>r(gcV@;M}nonz|r-6DniZAF9D zTEvunv$(bU^ux1P;?8gX{kLpi(A&=&$~WHcmUollww$-bMz%LTh<~m8|9eOC6aL80 XKF#xG&C|*bP;7a+`njxgN@xNAsIHRv literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/down.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/down.png new file mode 100644 index 0000000000000000000000000000000000000000..76511223d957dd488561ac4eefda6f5ef835ba26 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^93afX3?$7I7w-U4asfUeuK)l42QqPiwjPVMKsnBm zAirP+rY>g1X2!~vUXj&uKtXL!7srr_xa0(55x)cmX7#HIqHGIi8jDIwXe~E3kSH)Q hFg7qU;9w9`W@gA?V!2g*uIVJm9#2<4mvv4FO#u5cAhQ4f literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/download.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/download.png new file mode 100755 index 0000000000000000000000000000000000000000..76125f22a6e94ecc3c4b53e6b6d009ee4793fb44 GIT binary patch literal 674 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47gs@Y0R@59Nl8foy#SFiGBN_{va+)B z_xHEAw+Gtm=;#P^2GB-i0CXzQVX6<(dw{{0R1)MD%wW!cc_L@c=~rA+_-b1ouddEN z^SE2J_Q{?8rRJJbZ@Bg=?n!3uyW@Z5lQvLu@S#mub?^WrjHws??gV1OwTZ} zE}f;U>FZy*9ljOG>wG<+;qO8DgiiY=-XFWQ8yxiyDr;J|e&~G6qcFW+#JkWsPRs3+ zWy9MI0jnRI#jO`TC*JVSNXmGp`?((1`STc!ZmznOwQjcV)>&s65=8s2hucl9jq_)9 zUXY+sQ(RsCUx1Hw?(&m^S3j3^P6&1*lQb>=It(xb?# zTVA{5J9AqnAHNxz_)cDCQk95(=h2{7KV4Y@%VzH0x083ryJG&9<6nyJRDP_!7gQuw i@&Ci$pTGVcblM-YNUrbm`%77%F!pryb6Mw<&;$T*ORLua literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/file_edit.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/file_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..4bcd072e9f7e228d3452973b7c0e9e76a9543a96 GIT binary patch literal 764 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pn}NEkcg59UmvUF{9L`nl>DSry^7odplSvNn+hu+GdHy)QK2F?C$HG5 z!d3~a!V1U+3F|8Y3;nDA{o-C@9zzrKDK}xwt{K19`Se z86_nJR{Hwo<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9O-#x!EwNQn0$BtH5O0c3d|4@L;p!@;Rg)2@GT#PZ!4!3&E+A z_j?_25NO~0Gx@dXJPt9ju8yXtj*g{ME8ahteWyAmb9vlT;~O__{bXo*oA_|Cz(HTWyN0mrWR^{QFrF_gkVo!0^< zI|{#HT*AGwX7cl&mLELBZ#WpPjAFkNP@!p-xypwBJj1uy3DxsI&VBxH45svE7W|_kWesGo$TRwW@yq=frGs zNiXHr+VXXl0e^Lx^eo~%eJ1(tHrpVj!>G%r%)HX(!N*-{w;D`i?#LWaweR{P^F1}v kZt|xlHID~Ee|Oa}%-oR7{dOvA5hzJ|y85}Sb4q9e0O7eBumAu6 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings-white.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings-white.png new file mode 100755 index 0000000000000000000000000000000000000000..a92969a174c8ed385127cbdf5f836b539cc88170 GIT binary patch literal 8583 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/glyphicons-halflings.png new file mode 100755 index 0000000000000000000000000000000000000000..f43139a488fa35166c45f8f760fa6842cc82826c GIT binary patch literal 15602 zcmb`uRa6{J_%}!(xLbm|OR(TF!QF;|V8JE0y9Rf64Gx0^4+#!IgC)2V+;$t83=^bU_ph=&5w>5EKGG8G<8fe?WJ&Vp zFtd*QB~hZw_&`7aj*v0S-mg|Ll8+Vah}M4KAk1ew(w2AbOOjL>WJvE&vQaU4Ql+oD zwSID+e5&(X)$3f`TXTaLL9b6dHE*W(3fxXbpfydm4-kF7{GUsMLqp3%7~xVy8t(^( zBp?mX-Unrw31o3RahGnk&*ND!tdBFkNQ6l|9#iSO`qJl%v=rAMJx@sUQ=`R5w~^a8zj=JHo3mr-ze5J!Ma#_iPcFZR&E0l? zljaIK8J&>v(5^t`r<2L0Q;sbUUoGq-?L=N^34}V}Fg;|MDC3c=l2(bI2 z?Ed{cO|&pgflOBQlThd@~E3 zs4MYe#BxD#DO;C3`Oi}tZQ-@^PWs2W0_u1!d-KBTHlmIBxX!oz>_gV$IUa`K@tL+> zz0dS#XQ$Q=KtDb+%djP?ze1TZ=!JI!%ui%sjo%9A8?@$7$O)(oFUmiEEC{ zzq6ZpEcEd9ojGEi4RR( z>gvU`3R^m({T@g+msYf~@YH0#*x1&{v?|23Q!5br=ezN-nD_a{YMw59Z3r=y3H|=Y zQO(7ZCEF-XY>U#b2VITX^M30QH6>uqv=F5$T=Z{+uJJ9W{`IPrTny4)Bo>*MOTGfR zO#C8+u{)QDbK|x-9TROg7Lbvv8NUj{59|k~mo14@D{ij}{EJ@|!mbaz9LG07qlu<>CMgXjN#>J1zc*iIkS z=(ikJ%PJ7>p{_{p>`#{%)9v!V zck!RkJV9nOGwE9xlJKVAl9dp;HyLQ?QPV711o3Tjph-zF9~rkfu3}0oE;va8@_8=j zYxJ(vbuq2ZD!d&ztsc6H|PmfeXQad7$iqUJ0^p}~(LBGd*`%Vn?--Pt3&jfoesCxGBt4~CC z=~=F|4|dS*vGDVsjlZd~V27#{9DiO`nDDjlAm2kHf7G6EgPC(qKzC#5g}q8HDk>^I zWM7sS$){$!Xz6vNQ68ZyZkFoK1)Ymg&6C&h!UbvJqiU|eNs@OL!@Bp37rms(!Jo2a z#vSYNxiYa?xoD-L0^7sm^{TFNTc%I-8d3$H_$X7EK!tlpbqx^_sN#?cId33@xg~(_ zK^z+2QUfpLE*kn@sZ$RJ#-F`DSKqyp-&+Ibc71ogh+JL?n)| z!ZXU<#(UBh>aZVAc^dft$~3sc{q=TD>cu~Dyl2ez8ETevFl2ScD}XORKaxn7{OH#bCFhcs!hp9z zzb7X`cGDh`s8PN~Rjo|~)5>IYJe(FKd)IC3c@6)3hXto@V+#v=gBzRw#I@}7#r310-e7+x~vwx&&Q{>>82QPSt=J4Q>xNFJrd2|#5iZ=*s z-%Dk@|(e<11usYF|bz!xnK(PX*H zl2?ee^zcb3462M@6#qq%(MNzUjry!XaFscqXva?*&0(?CVR=Uu)#6KLkU6TAXyZIL zW{aLZP!2g3!meH**1lG3`IHjv1=TUr?Y~;&E7sxVPOmm+`Wqp0HJB>D={Uy*@w=Rpl8_a>0;BKTS@@h zgDgRL0M}h{H<1nJLp6R8_P?fTz0~XFynOEy`e~DNxybx*Plcney`62CDz?Cp`Zoih zq;)2t!ScU;;FF9E{eZaE99VLSv1!3-u!kob;>p!bq1-w+3uV1hROB#syKhOcxW_dv$irVmN@RJnq%S|FB@P9X1s^E{oo0o$B zyZJw@Vssd^*?4RJyF?cP(zN*n%80K0{%@3sbvSQJ#H$FD%*ihp<4}c;I2xn59KRBP z5P-w!yrS|^OA)}jQ_`o}lw#hX?KwJ=m>zG}A#=$%n7bU9;xx9GpG?smQnqfpu@#L3 zt%#8fuPbtcV#(cIX*2w7Z^Ko(QGYktS?))1PQaEfOvqxXBd^1c$$D?`o}2VT6&*+q z0S+yM-YEOaO}y1r9qdO4804u^qXS)(fMBH=PKUHl0ZoT2JmFK!%7F55b5BIkn2QW0 z31a&UitZF`+o?eC-6kTG5v!i@wB zBZD`1&Cs3WLm>Hcox!KbvoQuxFIf?`qP9{O51CU5VTpZm?Ot@utI&l(2?Ok>lPtR| z-~2O;<@tK!XW8J{OaF>=MgEpR;8?}Ky)9B=I_KYbXU65lft7EpeqT8<0a^k4e*$Wz z5mgp@l&j)fVY910y#OryI0_N0TV7NQ*k5&6#C(sm3!<}UlAbi*KQ1(ww)&4q5a868Bb96etYa()E?8F;XLXdmAJZ zE}e-}kftrgYw4jl7l2Y2*+WOuw!s;fe%GY4W%#UFOj?sbO5l%D#q^_)!?To+q`s8i zop)WeqD$fu4HopRKV7i)1|k|S0@x@{QwqXhE<2&e8>`CrVEL!}cDKE?7_uMb^YD96iwT=w!{2ZlLeizZIn%) zB~nqG)!0*PGXlRqlEA)S@}R}<;hc3!(3o$ho@R0xKPk-#3t36`Br5Eq^4X|Or98My ziBjpsHh+2aM8B8VO53bLA?5rDF*v)*tIQ85X*f~G{~-W-oTLfA81#^57ed_|tRcO` z6TUr1u#d#E%kZZ#cuA>N>+C?gg1Sd+a)HO;{p|`-uhR};ci{06-@9Isp+70MR8r|Q zI)!3YuTcphKTWFZysVPh5*E3a7pK1TFB{eBpuXzjvgi?N`p&nKl$2m5Ew1GqSx@?b(7^5~^^eXHgT~!Fy>G!RKlktguVWE$<;^ao$VkR|y4IU4!T})>%Y2WW8Vbmf3_)(SAWWLOYsADx=&M3zFR0!N#8)=F#LW_k;2<(#nqgc zA}BS7z)h0Z>IszJC@M|LezQ3cO{g8l)2`w__>`pv&vgu{m%^rzheOG@XP<))Y#7{c*m_@w1C&szapm+cx-T z(ywv_t1ux!DfN>)UDBe~q5ZYl$rt#o>DNG6 zO1~{bX*1-6d268NGMu7q;^smhQAM`f9;`V1vdCenUE3&LL;=z2+p0OyS!2-<41HK{{u_a`6#?ItBsiONpl zt}VGv)&0_@so7PGxJpXGJ@H8qzh~;aQ95r;Wdlfx4 za>kj!9vAblYUYQTU$P*x5Y}PY(n7=Xmt0+E9;Zk3)RH}@J65}Jf+Kk!MG)ZJcK=qmYAg-c&u5IY&7TzAW3J9~Fe2#F z<(05rswDWIB44!lCPs%y?kB-Mam3s%@ep$Xzh>aIJnG66ml*l!&Uf04Vt~|?3YQqG zk_KQHc$_e+j&$FG!$G@#yH?C~L0e3HzqI~tItX~H{!w1nK=zM3#=X|6mTJqIJ#$67 zLi$Af2SFoYv+Q%na+loF#}fHO$DLGVoBRI$e!+F0y?kX=l=JXfgSJ5F%XG5D+a&>; z&2?4<@Xd{a5_i!Jz0x|)r`!QtjPED!V-LDZw-yp$_#sxllAlxia%;=sdHgNUk0Ozr z(Fa<}X=q*5wt6K0tjzv|GT7abVPpJ;xr6#$cggE}%8U+nf`GpP>gm=FkOQlGW0j|$-yDso#Qb_xO%w*SfdVmIsA47MOzD=iCdzzRv_R(1=hV~ zlI`L{(Kd^{@^D+dJC@X&C63iV<^aOD#eb+v9%HVeX0+V{z;! zsVms)V(8lh+>VFVnt=ieXz11IV+{& z5&UDb1RkJ_K$K(t478Cm%S$LhGob7V)oqkA&OXT2Z1~5st>XN1C0#YHj>G;BiHVo83 zjCJ9N1LXs=*EZE-KV4)lPuT4#u643N91114tSsP|&0K|(L~|Bvt2(4V%gifJ zF|2uyM0Me8TwC~-tsfrtk7S;z*iK4oHniR-X7bba=;p+stJXYPon%a<8gPBQY!~=x zRb9M)Rg0^T_7$;rv;KXO(p4wtzv@W8_jpIpv~D$D*wj#x>Myv$uQB)H)&K& zEtUYhl;vO7E0)|yHyk7UCWQLX|v|bE1{EFXePiOW}lihbK)W0 zSBEPKjBR@BnKM45sXDO!EkE6(Cg(d#wFuNlSfyO(s#eZ{RoO2F{00(|Q9y_qx_;8FY_ z#Q$r`3dI6urw}lyR0ag(R+Y#9j7(oK(20F$1~|M+L7V@ zvuwL9p7~wCKG9=y|&0a}|M2-bE-%J4~nTeSDAJUJi^nm*T1wAuxtkxQm@@d*_Atg(0ZRGL_96*^m%S=>K+E zcgfY&M~=m-R1NH3%ZJG`psx{#*PvzzEIT8Y5?!XLan@lIYYBitLgf=E7O_mop;qHL zjQ?D6`DZ@u-skfz=i>q%&x5gF#nzy^)svY99&RJjF2(kp+m95Vl&FDOrE@LA)UP5` z0i&D7UAyc11q_Atq7qW6I9K~&X#Ak(yrH>TgIf-KHdi0+SAvjzF^PFaVwsFAT|X_t zBX=5Y1_sOVLuVDUseaMU=O-u>+l7YD3u}4BJf43b>lZc_R)-nNus)yS9nnaEu-mR6 za&)op@j}BgOZM>a6Te8a$^LEN@TXS$#W5vtcz><~Cy9guJFA%JPG7f$and=e-x2zA z`Ak4({lBGF>~QgaVy&e91m=L~A^V>{g^Pe;xP`)1yG#=A-)S_2Z*Msz+o_@gIn9|m zKTj90=e7*n?en!ZsQ;7rP)ZY|lE9X(ggtZMJuDN&B7$X=t+$2wJ)(VX9vS^0Qb$mo zwJPI5MDLGXDMq2%#ko`b26uu;EJ;}XZu)<{IgU{l8QkPX7W+LZz350&lPk$AS*r5JyD zswwt2?#80E>1q}^J{g!z8T;&{>muC|2RlT+3e%$y0}-aIo{{l(9NDbv!Q@$iElrT0 zD$LIa(7KSDSh2qjL?t$-M<=x7~R)3GTz(d&Tl@&_@m)W z0BA3h`+GAt8dDsb6mIDL5i-m~TuP(2pjAcu1}R9;gGSLD_6FD_-#p&D#Ys}Ad?m+x z)ls~4LLwx{-CmIq9m}tOy8za%4*X!ZTh#r{eS|SnY?v^e+u*gShE)@&k)S(a#H0(j zky(Z#oxz1J{inoz+b>@CGo6CorfT~7!(#WJhh!RU^&sl^y8ph`)+m^1{Zsx>X>`xc zRurcH{xu%mx^$((yM{r}7z)4>o`@X<2X`zL*1e+CXbs=3a{(c9tB(~=1dUL zrlIYRO4}_d5wg5!EowD90L!7N#jhvnZ%(~eaag?szE?547;SF_X~CK5eozZ8d0)4L}~6-B`$1ODF< z*Z-o&|JTH&@jtomf9SDnY$_W#X#+K1+lIRDG2&1ejQa9UA|`FH>*@dXB%WG?Bq%H0K+d0K(mldYEZG?0ng%Ld2GNpq| zhgB)t?_=L^K8UkbhUt)Q4&o6De^6o(kLbRmu%mI%hVUgJw`0EHxMN?6bvW+l$)hi7 z&gQdzBAZ3~y?$F}5yEjIVw|K)Kn(nF3)-^f!8=cBv0^<)a8QWu>&dc_t!s z8n(aock`)au?pB8P9A4*YW2SO2N>{92GL=Kn+rNDy;ni5sr`ZlVVPFLW7(z>ao;y; za+<28j&XY}awh?njwx=D6I55iBN$G3+q-jPa6zF{qw8`259Y?bT`=hFWOQ<3PE~o< zoz_#`i)>E%r&s*4 zDsG(ypADau35ADpX|%TSOTy8O5*CG{nD=vLrRJhS-8OvsE1)0T(Um2$Oq9r^jq_C% zLkqxfSPPr~-d&u;+IUgj18+cD!{djADXF-H{swOMvQ-iodUYkct>Rw&cu%V@%GMS> z+Xt(QP6SQ20rwU;usw4TWFK$Ol+6H~DFB*| zR2O!991X`rr-U6xVQjjS1$B867xT~3F9e!)CY6U4csKYSMDDBQCp?$`Nz}vrGNDmPB3_^ODPeSpl5yBvSCVw5_E*E{Ki<$`vF-@cGpZD* zkgq{2Q*BH3CvLt3*M>P5MCb z)EQUvD8s)Kf4Tpi9!Yeew!K&}QquDg3kAIMBFCwiTskqJ_{>{kwaTd=m6T{}jjv4} zQ+qEo>6gf7mIL8S(d0ZCO?0(NG{K<>ESt_nJ*`@$-zq-c>XP7>8Iua5Eqk;oeZ5*J z=HuF#VheG@iAE$&E(`&cZ7-qw^P@g6J^+qgMn9g?V|NdIYA`5F~Ya9iC0vr3&bnwR4M44KO@-F4SVfcm^02O)ss43>^$ibiobB? z?f3u*KV+`=w*jW7d#j@Pizf@QdcoFUPpJJW$)mmrfFr z48Evfu%`|k@*xQD@w2#N-$#5ejBGm^ZN0_I(bU1D|7JhxxIE#R3u;abf6uV}^UUo; zni)SM@#cgo8scWw0(jV{tHMzZ^Ub>W{yCT_joqiV^wKBDy56$4Y5$K*S@fXxAK?*p zV-awQlq1+$<4uDA{ftOePU_l4hrr*0VGqakpI&DImk^WB@^W%0<~u38Cjm2o?lk7D zBn;2d%mv@k9m>7Z43W01sNVL9->zJt`PEt?sw{ZL8Ey6YP|M!Or@UrJ#m|!zHw|XW zVE3#|yF8FcsH-j`n>GNLC)p`k|UVcNWwH>yC22n(DECik#25uvx3 z?4U3^Cqx9 zSj9XElYVuLVm(8j>=jGwUlPPj0@wQap!_P;Y(dc;ukU&|ToQn6l2m(ZlCTB&j(OF~ zrgJh_UP4MR@RO7PTB=X(NTV9Xi8&9yx>M$2-4)w8HnPoJlk`9SCpPYgf6*Af5&~FH zLG)`(u^s?(SZy#$Qc{Zr@RljNg zaZtQwkRw|P*a7Mj{j?r;4qPD|1&=KS~@G~NBa$jtwrj}-GvpuIVD0)E4s zG_bChvTY~Ou%Da&d^s}7d)#m-DOaJEzx3fopg|ScPOG_a9xpw`$u6<@^F&QBxoH2zPUDVH7wRT_<4gC) zQqbywA+f@i?Hqb(B5P(Mn2>Egyb+^Y)WJ0#%YTr&lrKPs8=s0O0 zD$>e4H(|GjY2e>a{Y(bPU1}ov8GZ%r!HEMQf3}nJs~;PwB!2)2n|UHtWILS)DdFm` zJU6<@&Yjonwp&f;3!i8(!{ zXPlAA>^5|fZEf}jOIwkmDCfN2xG_WACAZrL0F7MON*vw4;T~HngRsd3Psqf2w*}VPUl^aZ9)XS>M=d4tJ>o>m z?DCUT3sNHiTVY>kUF6Vwo!MMNP2M~HC?SaWDQ_Q9t_A+J61_BD3E zW$9tu!OVza>S)aUj57s)*+xtMctal6x8uiG0az4*mec;S0Wd#|Q}35H;WK*VxlDLZ1!#!lK1ta}8zk zvnN=fZhBfCt{ke7q+f|0`N#+R%0(&UZ1U6jjbkEFk#A#E`_^A}$%#J!P5U0eb?JQ2 zc)!GnCvPU~;0~_AudyxB6h780D#!Vgu<`~|EXWsF*h6^?%8_j{H5j)E@qnR5E4^%t zfa<2O;i0dh0T0)B2Do*9+``*1oc{RQIubE>K^=$?6<^IK!&PSXlOf@v2ip5d!1E(B z%Su8wQG8NTqDL=>RD3e7^mry3Q!I#4fj(U@dW2iuWVP|LLl@;B%j-Guk<5+2Ij3U1w|I)SC{IX0M zQRV@KNt?4=6eVT255Qmf2M?uYQ|EL!_xv@C~KX zXVjHo*0Shy+w=5@)gSAhNQXn2votP&11421>k`ZOg3z~677%#}b&Au&I4^IAzzP#x zp}X15^hlpi!{suIFfK|SN&soJ5<#h^8SfaDcZ#8agn3Y$p>pMF0ot$bKfXTfR+|~= zvSO43>2Lt=dH>>xe|XqKH(ZD`7qag217}$Z&`G?(z_bNrU#=e4RLwnAu@sVfVjv@V zm$A-O!h?y2s0zyY(-BK+bP~gLs=kEsE8xeVzTtmTp3*H)xDM3YO(T*F=mVSL3}inm%-*(hP8A z0>jhWBl^5qzM2Y?6M(=s2_X%hoHU+fH#cS?DnVhyu|7S|#QDBF`0knC*T>25d}zAJ@0z^F-YNOCnFU3K-}T~S zh)Pvmje*_VYN79kVo#<5_2dStvElfgfzJv*f8RY)6%F&q3Ui15p_bgKy6B;;kqL$KLtnVx{8>MYu_Eg`KUtj&VY(=C#0XQ!5X8ORW?{yDW5)U1ty}7ZbbnZuq>jv9d@H1j@ z%DE0LQuv7C*{*P2CL{z~gkenH^2UeSOd%Hw{h@NpG|m-q=!%th&KtI2)ze<925zm# zQNGQUTT_m+-U^%#oXA^vJ?tc66Y}@le*_3xao}X`2rTHqbMo(y?g z)5=$X9$s6!=khTMSS7?qY#F%m1r>sz!2zFepVvI0_{7JXmRh-*g7`OVaBuRCgvj37 zO?F#{Z$lKKF|2}r5`iDiGtL`f@mU&6mG3@Rz+uVs`WaN|k5lr@e4(PrNAzv-R`DQ# z-7vL5A3@Wh5etoYSpsMXFV13TWkSY(IJ9DM<*2MTt5Lch5_=g#>c#3>Z*T9% zvTNMN-&ck&^;jzCu8(7TQDMqdWYE zEz==|%3}ckyK^x@L@J#0$C4oCZrn6nw3+JM z&y0P`^%M$kLnrl1f}+GF#QM_!UYcn$*};d=F&e3zq5yQWU$^lEL3>w5hLb3Jvc9rJ znui`EETCs3BqaGOvH6>$`5+#TXI!5_3pb#eVbfrkyF&X&pM zApJqs^Ev&r)=LNz33 z>gk0ed$5NGsrum>xIzm_;?T0mLZOeVyVNbD&~FJ*ZpRw{L(o&PY;54<4*3?00kZDB z6%QzNlivP0qL`KZw9O1?&sa)uIL7=W;#}Ck6ILS89}6p5<0c)*3o1dW^ub{lDmsN1 zkXB?ra#~Do{L;ayFJsWAF1q}z#AdeB`UT&1I;^v<?UF_D% z1_gxKcHX?|dPkbek}X@49Hu`UEWh7P2rHZByj(jvAD3zUCNAryX=#?%N?INiS|$;P=N#aV!4XJihbMcC$ff>@3on2vtbRz~n(fk=2S0v7(C{_=cBMOwidH21` znL?jYYn8xr$^m7={PuwT&-lRF+g~+X9qV&WOZlA_x(%tshBhty+P*^>eTiMD?uRo~ z*k6#CeIQ)e?j(#!%yYi`;zs&}gAGx=#;NKfYPv@Q#wE||G?>JfE*vrvaqOLBHv@#~ zD>6`?_E-CS37Zr@GqmqI4a_wX&Bg!NPX_bsP0suJ@HtcLwd7PBrjQv(pY*gQ5@8Yy z(-b0@=M}(<^jJ#PaUxcb3ca^T=~6M zYnYsVngdnDio^ot)4A9ZD=tHn%k)N0G5J03M>!mQYr6iveKUfV+}uJ|Wu}wJ-w#*g zip;S!${8&|OXQBY{tA|`JEW!g$N|(a*WVw6(cyuPjPV0e(z@NwJn-7-$3eL?yH3sb z!BN~l_82*Vl8oqU6k8ylaUHlxHoYWo3Od5b(7ZHD{*Gf5nyX5xGvhr)%8? z&~}^%K#R!A@iBs-554+SGNiXo-V9v=^p)xhd=Y$DaRoe0eHIr&A}(^75hb1c{KNe{ z<Rn|!*yI&ncKCyL+-LvpIF6_{;jqFB}`F5ZQm|qOJlbI~e+FM?MhvsC!j*~Jl@V1%M|g#ToKgF-eyp}$t{9qa{SHC3%#9luC}QB`+0 z9bx{|aj<*g*`(GT@}EdUGoOwA#Aa=O98zY}eU+ai_LI{Tm#n3JEilgjzzxTo-A+0w zsC#IBsV#c+whlQDsk}{amAr~H+S5Kp&~0axk*_|tK~I04 z*>&jpaL{1#(k}ZV*%2n&lE)E;e<^b}$MAVxKz)S-^(^7_hrhf$#y_oL>n6WK2}=x7&sAcjf-%4!$2XF*l;Bp+uB_XU=cGKu@?>iD{9K^@FVct6eE5#$E)3Ob>Q`fQBhtGP@!20Ku@ygOwp0ynBA_pA2F8K9We5m^ig;c$q`@F2f4r=iv`QXO$RQ-07U zrt#fjyx>~Yq|*}mtU`_Bx&0>^Hhe-=$>ji8%3HhgKr#aU^ARsg>>h~#~u zGXim&lv0vdQu@_b82E4yzy1Vio2POmm107+z*Rsw^pbu?X!U8fL9E(k6`=g5R6=-hqi_Cw z2um-Io(@@o^$|si8@}m>ylE-HoX4*6vtLtoUH&hMgbRjEn-YbNML=vZDghs-DD=6Y zdi~6QPxNDv?xQsTy6BW+ec^=GAKALT0u7Y*Hh&THf?tJLJJI1qNyP~l?e@!hsGD4x zcipb}MLKrFAl-bgq48N71Wc)LOGvFy zLVP=-L#N&d)-=Y|{peq5Uy>-uCpFr++~x!rjz-@b9FF7|4zpk9H{U^$TVE%8{-);0 z+*-DC#X~b4cx7luh{Y#~%%ed%iev6x-|MzR7?8&<3AQ4DP&l<^8_o?+F3h^Ux{R3- z#eOIE{BTr{d)_q+B}!1_szQ6$GSk;ZBwkdBB+L96kZ(YJ?n4fGzhWgFM42!ox|{oH zAO)NZZ9y@D%uDTbJzkC}`>?QKzLbf2r%a6x52JY)vN0J2Ko+f^38h+!_-Z+T;rQR- ze?>h%-!D<8@0$^YCMFoe%>6(Y)SZ{DDbflx!MzW$iBW^kL9|<*fhSW>O{V=3)Y+uZ z>d{dO0$5PdvktfR#d+$#g5yGWgne^cPfOjMJa&6lmma-0Jqr)&zf^Ee%b#N1q<5rI zEO=HweoEw$lkn-;B8&xn{2ocj-c4E+F)TQF%F$(qc9O<7@?37W=Un#zWJyA(+;)-` z*U#rT%|E;3{onSYw$%keDow(luYtAy6?XFy4J;wM3OYLk|qAHhK(-o=7MV@q4Mxw==PzZG=>3}MC@msmP-N*TiFmpX@M8z z4Eu78xpcj)rG?zd%2B0z=)teVPY`ZH-WcbRv#mqU(&HaK#QBS=G0TvDi&qFs^C!33 zMrYQh8pTO=607y~eyb@=9ueU6QeNfV(dd>E7Sl@oVo$5+j9)O$^}p5Ay72)cMyGxn z-uwzN&z%cpR7^jWOaTSZ8dG5ud;sf$CY8ZLZ6@XqBe@ES;Qit8zNRA5lEHoPY(cRE zw{USqZ{cd_!vod((1Z0Pdcpxm0LV zMeyT~HXPC<7HmZ(x%s_-qcd)+q9a9tROnceq@qC znDd91AdH$J0gvH-4gBgok8`TD+0NbtgZWPA*ZYBp3>LF(^FEn%!3Uqo>tFrwT4h+o zq}9SmI!V#eO4LM_e?kqvc3}lsL%9g;rTi@(!J^w2w1U`N#~%kqJzgA4q~qB4mm1%o z1&1k!JU5I*xHw7!KZvcEyPR!Vs?1Ej627MwU)Gc&K(>wO)I?htoQWln(*pA1R-3td z-|tT}leLoW$^ z@lR z2uf&jBWYY5ogg@gNkwX9(L|#q=Ig z8DlQgS0zh>kpMwiPix221d_LGzGG@nEcv@y#Bn$?GK4wFmXyaMhcl-%Zc_i>f&4IH z!Q0yGu#`jGpu2uM8q^3@J6ekW%5eiSGl&l9K^U-sFs>*P7EIy+)3{TVumD=>FqWwz z(PTZWvx5oIGefouDh?-rdwi<_Zcsrs+KM%r4OVti!~7SlmyYjJmEu()26Sm;p(j2| zD|{Z;GdL}SWZ$&j#?4<_6AFloN_iDI)ZINW;^sC+8_P;{u^Z@j9lcT>t(ZSXkl0MJ z2W;29>`;@TQ_#RjFU-;yGt}xFwkq|%HLz7p?|%1}1KReqg*y&RVa2C?uZcoJLLzji zmwNK8;3IXd+rr|f&FsWe+9ZF6c2R;p;l- z#5-vf$dzQ>sY7#*Qxgzw-=oG|;vwC%E0;`EpmL#^Il0cKJ{$Om7Zxy!eAfE>4iu;) zHGWk9KF_fYpitUGd#`_Dt*Z3W+zv^lCr_UAWA=@nv`QMb=Ha^(Ox3Wh`nZ*y>go$sKGKO4cdiQDO zr`#qTeoRylU_3=X>YTI2vnq|kmi=rm;1*=@47wNIp}&mq(n>}Oj&miXU8bfllp111 z?&RAqNE*}5m?Xi<(mWj|Q)BNwR^!_M-HAz!OHHITp>X|YsqAldDO9heA{Z(v zI+1wpS(Yp9){$Wg+u0HK8nwME0p(C(s_fRO5&w~)+0k`tPw^#yK+>eW6 zBmoTSF(m+k;n0W)3UYuRQW2CUpo@Wxj>HG5qC>R^1sz{14yitCv=_*4KwrSxl?DVHm>?1k)*A>;AY}rU8kqP}5gjfS@>z)21{bP#;d=>gWlj zRGx`aS0Hg%n_V;^4SH#hybu2&rj%bGZ>A?*dO8c~>*-{Ekh^~38P(emo@T|Xwh|Rr zZ?DVGHPFjba6fXg%ogjGTI_k?KP~lnNy)GMX1R*+Ul>`dWmeG#9%*sHQ!XLD!tY_|u2_8iR}zO9$inCa5t{gl9FU`^w> zxk$?PT2`6g%lw?OYdw+6RC130-;n#SI@*d8v9HyI2`cGW^+u8H#AV22im z7e*hnJIdMrP&S>X7pp20oRnaJ>E`-}11nF{E#x1v#vFEesBa{Nq{lDWmSLQqms+e? zp6u}ePsfa~5-gdI--zVMXy#JVH^&5C;D=trD1D+ z3AFh#yrp!L!|Ql5LN*di$CwK{8Nt6SAFc`D38n55WoYzN}rahqlPnlC+VL(;eZ=Hopk&9Z^ z8j{TfvXO24Zxz7?o8-LF^bJG}R%t(pN%p$4PkX&+`F+~(HBITA4lSLzTC%MfI<(5#%CWWC@ zaw%zAKWdfOunCEVByAR{kV_(dhc3VU_xGH0-p~6v&w1bTJm2U0exHS|g+4&GwX(4S z5Ci~(USQz`U~Luf4gg?h2ebhI1OOf90Sr1ry+9d#0DyDhZ*L-Uk#BRiMd!ji(BF9| zj2Fa<@bgvMe?-mJVXJizFPNvcQO8(EPiNB(HJjitztCXsAJv!weLZ8Qw~wLWLO0+5 z7(!qKf?)(+Gz5z*8V)0a$Kr8#JRV0P$x~#h@&rW!iA0s7Dk>?hT)9$y*(%jlBvo0` zN~Oh3(B+FOi3mbeB9I75|Fdu$oL9)^YH$)4|{)|KnNIm^#~e@xgj7td)MH}%S$^h(}WhtKTYuCcz5VsQ4+ z^9vsS*Fqm!zmqeU3YtF7Er3VvpHh0KNEiFQQ$3C-&YCW58Kl$MH$QM^z(k(=W<$j5 zi|?n+Ch%sh6DcB(`L~zLq^8zMAD6ZS^S@>)JXC2XnjD_B=61QZiwb{JM9O z#>8g*3R6K?nSU#%mYmj^G4p$EO@-65BIi@u2ct8z>;(E{{?#ossd;ck(N)!s3tJ?= zS|WiX_YWFzw{dshFrkWUr=lmr$0`SVG;YQU+Fth%k0`iCMTwM8W*bb|ef}VFki)o4 zPc@>G;k2RPiO6J=XjesRxf++PH%#P3ZkvM}gZ1b52Lmd?`6X|ML=iKs+O7jO;+%Jp zA2OOuLzVZ9E3Vhxkr7jdCcmD7CJ$p_MCNPq5R6~|7DrK_s?qs0hAxY3>FAxFSKGgY z0a||xXllJ*)VaE}I-dfHQ=$7fZjbrFyG7@M5~U7^q_c)|p+ddxD8srbRX53_+ECSk z{OR0%*HzRgxQyhuRAa+n+s8-FPtImgX*2guGYHCOr<%$!4hR zNqJ9LcBsvd#nswk9*4UWHM|)0Mk-zJ^NsNqOp77GrOpCg&|lFUyK9pZhSb2vDx#}rS8Hpf zVEeP((%a6pH^Fi<=FHo z`YZ>Z7hiaWvw#->Q^qz!o?*>X?&(h8Jy4G=oE7TJCKq3s)_Y_}5}Ro)fXa5S!#~Eg zj**sC8p&)3R7NtwHoY(x!JQT9-$sPkNQ zkmD?0wO>72F-9uE+!y_zAjoEHcN>3l-As8RY+Zx6ql)OA)p}N==IODA7yX0pw3V%< zmDYC*c(prQZ#k}BsGG>;*fwnD?DN)APD(#~Ah1xu@@|%vO5$H`+&5Q9e@Ui?(~NyQ zozn;7?}Qv}+!P{Oj=kNXI`cyzFQH|R{j+evhr*wjYs`0LjjVM$o$}s>wyCOtZT9e0 zRnyMvqjSV%lWv&e?S@v*`hEO~zA+^KX^-(p*;m|d$=;Hwpn77-iO!P`lM=PLRS(QA za4QWWxqPpm!?VC!?sU;m=F8v-_d#xN_1LEdlp|}%Xg7c{IQX0JKomgNMakjK7pCW3 z8zr+GYFocbj|F}1{)e0NegjM#E3k_##G8-m7{fgmU$BLUiJ4yr_eGb-cFj5S16G_S zWJRjO-}S5;Ef%7V$y8(IGwge{E>8!;54bovpYnA(M$H`Hmp2!d91~JHz#h!=WhpCM z(m>aH+E4l$nk@yTG^$mF^mW`nhN3;r-OQX4%Wb(Kx6g}>ih62WdkK>9--%c4?{2y6 zPzH#eO)Y_?)btGjr4Ab-@9@ES6A&kh)1e)jVxBg8wz+f+rZ78y zOS70x6}KlQ^wwe7PEjZ81MJ1dgsE2jkth}6i79zfsf?zLq0!Nn-3*qbu}bNORi{n= zX&;F}aaigxXomuT3|^)hy^M7Q7!p1$=wCD!8HLI@_FD&E zVicR{O?Kp`=dpyfFGjC@BNTa(5JK*yS94xALYSNbzN3Lm`M0X@99KCZ<)5gqY_vz3ve#wdsoLZ=k0o&ZdM&8>J&kl$$vuZ z%p4@8;ZJh)+5GQDc}Xr|#f<@V4sneg>k4E)(t}0`!&`MyeKkXR36`}=3d-|{z3>nJ z;dQwr>#V1;vrMQ@tpN1BGI#hh;kf7*(l7n_#8pvJUBan+`Z9wn&7P;9JN;ItaX!CO tbZ_LbX~3NI@X(=tRq#4}*N&R+dPKifSK<>V-deej)I`Q}{EHTz{ulCq_9FlQ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ade.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ade.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b653b3d1375113626f327305808833c8cf96fc58 GIT binary patch literal 2290 zcmb7Fc|4Ts9)I3>XR*&>X^e&$lMbRgW5!h|Gs!wR8H6mA-H>IZ#W)>_CgpIAx^XHZ zrMW0{>PlH6MQP!b6Cl_y}x(){GR9c{@&;N{VmU<=vRyYg1fVu zGk_ofAmjpyQNVTDCyWHZ!vmND08{{USP0OFhFAdwc>q9_pq6IDCGe6Ss5B}T0cUe! zvM^34jtHlPrqJ9yom}FC@j@DV_1e`|tF1TD+~SiXlHx;l(wO_K!XucRu+T`wAaDd2 z7)HS`1_h%qh~U(5I2guhsi~=`6SRm#f)*Z6(xK>)w8`3dyq=LBnPNbtQi*y-#zxDH zDa)w_%AY_=Pb^Lohto9B#%mk=-=b&*L=_MS#4uzGP(%nOLW(wEfY3+5$}lYn8UtZ* zFbXkJka@(oWI+^Uh{j+Q13&|rM-gBG62BhYcTXkCkFdN08^K*kA^@An=)m>zqDN^D zyoR`S%|-1acP_mUSD!IF^e8NP!*n52<$6Qb%%6+9o>ho)8_nyJ&AP76ADfAra;n~8 zKBSrfvMc36yE&ImcG#)<&nI+b0fr|B9qVM(J6H81)+~H#(SGxV2G@Q7*&sky5C957 zBRBjFD;fg>2!&-@>k^1MdUUQQ0$By217T2$jg4=&pGx|UXBS=icuSb))b$~2a?35} z(tcIDb-N;3e{J2UKRr?O!}|^PG#lSX<_Ttg5jy2z|D29@*P^nk2i+R@+}w#h6uZy_ z)#j+(F%;+LveC!33leXQJ->V8Z)!V(lB}D#W-x0el4-_>ixD3x6RwGD(hIG^wX38? z^xE97$UPgHim|utJfwc-P{juGzB`MDjjDf;Gpa_NtvUDCJfmGp(7JWm(VI`#{;?Th zXhsAO3}Ml@Zv+u`FcF|h+B7;3!(d6RxFMqS(XlTyk$gHp?|cX2O6&u97mm*iC;$AR zJYx=$4!$W&)r*R=lDz!`qumu7-)UH{4=ci>!y zh-zentiVxb6{$BIM)hkABAfx5h#}FLAy|U8F>6-~!-^;H($VF5hKZ8WrQKh%jCDYL zmV>CgD&m46BUt@*&X#}g{psXv-{oeL;lL|hL*r|!9HWnnUosyXv(uV#ZL_PI&lf|DBBAHrSH=MLScSDOS^xhvyReQ+(V6j^^ zJbcf8r!2VN(BX^sh2EZ_&XxP$U(do^zV)fYjt)pnPZm^3EXIK}C z%~d}QxqGO`9Y0DOjory?*mOI2;xnZ#CZgV>sd#d8%ERvVF$W|+D+x%(As9w4)c^#D zbQVv*6qORBwJjm(T+iumedj=59I_lA&MH7p>OEufO@AC;HQ;E~nbeecy#T`dF=@@6 zRvKw#teOJWukVuTd_-BhOOn|WKKr~%8cQ1MeLuUr;w7`s^zrX@QW(C^{`RCYWBmF0 z;%wqmAMDEVYZ;i*Ovcufo-uwTQ^NB* z*dgHKV($>1MxD)?TD>=*m$W>+Tz(>(!YcQHBSl*mOEiERqgAA!;(8r&ghm?-WdT~(Z^1U?Z;p5I$-O>2aB0ik!@tnKE~RD3z|o{zo#t# zn{$GL?8LVQ^XmjJkE`a#d2DO0u~dopBah~PkZe6#+mp;LyBDDSvFuIwDv|y+mj~`Q zO`|(bS^50K@T_aljTqZ?Q7Nl@rlULbCI=<$;JA<#B7w&a-J9g)iQO9gpX^)Vzf7&? z)4!l|CHG#q3&E}MvJXG4G{ZTxtDe@H`si38%Tbvockli_dWJ#wfh~-Kx`Hkf`nO%2 j>&fMIzK~?woIOmQ4-EEX4<32%-F{!n#~xZ}SN!%L0k>Q) literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/adp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/adp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b653b3d1375113626f327305808833c8cf96fc58 GIT binary patch literal 2290 zcmb7Fc|4Ts9)I3>XR*&>X^e&$lMbRgW5!h|Gs!wR8H6mA-H>IZ#W)>_CgpIAx^XHZ zrMW0{>PlH6MQP!b6Cl_y}x(){GR9c{@&;N{VmU<=vRyYg1fVu zGk_ofAmjpyQNVTDCyWHZ!vmND08{{USP0OFhFAdwc>q9_pq6IDCGe6Ss5B}T0cUe! zvM^34jtHlPrqJ9yom}FC@j@DV_1e`|tF1TD+~SiXlHx;l(wO_K!XucRu+T`wAaDd2 z7)HS`1_h%qh~U(5I2guhsi~=`6SRm#f)*Z6(xK>)w8`3dyq=LBnPNbtQi*y-#zxDH zDa)w_%AY_=Pb^Lohto9B#%mk=-=b&*L=_MS#4uzGP(%nOLW(wEfY3+5$}lYn8UtZ* zFbXkJka@(oWI+^Uh{j+Q13&|rM-gBG62BhYcTXkCkFdN08^K*kA^@An=)m>zqDN^D zyoR`S%|-1acP_mUSD!IF^e8NP!*n52<$6Qb%%6+9o>ho)8_nyJ&AP76ADfAra;n~8 zKBSrfvMc36yE&ImcG#)<&nI+b0fr|B9qVM(J6H81)+~H#(SGxV2G@Q7*&sky5C957 zBRBjFD;fg>2!&-@>k^1MdUUQQ0$By217T2$jg4=&pGx|UXBS=icuSb))b$~2a?35} z(tcIDb-N;3e{J2UKRr?O!}|^PG#lSX<_Ttg5jy2z|D29@*P^nk2i+R@+}w#h6uZy_ z)#j+(F%;+LveC!33leXQJ->V8Z)!V(lB}D#W-x0el4-_>ixD3x6RwGD(hIG^wX38? z^xE97$UPgHim|utJfwc-P{juGzB`MDjjDf;Gpa_NtvUDCJfmGp(7JWm(VI`#{;?Th zXhsAO3}Ml@Zv+u`FcF|h+B7;3!(d6RxFMqS(XlTyk$gHp?|cX2O6&u97mm*iC;$AR zJYx=$4!$W&)r*R=lDz!`qumu7-)UH{4=ci>!y zh-zentiVxb6{$BIM)hkABAfx5h#}FLAy|U8F>6-~!-^;H($VF5hKZ8WrQKh%jCDYL zmV>CgD&m46BUt@*&X#}g{psXv-{oeL;lL|hL*r|!9HWnnUosyXv(uV#ZL_PI&lf|DBBAHrSH=MLScSDOS^xhvyReQ+(V6j^^ zJbcf8r!2VN(BX^sh2EZ_&XxP$U(do^zV)fYjt)pnPZm^3EXIK}C z%~d}QxqGO`9Y0DOjory?*mOI2;xnZ#CZgV>sd#d8%ERvVF$W|+D+x%(As9w4)c^#D zbQVv*6qORBwJjm(T+iumedj=59I_lA&MH7p>OEufO@AC;HQ;E~nbeecy#T`dF=@@6 zRvKw#teOJWukVuTd_-BhOOn|WKKr~%8cQ1MeLuUr;w7`s^zrX@QW(C^{`RCYWBmF0 z;%wqmAMDEVYZ;i*Ovcufo-uwTQ^NB* z*dgHKV($>1MxD)?TD>=*m$W>+Tz(>(!YcQHBSl*mOEiERqgAA!;(8r&ghm?-WdT~(Z^1U?Z;p5I$-O>2aB0ik!@tnKE~RD3z|o{zo#t# zn{$GL?8LVQ^XmjJkE`a#d2DO0u~dopBah~PkZe6#+mp;LyBDDSvFuIwDv|y+mj~`Q zO`|(bS^50K@T_aljTqZ?Q7Nl@rlULbCI=<$;JA<#B7w&a-J9g)iQO9gpX^)Vzf7&? z)4!l|CHG#q3&E}MvJXG4G{ZTxtDe@H`si38%Tbvockli_dWJ#wfh~-Kx`Hkf`nO%2 j>&fMIzK~?woIOmQ4-EEX4<32%-F{!n#~xZ}SN!%L0k>Q) literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ai.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ai.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e469be3df8781b9a24e84ec22c5e6433dfd2feb7 GIT binary patch literal 1776 zcmb7^dpJ~S9LL{t&YYRS;EaiFC1zx$+L&RCt%&KukZV+ya@!QcOjuF0iLT4a79p21 z+Y{_e%4+Irs_Jk^Q~U%@ zSImTSaT=9OrTuTo>j0e!yg>|x=mV6FV01)&11644N|EBEC}f<3VlXxbx(B%x{!9xa zAt+9!$R7h527?4fK>yyUCykX%elf2h2-+A*wjnK{eh4a$E_6ubnmMnIW&PyZ4p#o2 z!mBPQi0>c$-Y5BXURZ32tge55@=8BM&8sp$OZf1&1M?dra@%_1h9j?BVLczS@qEYw zMDM%?0JO|iPeLRE0w5#=dN2(HASwg`2wP*81w)JD>Id1VkQu?z(J~Klf5gXG4dE3A zo>gaZGRu^<@QTU=%@)IkmXY^|4JiwXVw2mCYR8P$OM;eNuZ%pfEXn+ZM{B53R_2@A zMr#JP?ub5I8X_Ttt*^5jkLW&*;(uPhI~#Hs(kF_F<1^+UDC`$HlZ6u+`g}IWG~tMB zf&}_!jeI)qS+t(3w)XvOt!`1~khx1lp$9MaF!!*#WrSV$&eo+P@ta2H55-hg1*Dg* z3Y(iT@a4h6PY!c+5OfU| z2WLVI(-l(`sDfg|xTUi7qj%#r?$W!NNq^pJeHU@6y=mF%2AT#f91cB?rQ09ymz#OG+=ISl2&f&#O@b- zvfSpUojm`TpVY38e#?1}j|sA|$o4?x~uQ ztMa=!W?U|IW|(HJf36(#ZZ!qfUslX>Q-RQMHf})Te#&VSq-G z#qwEyEE`N6P7KqZbJHZ+%HvVtrCg`CvtwzC+j8?oReJPs{@v7_<$9~n8U(4+-%1S` z4y~ano>n49_d~)=;`+cd!hqcB7&L%-UJ*L*L z3t9wHW&3FB?{Fe{4A+TrYad&1^M+GRR+Q_5y~eTE7*U?DPHkFnE~COn4w@nF)OH3K zWQ99=QhX9&1K5}jr~zy}OZen!J1WL7S_3m=(G|x70{7qa1Vx4%g30E?4C8BOx}O+0 zU<+k+=3FPkyR^EfRrf4e%cQAxNcQrgBTzO$R3ak>@47ub-lysNB*khk@1ltJrb`;< zxq)i1u(5p8Wid6$d11;6X@%t%bt~)1r4`2jX=Y^rmnK*oK9lVh?mxA(qUDLcyd%xy zy^Dty^FHm*=`mCb_}Tu@kvkeXy1sZ>S42Z^Xd+MlM&KoqOx4DP3Py)S(VYc6YWELj z^pEE%{P)@H$ssri$M*5p&`6(=?2zi0&R63gfF1#>i{bw{8YgmRySjzP^ZzX@F)Rbd$r1&!C-&dV0+~(lt4dea78=QP0^*QNA6W%#jO4S64F5eEEwZfAkONwN$_)yl2R zkbAQ7r0e7|lPsd*AxV!hO6$_fN+K$>!t8fK?4SFd=RD_ozTfwK@9+11zxNng4G#g~ zKih9MKo9^B_y9u(5csA_VgQ&wA200oX<6j;C)0Q4|AG9y2Xjf^A6py4Cn z3#EyYc!^vb&5c^e^$+r$6E8`SaHlxAIk`AZoyYY{NEEM05XEtwQ(atLqIj-6k)a)U z0~Enf3_(#0C4o^f5;O`0qta<~I-SO%(Q&2`9XG~lETd6I#!M!Q#iARHG8x4(fkP&F z2;5HYG{!JvCeFf{{~Lx&fQ^F)Ajc3JfU*&cjTq{I6)c}TnXK?LXgHOQFi?yF!6}5WZvbf{7ew&eJa^iwT9HG8; zqW0V!SrebQ&rf4)iBQ#P8v6w2?x^l3IUWyHXI^>EyK-gc`ZYX@Ty1XO{u@`dWgL}y zVoW*xnX3C>^922c!*SOGT3#%8_T>L~$*}W1{nBfd) z@JhY_wjH3Dno-$YYo3=gU+{968zs31?@ijs-@Md6o%X88k5#>C^bYy4V|&>_;{$DJ z1GnBv+oK%jKHad6ZnXyy)t*Enf+Vc;pQr6gqXJR#++pz*2c;);7*w z!BsA66BUJotsrDUq)7IuVg%4U(V_3Bhu+)nt*H97Q{Pb9n{ai0kKVrR%D9b9&*t=} zi&Ire#g8u^NN=-J+2J zZ*ES@xz!b-u4bSg7m8DUes*qK>|eFn(+(`M z+xnEfN6b9YT20v@-hIe@{J3R3k_t3j-<~h^JKS&Dy6$AX({62%cAFc2qx|;cz^3Kb zJSN+A1`dU&3R+69{_$Q2MHo*&SEE$QSGf^3unu|jFtJmf8wRbGuFE~&a%(Rh;bJh zz@v){g|t8k*@yiJNT>YQn!wyn4JXZT(z)@Q$bK<{FD%Q34IK^rMJ4Bkfv~Ls*Gt3` z>~hWc?Blb%joJ>!Tje6Ebyyzg4-id}nNyFa{9 z09kAak_DxG{cQ}hIC}*Ji)49Kk%gbk0T+1^gYG#A| uoKv9I8EKD(DymX6r|XiE!`>XqbsrMGzU^QsJp;yE>Qd*8BaVsP@hB#wgs7CfK#+t&ZU@+)xwkwzA?8;0p2uj0YbOh3G z0}<*CXTcpe01HA;0wW-O);$-xhW-JXvwEA;BV7H=O4-4<oHK7nl!tfX&mki(Uupd7(nVI;o1~$zkMRUR zD9&hub!aF~2Mi`A2|x%gZ@5%zfK4&sb|W}uZq=-D?y%nqr#!dsc`@r|P#+r-SIY~Jn}5+w+^awF!P4SQ z@6>_1Dp$JJgG=R=erFfWjf=M%v{^i8bU0eq}CdWk2GBF ze*BgxdMMhbQ@aVuaiQ0Il}BCN{@eGJn;qbv#mV(6I~|~KhWKw=b3w<;a{I5>qo?S% ztEcIS1j@T$J4c(LmYa;r0I#O5s0teoD8jagXY-gISs*t5t!#)oQm z--Ky+*8KCdFO+-lua=*kZW4Cyg2nsK6rlDJ9;=}ij!WRDrI`ePy?rfw_8T0_g9`FYh9O{Uw&p=eyP2f0Fj4W6+uOQ?~7$NU*7;lrFDIKFz;brgT!bk zOM5WQgTBQ}GN)XB1Fc$jnocHeg?z`tZzq8%nQ4Op9 z18^^QPj`SI03h%Iswv>I?Lb^C06spz8UR28NKPCe!5!2BW4Hi7tI?H{%xY|9AEs8S zmVn*Pl(e{{xJ*$DE9xN2%XgbcQe1Kz%htxxhG(&w1S1gD4VX9rFhpIZ6(LioBpL>F zCh!=>{bwCULQtqzDS$Qxl{kjO`jz~}U^;8X9DvQr4{T#aLx#g;wN>?TQd_yyZ+d~( zq;oV2Tz=4GpHX%CMC;__=9ct@za4(O)}#IK&F_n(^1JfKkxiP$038gvAiF$NKl_z) z!oH8*OzU);k@>vLHV=qzt$Kv8U1bd`{%BPXHBr* zSoX%l6GpSOMoia@hVT3Wj)gvT+(XVwHypA0Fu3jSBNoG~ri!L^w+X53Gbe-Ga|zQK zi-EI8ilSQ&9h)hy4Y5zgvvNyA`i@p~TU0arYbx$!G>fCO{VmNxUdb=K`!X^L;?+Hw1MG%z0^jPK$HfJlB=dzp$?1nS4$PKTwZfq+fYJ;x0J`2AP z#r+{U{Os%@i@}(q-f4Mm@$9%@rZdF+D*+G`!)RK6f`qr4OfVp1K z3ZwRk;&By#0rJ)TLr_f`iTW-?RNYX5LDn3Rhorg;C$+AmP*_r*c^6VX^Uz)7_aAcv;)*I|?w`BmI&rapy8n}+F; zp^?FLTe349Lwf^CdX)i~B*|pFVcEdL?s$g7w6ZeLlVVy^(B$>P;FsX_p|0Ed+P^op z@p<^EJT>|9iPOdDpV@_<|J?K6Jte8>o}q$kUO%XSD1>A1^K?n>?w(h>VcD(JWk)Fp zd4<{tAk4V}j-OC0e~zqq9&q;i?>x=7&)-3!hS^psW*<&>pB|qO zC5K9s`rbgdXR>fXPHd`~}tVwP*?UKj} zBR18Q?o)xKrS!>xMu)^fn{=aQR3<^my$E9OXKF48XfDy8r_egQ4jikEOh)MKM7^BNzO)QszL-nJP3BZvLf zLP;Gaeo1|lr{C{(@O)!LxlYuq%^B0%_nvVA7^NCdmbqey!+{IQfvosLV9$WS4`*?n z`$h`IlCG7O;R||i&r7|xvhSw(ZPRzr!_kTSc;%@=hm((b+J^0dQa6;Y8K&RgE7qLq z+rjChj}v3-hf<%g z8?8S31scpI-8s7*FW`HkPuh$k(0hJoSmI4719}19bt-y4`PDHLJw}+Dz2_8@u}99A q-P?KT$Db74$!(m0MXjF0?PqdN?AKGi%o@JMxpl>DuG@&L8u>4o$F|J? literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/c4d.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/c4d.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62994da7a372dd446ff991e89eb2b1f38f863865 GIT binary patch literal 6241 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/css.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/css.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1673b0743b8c26007a9828f0d61ff3ff8b4e8d1 GIT binary patch literal 1722 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 T4edi=31f=DPE=aUT^Rf?WJ=VB literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/default.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94ca6691a6257d6e13d45455484f99d08fb8b88c GIT binary patch literal 1723 zcmb7Edo)ye9RJ;W=W)##W+cd?Dw zYo#zPDW#VlC>%sJ$q2P*9m(3#J2qy2Q>nB6v}Zr}-rxP5@9X})pYQj6wGXx3fbQq* z>kSYD00dq@+XIANNzzCF{QZG7000L_h7=Is4r;*^_yB5;b%x`}z*%+b_xP`b*9uBp=z6Q#t z)b6dQ*&<+e#1|cL{qV}{XUF{8niLqQBxG*M!h(_B?v3dbz0kSST%d8N+vPbOY1Fq% zlVSka0*_+}KS>}#F29|MKqR4L+=T0lV00s=?W;0dg z;m2iV=b{dsn!2Rc*fjoyX8uUcyj%6f@|Mip@}_DT{{ib=7zmLeoPc|Ks6iL|YkfK* z#TJWCETt*~vy_25g~wXip{Fl-TYI6K4G8*Vo(qB9CSR}opYsrpHJhM0T+p2;VlvWN`>Ud^+ z%Lpb8@i`HgsQ~f(jsZGu;G&}jBam=R?{fg4DHpA6;|jujHlYnN)HvvyvL_*pb6|@mZ;D*}pvLUjN5T zm!Q3c0~Zu2_nxVYSx01k?fC~Xu};%fFLv`1>y9IX8HW^cvQ9~Gvq9gS$md}TVt?{E z99}4-7z4+^tNCMz1Nf_~;VzX$<8-6Y;S~i6NoIZ`A$Z?uXU`@#S0{OyO=QOIzGWsV zf0Oe?W`)9>p%hYS{q=_<)spuSe-bmQtrS@&+w7IX!a>uul>5`f>W1_3ona310;7u2 z=DNE+ScPbN4`rkDmL7lI`{azpyY{tMwEkw%#bj^Tf92-0+wB;yg3hZ{MQDy((tLHd z9)586MA6z7pHo#)4wNl9S(;bD^2g3oeO00t9_doM6ZR-Me0d5*B02f<`2J+tzUB^xsw$-=h(aIt}B8! zd)%u$M$P`#wK0bdi$g>SLEH?{8A{2P0c+%UK>PU_Bu?Wp_Fna z+IyK^znU=El(C+3qSvLKZz~oopx<&-K#}{}HWb`Gd4`R)8)^j&MBK>OUL5y?K_^V{SwLa9qbh ztB->5;qYmkz>fS3eJ*?>mb?@Ih^9AnD=>#E0l?)uy{&70`hPY5CxaPu_{XDgpn`Eg zLhS*a8z6KS=dwkqW$K=x@yQ^dzYbmN>vZq5Sr6ioPO&LiIn?igi|~B6*m9%Y6uWL& zBjU$zIf$ooUn1 zvVu*2GwB28Z2NFT#NeE&r-h65wZuG{0c`!OTkA=0lTmrhd}>hbinMz4uRg*VqXNie?duRZe~?#ib7JQf>(g6dv0c4rh>7arJj+VsgHtZ zUP)?EUSf`dL4}z`ilLc#Qu6=X49*NpjEo?}#LNT&%&g2Hz{bMD%*xKj&d$!p#>URU z!^O_Q&B4aT#mB|X!^6wV%g)8e&&SITWb%Lv0cr>82kB+y;b7z7AsPHX#30DQ5Y14< z%&5e`B*@4t$oT&VgACC7K!ZVH00V3stn7?T%q&1z5m5M{g8#P|c!0{81egVYL3a{G zk};9Py_(e3|5?vS72aZ)-Kgj-Dh!C+HLN%&+prOP90uT?l%pn$@Mb~Tc2DWCjf<*)q7-jH86l&r7Xa}$il?L$O^Zf1?Y7)Ms@}R0YMQ_F^2@8GdO^b zV`OFeCob{zjM&-<({k6E$VpDSe3Yl@a0!#u*Qu&Jyw9Enq+McuqmjNVVe!APRF1IiIK!Owa^cj5w|`XU7g&A`e%!a<&~Db~XV0~{C%nu&v*~GCshCE+ z-mYm<+s@UtRj*o^tF$Ud^pf3y`zp^_+Opnn6i@We4t6s*HFfIq&;J=f!6gWHFVH_A z5CC>3Gb5utqca`_z|;XzU?KoaEKE%7tgM_60~kOtA;=&kplD#|=oBcd5LDQxWHj;M zLsn&DhlIqUi;tio!Di3&mq%r?u1xyz_wqi~p{2U&0SxjyVoeLRbWa^tPFys}tjp!z z8lAGvZ#^exMVcO3KB4sUJHdplf&IHCKdH~L$>G{1vxc8})6(S+O&a~DF*PQbGA=l> z;jESB#)-N4emnXWsht;D^x(x?hYhQG?AJZsw6J*hmXjaFe!iGwecNj4ejll_r8D-v zFIxp{Z|e@vWv_UnO@R!in2*ZSD+m0Y%>Pw~Rs^vi6s1TF>@?%%6_Irrw; zSTDCqmnA$gll-6A1A|mU0GJAxSXkJYp#jFgD9E5_=oq+Az#ws=LSf^^iys^k4#Lul zz2aX{2F|Edy_Ar>`!@RZEXaQ)Uv)%xJ-=Gutr@B=j%U~ob#C)1OSw&*`PwIg#2WL12kOzTz4hgUrOlV+W;L&IT zig7Y1z+~_wG*C(uAe0ip3Y0+M3M_08B>*T~9Ss8;1q>1rCl+3Whp51Z5Qh$isbv~M z5wFg)$%Vd}mZKN=R{U9?o1Mjs{ZXE;#QZ-V6MA0o{ZPc(&~>YBcyD{X?7ZXT8+J2N z7A?|nT7SWI<(7cDMaGZvG`_}22r@`8aIu9jy?QiL{gTF^MP;JXbgP87Iqo#&ZceFU z)G>B_K2!E>*(Akv4$~gQS;d^5qU!i&=CVhZTMcA7*F8(zs_)?y>$%A};^a&ACU&mE k2M4!2ICkTbdEx!tac;scrRm8%Q|h06U3F#UJo*1O0kXjJJOBUy literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/doc.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/doc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c0e14b3f4b883770eb061827cc9eb8497a75805f GIT binary patch literal 2511 zcmb7FdpuNI8(w?wx$H3PVM3HJya^&U|}1r@sFE*8c7NTfhD6^}g$U_OqT>{z%>jFlR?6 zM*u+pK==jZ{lJ#DGc*_gH#e{V0DuB0DHIU!8IA%S{00CnhQGgwDMr4}Hz+{)-@wWv zLL3?v8nY>gF5E?T_T;S!3k?sYTbeC3voN!Er8|X-H*F6O*h)9w8604-SjY;tmOlpe z0EQ44fnXSc6$2q6ia{a}$V4)UOeT{k6g8@fk{YUvQYcEQ8pPmVVTK$IbeuRUh6rfd75}SK~((HDb3@;YcxOm zu*9c;&IEwu+SqlspZAG<-@rf)JpLmGPM?eHE2P&~i9V^knv#Q{(eT28iQPzC2*;Wz z3%cVLJET~yFWmNpdyZrM!q=~~P9EMyFML(tCG*N2iYG_fKbBL2AZK9V+NG7*NSe zIai3+Yls&^Adr46877i&LZ}cnlWxIAHOyHwTfBA@=L90cazNr9`SDlWnTmToFvgwT zb0<2lx+6a>-&1lgq)x3vx<=4CLpx-3{Z#f$v(2I7FOyGBEBOyMs|u|yF-0_SZpZD% zZuWKW2If7ymQp>nz0s?Qba=q+=e)EM*CRAekzpV@SZ(ONR&8Q%B2lTfoqg<(PvUBA zw>4^WrnA~4k67+wdvapmwLLFyD0AU3*rI0+J#kAP3?&|67Mfa9jJ1D{DRc6v9&-&$ zip>(iybZDfk6X)P2St5d&Yn(rMyJz@9Z%+)Yz;YE>0==9Fs`2ZCE!bXSMvvpw9ow4bC4I+A?EM7}GeK@>ZkM@QjC4 zXQHS>r~R1D@{K21IsMo}`s-A^4xRgUZ%6I7n;oS{3Oqj-ccw+5?#SB)hEt82h$7N^ z?@O-1lP;hF7!Yyck-ueyV1N)Xbt09;NFZrsRMO3@R@y%w{+b+CBnLMQSge#ZS7D$= z(7+2r%`+p8(qP)!9%g5!&1h(vhfmHZukuM!fR6a}u34^^Bg5GKAMzuon8$`j&Lrjx z&X4;j;pgvJ5_q`$pyA-v-9txzx{z6J!1h1*Jbz2g$|E)omnD>pUpUu&?n_d`uPzEO+chLyX5%! z`g!v$trpv^bl?m8h1>UKWL33)_*Z5mE%_mdJct|7&%F6Sa?DR< z$jc~mX#9`f9vgdyj=!i#wXnNRaB)pnvnG3E@-tsiuGzNRE|dG6y1L!Veb6|Kb>oRt z!lSb3;56lCFZT)8tqlzKsn|I!v1_IN6+yX9f<~j4XqAP*`?U)fvkznKmOJL=V@kcq4uQC)eFw>6;K7$k&={vP6*R#@{Ym zZ?(+IJ7WH1$S%Cc2KhN-O%b^*aQuSA;jBLPjXG%KR+))<1*G^&`A3X^UvZ zNN;Lw9xKYPVq{j23-R2X&{; zlGSTDTqXGM(`M%0e&p)w2=YR0GO{?EPum27Av5>&Mu&}p2n}gl&ozxi)kdZ!`Pdj2 zPu=rm!`y14QQ|C~t2WJh+p~(;>5WG=e2jmRjzxGT8x;rrP309CrWT>0&pq(czjm6h z3}Gl{N5GtbOt0Zm%0liFE!dyOQW99wdu;Ih!OmY7v{1U<6e&g`4@u=PHj^5g2pCim3hHA zi}A=zJTmS^2=SX4;gK=?m)Qkm(D^0ikqMRc-+c)4Zu66a*Ouj0hY~a))6u8*Oucrb z9q_)?kQrsPuXn01DM7ozZ?9zfz?FR29pTs{^Huah@9re4j%_Z3Mf5qkQl9apjb-jJ z^mxZx_PKa=yhA~-qDB3Xor*h(9TpIoV9RgsA0F|~_-6xnhvH)6^lWeBR!c$7d`Qdv z%aiqXC%TPztNRFo18BlE8+onC@aOEb3~0KiJya^&U|}1r@sFE*8c7NTfhD6^}g$U_OqT>{z%>jFlR?6 zM*u+pK==jZ{lJ#DGc*_gH#e{V0DuB0DHIU!8IA%S{00CnhQGgwDMr4}Hz+{)-@wWv zLL3?v8nY>gF5E?T_T;S!3k?sYTbeC3voN!Er8|X-H*F6O*h)9w8604-SjY;tmOlpe z0EQ44fnXSc6$2q6ia{a}$V4)UOeT{k6g8@fk{YUvQYcEQ8pPmVVTK$IbeuRUh6rfd75}SK~((HDb3@;YcxOm zu*9c;&IEwu+SqlspZAG<-@rf)JpLmGPM?eHE2P&~i9V^knv#Q{(eT28iQPzC2*;Wz z3%cVLJET~yFWmNpdyZrM!q=~~P9EMyFML(tCG*N2iYG_fKbBL2AZK9V+NG7*NSe zIai3+Yls&^Adr46877i&LZ}cnlWxIAHOyHwTfBA@=L90cazNr9`SDlWnTmToFvgwT zb0<2lx+6a>-&1lgq)x3vx<=4CLpx-3{Z#f$v(2I7FOyGBEBOyMs|u|yF-0_SZpZD% zZuWKW2If7ymQp>nz0s?Qba=q+=e)EM*CRAekzpV@SZ(ONR&8Q%B2lTfoqg<(PvUBA zw>4^WrnA~4k67+wdvapmwLLFyD0AU3*rI0+J#kAP3?&|67Mfa9jJ1D{DRc6v9&-&$ zip>(iybZDfk6X)P2St5d&Yn(rMyJz@9Z%+)Yz;YE>0==9Fs`2ZCE!bXSMvvpw9ow4bC4I+A?EM7}GeK@>ZkM@QjC4 zXQHS>r~R1D@{K21IsMo}`s-A^4xRgUZ%6I7n;oS{3Oqj-ccw+5?#SB)hEt82h$7N^ z?@O-1lP;hF7!Yyck-ueyV1N)Xbt09;NFZrsRMO3@R@y%w{+b+CBnLMQSge#ZS7D$= z(7+2r%`+p8(qP)!9%g5!&1h(vhfmHZukuM!fR6a}u34^^Bg5GKAMzuon8$`j&Lrjx z&X4;j;pgvJ5_q`$pyA-v-9txzx{z6J!1h1*Jbz2g$|E)omnD>pUpUu&?n_d`uPzEO+chLyX5%! z`g!v$trpv^bl?m8h1>UKWL33)_*Z5mE%_mdJct|7&%F6Sa?DR< z$jc~mX#9`f9vgdyj=!i#wXnNRaB)pnvnG3E@-tsiuGzNRE|dG6y1L!Veb6|Kb>oRt z!lSb3;56lCFZT)8tqlzKsn|I!v1_IN6+yX9f<~j4XqAP*`?U)fvkznKmOJL=V@kcq4uQC)eFw>6;K7$k&={vP6*R#@{Ym zZ?(+IJ7WH1$S%Cc2KhN-O%b^*aQuSA;jBLPjXG%KR+))<1*G^&`A3X^UvZ zNN;Lw9xKYPVq{j23-R2X&{; zlGSTDTqXGM(`M%0e&p)w2=YR0GO{?EPum27Av5>&Mu&}p2n}gl&ozxi)kdZ!`Pdj2 zPu=rm!`y14QQ|C~t2WJh+p~(;>5WG=e2jmRjzxGT8x;rrP309CrWT>0&pq(czjm6h z3}Gl{N5GtbOt0Zm%0liFE!dyOQW99wdu;Ih!OmY7v{1U<6e&g`4@u=PHj^5g2pCim3hHA zi}A=zJTmS^2=SX4;gK=?m)Qkm(D^0ikqMRc-+c)4Zu66a*Ouj0hY~a))6u8*Oucrb z9q_)?kQrsPuXn01DM7ozZ?9zfz?FR29pTs{^Huah@9re4j%_Z3Mf5qkQl9apjb-jJ z^mxZx_PKa=yhA~-qDB3Xor*h(9TpIoV9RgsA0F|~_-6xnhvH)6^lWeBR!c$7d`Qdv z%aiqXC%TPztNRFo18BlE8+onC@aOEb3~0KiFDfS~H6|!kh+9m>3!x z0xT>5aQ)x`m}KBL1EjYH0GOHrasU7v1z2Ld0k#9~Km-szcmd$h>qCG46ZV?*@4Vx$ zN#+kg^OhGP2odOoxOeu_MI}H}&)AghmxcrSgO~h+Juz@5aWomIW?Oj3k-1FQd%$c0 zc#i^(Ko~0vFK~#Lg_W0u*$RjqSY~JWgZ@}{Ft8kAWn({l%483E&V5E9)UP zR(AGZW>_K*<^eWd_LJw7uO2>S;d(^epHJn{v)rQ+dR5K*mc7*Tm)rs#b8rd>3W0*^bbEv;?s9lv*W_4N-74h@ftj*%%d-)86L zzb`D(*48&Rw|>&McYfhw0a*Wpbuj*k?Em08a01IAHa1qaBfoI59J>DtI4>LfIpxDA zuUZ^&^*<%9^5`g^-m~1QW)6u04^QvS?+AnB-Ap6&VJ^r_l{TA-KQj3SXI=Q8q^D=#Z`=m-~*Oic#@9Xbm|U0gaR_r|?zb}@ZSz{nhU>!Jyv zBv;a;E}U(l4g{ddPe@pp56lI=eum#+~4*(1cN#>R>& zXH0$DkDYHw$GG}^Rnd8`peB7Q%s)6=v>sF`Za*ZurquXUhaSQI|1e_U2!F zh)(>4FFZcLvb!C#)B@!Rta{Er%-PfR8q68Qmp4j1v0hA|+Oz4nkZdw}zi=-hd2&fO z2VW}C@iX`RfFxdPMfdZOZw7(pm)d(6(7K8*i4yb@>;rJ*iyaTE4STAD%xn<-7)KIT z0E6p(CqI8_&S$%XLfcgOyo+BBjlfkc3L6op&;isI^0$BzFeW>yuEAW zyGXyq&Yz8IdqwooX~dJCP=N@Pe`y3fp(QJ^@qD9CH;1k;J!fCF{^!MA)sIz~4$ksd z*uKaa?%NndN}a5cbuE!0pSixPIfk+;7ImNO8-%_iEQqcBZ1>}&KIf-k&QLCygCtr; zqg~FmlLS-rTb@dMf~7+~SW}<1Pge!Kt;_5SGb}%9n4OMQu$U!KD;tlZdWq5u;YtvS zw)1_9PS{~V(XFoSk@oed5JvJmBcM^93Czu;(xa)1Jcq}So-VyQ=CB#Xqe$YoWyVz+ zdkzLwU@ZALA*9Bk5ffPeH&K-LTP{v#MSHvEfG8;-$BWo<&XqDOM}H8!&wsvX7UZpl z>@-opN;NBdi{&>l=D=T~zi)~z9kbIDPgp_f zGXXssKN7Suf^eAHO=JRwjSskV0?SegZ z^`VY)`GSUv(hz%1evy|$($`lV&+pw%ZP8KhIh}C2_ruNKKjmEuk`73NRy0%IZcyux zW_TH6%jg-oX9*Ap#Jpi+-<@%Z-c5$aIhj(1V@C-*RB8TsEf?v8K=+tWD$B`AZMT

~yju=_>uu*lZ*+Of!ulMa&( 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 I;$e>dH<`FnivR!s literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/dxf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/dxf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7041cbe6f750106d9461dce3648976613f6cef82 GIT binary patch literal 5419 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 R2Z9KsF=E#Y5-ahq@dHtmFyR0I literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/fla.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/fla.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41bd2ec10832000d145e32e4652a41a932b64cc2 GIT binary patch literal 1859 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/folder_back.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/folder_back.png new file mode 100644 index 0000000000000000000000000000000000000000..dc0786ec6cea1394a7bd1c394727ce9604c9141b GIT binary patch literal 1128 zcmeAS@N?(olHy`uVBq!ia0vp^RX`lg!3-q3%M)E07#M2L^NvAv_Sw|~OKsWav-ShQ@-+I8zUZQinN`;MKvcJJMP;NX#? zr_Y={cj5AtYu9hzx&QFV(`PT2FPYU7|t)Hku3cJ}G-&`8KU6hAq87==kjTKgss` z3im7Prq4Y3|MX{@^I+sJ+563aVM>$D(hVQ4ggNY6+j#l@iR@3gyfG@Wm8?>Wc&ze_ zi%Ql!NxjWz#Gk2bl(bYlYRjHQA^OHCo?nusOZqNuiu<>VF{4JNat;cS?{w6kwl+^nZGMyT_}1@~(|4b`Rj$vmG!~4%eUWdGvtt+AyJJr~xZ4FB zH20p+@m5sjlIUFTd;0W=1(s89X;)4)OUn87^~;sbpPn4~@#Dsg7efA7a(8zd7yUhS zbKxSdm1_(8^fcXbj`o(6N#|@X@p0Lv_D48-ZE>Fs&*W1te)Iec*O7NvzUdc_ZnW@K zi*#)nztpWvUTgIJR+@b+w14~dIW4^Kd-mDcpKMT#?^!cAwpZUXC<(25)zVb5ySm9# zJyAio!Oq^ais@}a14BRtdn!Y-+0W_a7ooAaCw|FmjY&OoIxYiKEQ6=3pUXO@geCwO CHQzk| literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gif.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gif.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c771ca3c3e3c87d3eb8409538ccc6187ddd717c GIT binary patch literal 1979 zcmb7Ed010d7QgSkY%GEI0*Gvx5D=BNOcIcQm4OI?AdG-4Wvc`T$|^x%6qk|@6gTBQ}GN)XB1Fc$jnocHeg?z`tZzq8%nQ4Op9 z18^^QPj`SI03h%Iswv>I?Lb^C06spz8UR28NKPCe!5!2BW4Hi7tI?H{%xY|9AEs8S zmVn*Pl(e{{xJ*$DE9xN2%XgbcQe1Kz%htxxhG(&w1S1gD4VX9rFhpIZ6(LioBpL>F zCh!=>{bwCULQtqzDS$Qxl{kjO`jz~}U^;8X9DvQr4{T#aLx#g;wN>?TQd_yyZ+d~( zq;oV2Tz=4GpHX%CMC;__=9ct@za4(O)}#IK&F_n(^1JfKkxiP$038gvAiF$NKl_z) z!oH8*OzU);k@>vLHV=qzt$Kv8U1bd`{%BPXHBr* zSoX%l6GpSOMoia@hVT3Wj)gvT+(XVwHypA0Fu3jSBNoG~ri!L^w+X53Gbe-Ga|zQK zi-EI8ilSQ&9h)hy4Y5zgvvNyA`i@p~TU0arYbx$!G>fCO{VmNxUdb=K`!X^L;?+Hw1MG%z0^jPK$HfJlB=dzp$?1nS4$PKTwZfq+fYJ;x0J`2AP z#r+{U{Os%@i@}(q-f4Mm@$9%@rZdF+D*+G`!)RK6f`qr4OfVp1K z3ZwRk;&By#0rJ)TLr_f`iTW-?RNYX5LDn3Rhorg;C$+AmP*_r*c^6VX^Uz)7_aAcv;)*I|?w`BmI&rapy8n}+F; zp^?FLTe349Lwf^CdX)i~B*|pFVcEdL?s$g7w6ZeLlVVy^(B$>P;FsX_p|0Ed+P^op z@p<^EJT>|9iPOdDpV@_<|J?K6Jte8>o}q$kUO%XSD1>A1^K?n>?w(h>VcD(JWk)Fp zd4<{tAk4V}j-OC0e~zqq9&q;i?>x=7&)-3!hS^psW*<&>pB|qO zC5K9s`rbgdXR>fXPHd`~}tVwP*?UKj} zBR18Q?o)xKrS!>xMu)^fn{=aQR3<^my$E9OXKF48XfDy8r_egQ4jikEOh)MKM7^BNzO)QszL-nJP3BZvLf zLP;Gaeo1|lr{C{(@O)!LxlYuq%^B0%_nvVA7^NCdmbqey!+{IQfvosLV9$WS4`*?n z`$h`IlCG7O;R||i&r7|xvhSw(ZPRzr!_kTSc;%@=hm((b+J^0dQa6;Y8K&RgE7qLq z+rjChj}v3-hf<%g z8?8S31scpI-8s7*FW`HkPuh$k(0hJoSmI4719}19bt-y4`PDHLJw}+Dz2_8@u}99A q-P?KT$Db74$!(m0MXjF0?PqdN?AKGi%o@JMxpl>DuG@&L8u>4o$F|J? literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gz.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/gz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36d159166e47d37b44fd4ed6dd800c2eca16f903 GIT binary patch literal 1718 zcmb7EdpuNG96$Hod3lWH65}z}jFeQXnPG}z8A+&Nrc$J0@-Bvv3aQ3!QlgDYeaPlf z5?fw9cGvcx6urIrc&iqxQh9$$W%gV)yZh&U&*z@cx#xGz{eFM1t87+22Mkvy7bk!q z03dJxP$MFPF2;Ip+TRaPNy@8kHG81 zO*ITtW76m}=KqGW3g9&04Pr6G7@#$i3;`$uW558`CqAma(JCAD43`Eeao)5>W%2iS>b!Ts@wZteVlM_ zj9DQZ(mQ{0q!;_M=QIAto^Q))oAvrg=}w*RqGi3S7w)MYP0qZs-7tvNJowO>UpcG< zK3Bb#VzwZyrmf=%y}8!ui(1AQO9>)+vYuI=?U7`*+eFOY@xZG5}fwnuTW zifL1vjuu=hd1WMm8ccBj=@3L^S_6z3Mj}%fI7gGs$2CthC5H1u4O)>=Lu*J`(^dwAg9 zn`=-a7iNhlDeAOD*ermAGc>h0v$#A6Wy=^F^^kKQUFZ??j$B zD?9haWcHZz!f*6r2jZ*!Gq0E5+hEHtlVi@oy+=1UAF8$s7U}+GDPeo$uVk)uF|er` z75vaJ-$?s?a9fkk?FEA2aWB*RKKhlfPW)(A9E9yn$=of9EBa98e*6Y;aH%zRm>a%W z9%ptUE$-aU%jCC0&2{`Qrwnh-|7G8ZL>(IQ|R9vS7&@~R> z8Wq4c`3eN*00x&Qkq(G`D|5cqo*idIoa^j-RCmShF|=6IIr>Ns&$uY(f;AG3-PH~3 z?@R1sFPjiK(0^AA zVBkECu$0Y}#t%s3sX29%;)$ANbSo0b5J83aTTpR!V#TPR&&iz?O?zHqhZ`Q>G;r+< z-SFNcBiF@YJVFufR?}_omZi4o&F!6#$YiQLNQAg4AOL4@ctVMk&6TGP1dt?EX*!=IdZXNJaxP1_c3b6))-Gab04 zf|IJEwrG3Lz$$Knd7`Tkq@2Y7@E=e4Pf`G6WN_^zQn?s%PN#)2AY)lYj8+|@B*}P literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/html.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/html.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a1af20d076fc5c79e6db7996e79bfefe2f241a7b GIT binary patch literal 2152 zcmb7_dpK0<9>?Fc)?68yam%GN!xlPdh^?_>u;nf@qlC~5%{ikQxr@Ck_XvqI)seJK zbcS3qDzwEGC6}JLuBk}sq)z9-oHbL~XP^JhZ>{yL_g%mDeV@;cILWB_0agis*aZJ;L)5sb)V@YV2G9E=b!sB@jd z2avBG^o?L(EDpjGWRCy|-35~oG8)0W0&%N6sQ+bJfks|TlcoRw^zL!^wypj5f`^^5 zUa{=#vC4XtFLj02lefI|31S!+Rtx~JZf=n8wO*7|ZgqEESa*0I85jEHEEL0#3?K{) zA=uU9aR>&B2N0~TMc1HiWN}d%0?G3*nIL@=Yg7#9hXOT zFL;WMa@|j8rxl&r_i*P8s-&%Dqu`qz0ey+O>XT~le8Uy3`G0!3l(+Z<)Q9?X^N$!1 ztBcz6ZR5v0LfuWFgl=m=lf6lOU@vX*)A}fjt+vLSo=5!lNCr?sGYWtZ7y~PhzZT-=CL|LjsI36oLm}@pdBEx>lY=XZm!09 zD&e0>UE2k=|2UP|6ZK83$;vD5C&dgQsHosd*S5ACGY&cno$5-?;PbL|pcyqe<{dIiO!%kdzD@JBofP@`ehsa8(x=t2zxl+l@! znzrC49#kNr1l z5@(hIhtq}EF9rHzl#DdH*O2V`bZcmjYg`i5eZBj=e&8Ik?qM8xYApHC@IaJ-)g9oE zT8NBWbQu0kn$Oi6QkH%pUbDu|rv=xUiv+jh9A@lyJN=TqO<4PMcVKCIX;m=e^2_;| z-bRxoBV`XUhE)Jn_B_yU?sd`@5S^AfZj97TJu|oHEk3Z)`%~je{G^byLV3ZT&OW#s zX?{1Ckri*l!+XoX8O(BmYC>+#!G~GDX8sh-43U%;-MfA^Oy7U%+oDVQ&K>+@N!Yyf zX5;D1t#AImq2Xwx)^RoMcz^xoi8Cpu?N{#K@*HJ55A7#d8$2qV;}=g6N7!oL$$-|6 zvwYKQV;(ldch{aaCxmR#Nl(^#hGAFC3`@f4wyv-mG%h;AF*R zCG}*c+-kvhozE4Wx4dn4V#D`Q2doMPSazg|l62nB;WZ(do%mY73UnOb#|*2KSle>< z7792)qUK^s*I3%#p+fwA!{YNpSWGo8g?CSfMm`FO}F^dB-tpnq|pp`lUa5`;lz`s;FtVhLz$ zo>Me6mF_5A?R@gGdtFMBd)w&`ZUy=A-6r+Ho%wp{6C08_6VJ}UbNKzU;faHibUILu zdoDK2e}7BI)#2;{t-mYh%9b@A86O0lpt6&%mPJe$@2c@O%2XAN&Yip<4h$K7{4a$Z zDM$dS;;XW*NRktqM~$XC7Jep?H#qs?wl;!%QQ;?XhBfoH)tmPN}=* z*@jyKJL=;=Hz|Gat%Ai+UN9Jd`(G9^oz3N;6(jvDH|QcJ`E_cR!w-ASj=e6|j)Pnr zh1w?rz4k}l-(TMqT5Xm{x}EpeSW9Kmk@CaV-u^bTDF?eQ3Xi||WKIeh;X1JDCHC90 zr%Me^xyyh literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/iso.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/iso.jpg new file mode 100644 index 0000000000000000000000000000000000000000..379f50667f68117eeaa2ced50fcc0ace9c45a143 GIT binary patch literal 1496 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 IMcNzx1#lOing9R* literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/jpg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c771ca3c3e3c87d3eb8409538ccc6187ddd717c GIT binary patch literal 1979 zcmb7Ed010d7QgSkY%GEI0*Gvx5D=BNOcIcQm4OI?AdG-4Wvc`T$|^x%6qk|@6gTBQ}GN)XB1Fc$jnocHeg?z`tZzq8%nQ4Op9 z18^^QPj`SI03h%Iswv>I?Lb^C06spz8UR28NKPCe!5!2BW4Hi7tI?H{%xY|9AEs8S zmVn*Pl(e{{xJ*$DE9xN2%XgbcQe1Kz%htxxhG(&w1S1gD4VX9rFhpIZ6(LioBpL>F zCh!=>{bwCULQtqzDS$Qxl{kjO`jz~}U^;8X9DvQr4{T#aLx#g;wN>?TQd_yyZ+d~( zq;oV2Tz=4GpHX%CMC;__=9ct@za4(O)}#IK&F_n(^1JfKkxiP$038gvAiF$NKl_z) z!oH8*OzU);k@>vLHV=qzt$Kv8U1bd`{%BPXHBr* zSoX%l6GpSOMoia@hVT3Wj)gvT+(XVwHypA0Fu3jSBNoG~ri!L^w+X53Gbe-Ga|zQK zi-EI8ilSQ&9h)hy4Y5zgvvNyA`i@p~TU0arYbx$!G>fCO{VmNxUdb=K`!X^L;?+Hw1MG%z0^jPK$HfJlB=dzp$?1nS4$PKTwZfq+fYJ;x0J`2AP z#r+{U{Os%@i@}(q-f4Mm@$9%@rZdF+D*+G`!)RK6f`qr4OfVp1K z3ZwRk;&By#0rJ)TLr_f`iTW-?RNYX5LDn3Rhorg;C$+AmP*_r*c^6VX^Uz)7_aAcv;)*I|?w`BmI&rapy8n}+F; zp^?FLTe349Lwf^CdX)i~B*|pFVcEdL?s$g7w6ZeLlVVy^(B$>P;FsX_p|0Ed+P^op z@p<^EJT>|9iPOdDpV@_<|J?K6Jte8>o}q$kUO%XSD1>A1^K?n>?w(h>VcD(JWk)Fp zd4<{tAk4V}j-OC0e~zqq9&q;i?>x=7&)-3!hS^psW*<&>pB|qO zC5K9s`rbgdXR>fXPHd`~}tVwP*?UKj} zBR18Q?o)xKrS!>xMu)^fn{=aQR3<^my$E9OXKF48XfDy8r_egQ4jikEOh)MKM7^BNzO)QszL-nJP3BZvLf zLP;Gaeo1|lr{C{(@O)!LxlYuq%^B0%_nvVA7^NCdmbqey!+{IQfvosLV9$WS4`*?n z`$h`IlCG7O;R||i&r7|xvhSw(ZPRzr!_kTSc;%@=hm((b+J^0dQa6;Y8K&RgE7qLq z+rjChj}v3-hf<%g z8?8S31scpI-8s7*FW`HkPuh$k(0hJoSmI4719}19bt-y4`PDHLJw}+Dz2_8@u}99A q-P?KT$Db74$!(m0MXjF0?PqdN?AKGi%o@JMxpl>DuG@&L8u>4o$F|J? literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/log.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/log.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec6d3e3f5f5b5ea808a90bb21ba75007d3802a95 GIT binary patch literal 1765 zcmb7EdpJ~S82`>W=HfEzj7yVC84N|ca+{J%lyNJ=P>B>vshN#RROmu-Yh82MbYX`? zs8FNwL=>XvGL(|gkdlYUsKsNt9|x&p7WjWy?pO^-{1FspZKNt4M5k~JJ|yW z0sz7uAQk`{yD-j90GLdm4*(znD4qkPuo-3rs@Mwv%!R*eBDl!+xwph9o&~0^`$9QE zoQQxORR3`5I+mS75N8jEYGSa;z}SH9Om*558nAzlUm(>mj7~Q(_4D@&5O)Dv07D3j zKroEJ5+FE40=$$o0Y|_S2n0NdBu|!;ktfO$NhHOe6lLWoBo&gpjM}1~Nb+(d5=9aO zTP|5Ciy*QTB8f=(-w@veWFqhe5eTFOU^0Y|A#npx$I3?_2_!Xs1%W7yL!=-)W>xx^ zdd@0-1>_J2z$k)Z)IAxSQ`6dvnf^-5$Qb?UW4~eso>>i#ak*ICe=x%RwrYT!+s}+Q z03hs&L+pf*{DKKA^xtQm_+k;zT`!i}DG zzlsUgSTZ`;52f&s6oSd$Aceyd0E{d!TnV9M1&XE(3(Jm(8eGmIJ>z!3=q+&niBj9~PTHA58?m9z}$Yxt;<@u~F8EN$8fH~+hR zHmu;|d2?*xtzpq~MSs?KK|@ISzysbMX&=)Nwdl>s>i6Gd^*b2d(h1|Yn$;&?DLUhp z$M*8v5zygnUK8UuQdE7A-($fZrKl{t?D>3n=nGjZ^k#7t(#^~hhQ?G0O9o)$b9-<9ET?xD{X+OE$ZZ+!BsDD8Ycti>2;Ihd?Bbaa<)XUb{b z!;XHTDs6?pIU{}dqnk$kw`wb@WLs-m*@oMd9IJM|vv(`?oa|Y)fPPq#d&GL4(h}da z>%om@77dy3S~+Qh+2wEFo;69(9$J02G1=#FnV(|Y^*)A4Vu-cX_+RXf&mxD3lN)1V z-_u(6bq9NRg%1n(%ks{i;})%mUuVB}b3CF!TJq$WwxD2YwBZ+>&1jaME@Rh<-tvgF z%ulsC!s^-HrVnC(ZKp1ZbtsITvG1J>k%610q0yQ#)bBVo@9rmTcji0UT2oXqptO)% zuaM3xpEx-3Qo8*bU)i*SmD995<+klwy)Iw7vixUH)skLlAGs4T;<&|c&mGSz~t+C@%A3y8MOuUXAGQO(0GNoFg5VvC*OLTzw6@8X<-?`t zD^+XUokpK>^-dJY(=~7Dfm(xzqA(4x!7kY! zp9b{5PQzCR3BNGFNdbZ+xC9Vc6QG7hZZ>QD#;B~|yb8YHJHO~uNqox8(WOqqN8nhQ z2(DKhHMJ1G;YRjxl;WX;pb5SznVWvkjt#U8wBEqtTsL=n8O^{Mbvw_BE^{mYSlX9x zF1)E$aEU%dQFc&`*VG&Fs*iW|++anvke=!99ebv#;y%uxT0}7(ExeT5G;s7R>sg0;Tf8-%H+AQ{bIqHKT*OJTGTVly_in$NlplnuaV~1Dof7W5*X6#M Rx=kP#X|PH7&OB1w`8S?lY>xl{ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/m4a.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/m4a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c6417c870d36a1433acfa810ec20ac75026b1d5 GIT binary patch literal 1529 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mid.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mid.jpg new file mode 100644 index 0000000000000000000000000000000000000000..176cd71a923a95c591c6e0c5da3e88377952ed24 GIT binary patch literal 1630 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 Hp3V9%0{PkZ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpeg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpeg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..50f99ff0a74487f5478ecf274344071a182ac813 GIT binary patch literal 1589 zcmb7DeK=HU6o2o%Gk3-`!@WMr(?&C95zYGWpqM2xRe)@DQ*8=4l$R?0>n?35C_ z;aRFFNs7VRNs(0Bl2E(JN5xYlTRuu{J=N@c$Flz2bD#IQ=f3Bj-}`%i=NwI&<_REH zt#Drf5Ci}OK0wnAM9ULon*dn78dw1Um;l)?12pKtD3}fx0BAlsv6GmOP541nQ1cns zd2fxCMadGw!?>Y4xT_?~-J)dCGVTIvCu>`4drz)=bZq#xXz3QNAR#ndDzFm@9W))l z6`%-)VhD<2C}kKOqYS6fFggQgFc>(FGni}^gE@tX<1Ag)6gHc~;V@Xbdb%7v=&~sg zm`-KFTsoVHGui*!G*GXQM?S*;qd#PQWxqce}P0tbr=i({+HBQnkRjG;mvvj~7d$!OTb zIdqhUV+>eC0YNTw(3gZjPE1&BgpPhZy^`1CpCf+yq9b8en(Dd#Ih`X5cGsuSF2pJG z8#(mrimSN;yHeCP@llNlqC}@}yQ>`s`kPK0?t5xp)^|NYK2*CXe)vlKdGFiPcMioF zhRLVeYHVWEG{O*<^x zr?*8IZI!0BxCpadC}9wc#v;cNsQQqAt`C!ihFmjSv5$0HYzAS(UtqUX;_DX@D*wJz zRoA*V`Pj9Ve>KBh&{022{lU22xt>J_Tz72_Ru%oVIrshNV=*js(($B}gC3I8BM$r# zW#zo8lKS1p>q?8|ip8_bd0vjHWlA&Uisrt?aJGYepniIA3x2#ymt%By`0C{xkD^!7 zsLGND&!$$qSn8U3Haj@^L`+x{f4gPN4(wIb`fj6?^nOB$-F

eCZ0wrm-f@}a>ynvifXXp@H=;Q@l= z3Pj=p?d_;0CHi%zHaIt@pZIjA)KqvW@>C>R$e0PUO-V|i@&3|cA|zKRCIlj>T$@hy zC(&)O&LoWU<-Ko~HCR>7$~5&5FV3R`=8g&cpT1yBU@@g`#@P9go(u8P!!#o!-^PgV z>VBxYtIuwxVtUwG#yd{?+;lBBjZ92Wb@i}wz5;}9O-KbPgcc` zGP?1zGQ^~1j+etVcIQ*_nGqiMTS%5=_OvHv-Bo|`e^TKfu=}myjf;DDdd0b^7do0Y QFchgdje#Jm3(ETNA2~qyvH$=8 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/mpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..daa2bc4633d71a8205d00348edea30d4a8ed9345 GIT binary patch literal 1532 zcmb7Dc~BE)6#sTN7a>b_MUG)m7EnQ@Gzm}yWdJEhFqq(xQaniH7{Vn;Vi9Uk6Q1Xuw8-~c2~1sKqSQD6sO08kw|x00>H=KL*m z&}aaj(sZ>dRh1ndNA1`{h0B6NQ&njy%ER5qUF7a1p~PwG_+4qr6iSfgB@)Fem7-YV zeGmjt1Vb?dMKP2%jET|4Vwka+Y!;i%X5l!W!L!1CgA{dDn^}rss4-?ZI%o>ZsHbYP*14eBT zlg&oxFM={KV;|r_2uffCT&Sdk;Pu*KqwMWg`4M57@9wV7wOBek*9jzHjP~AFGP_j-FDPEiSUrs(O!xWIE28jo`>g=ZQ;ye6xdGdwhv>VC_8*iX- z&zua)FL^91TsNGe)F5}C$WtyDbhitBJPT{0NPu7%a~^S!5E5HJ5tag>D8N(@h9LgP z^f~TCW!Ejg6`y5z%CEVRW;KiqBY+tkNGJ@HJ=YU-kOe4((FpA1jBz@kKv8JQYw(}gZ#p_Q}HQ?_BFV#ogW zHzcwA(SKx1LR%cFe2%t`I46Ez)!h7Y`}^D%XTuHM<0l=9?c@%@Q-;Cy!H0fos`Dys z9vF=1ROZEnY0|Cl+smtqt|W4kv)cpw+*Wm0#4G;ndEGPSUbMg6ZjJn?OaInMnZ)<6 z&DOrjV!znOl~z$NPv?Zb+2t+oJ6fB!*eU;!-n^vj=bNkhR}nK@7nU7Tlq$2U(QE^F_79N1k?hCvfk<%A%UYXP$`Ja(3UpI6zyHJit%@xsguQ7 z`W)t}T|GQ%e^{~f;4o8CqFz@$ZLd8xQ=j3?>rP0s6|@E=$E-={FqBs^@J*|uYr;_f zsL7t@2U(*hh9-v&jk+8zu%8l&hhUQTM_`9!&0)R&{W`nS|MI=43^JW1~Fi8ax zLP3Di)D*2cV(ReIz41>uU&Y=ptORY;ZvDsSo%|u%9*XXNV1SSW1t9pX;)oHx8OPV_ z4&zB!X?~{d!)cS`D4J8oe5{F6r67=slqoXi_#|ekMKddT{RcO`&^LrjqB?SwJ>?Pj z!hO%{)XWoA`QJLZ-quIwW}7L-bmalMwd?IyE$$ViT)iyxtk!(d{3$9k+iLZ>OZ_jM zE?SFwk0}Xf$+&`7Qzpz=bHK5;qh=?!@%1*HbA5w;dcX*_?M&20p0$o`YPoKwh%xs5 E3(f1;z5oCK literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odb.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4157e4570faf5b2e20efaff272e816ae735290 GIT binary patch literal 1748 zcmb7EYfw{16yAGpZW8h!2>~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da290dc7bb3c8b1bcc85a9d1dc48743d221b9517 GIT binary patch literal 1760 zcmb7Ddo+}37=OR-o0~FY#-%YX?F=d`nn7~utYM~U5r#I}!&=w25sJ*ZER~aJw-l1( zQsYt~vB+iH)RJtZGDo{zs9X|TZ4Fi}soD1{)SmropYOcqd(Zp4&-47=-}8Hvca#Hw z?kaK-0R#a6fgex~0{+@~$z}lD-GM0pfC7+o2_V27^a35Y06=Bv!bzeGTiE;IPUTx* z?YTWx5-CXx3uOlEoDLZvYOw<+5Ig97|OB8C_Ml!0IjMA;5>;qxIjoP&8Ik`Mx!f zfe!3rA0R*wWaT}e3Xf4bMu+sBITSDn{~y`ii@i3>O0J2{ORrW=-e{8j@#S#W262nA zz>NR?mTR)TFlX$AuxqlqvVZ3JsQp;8hqKyz~uRI0QpF4i6wG`F$h+ z1R{!&5C-6?vw3_caUcXkfiMvw`c~WZdE+?4v5r)h?5nc(NFRUXhLQ7~xO$Aq%8mUsBB+-_lyB)$VCFrfvt}|nd6@RZKSQ-~`-FtaJ@N zt#awlQ`6bq_FeVDE^C*!d#>uN+kV{B`NA2S7Z|ywugT);6LFVzK%hnp0J}_BfQjo0 z#Rv=y4wt8{Wyu#rr@TW7xpqXJ4gE5)Tp*gwk58`Pl<8YsY9CmcTgbb7;Z$c~Q;1Zb z2((9TFAAS=FA2^XC`gHPgaww(75LB&1jQJT4i48+T~mv}7ER#j|!$ad}h zbt1pH#jb+!+GV*_Z*%mUs_#!u1q_+=yJ?t?v<3ERM?N1dJe4Wqh+>rh*0H7I4?&2k zi?BJ$p?nE|p-$A`7zAk=a(R}{VlVHI=vpl&fp9}$aLkUBV)@`)8%U1mG)qTvdTDfg zDp@PIf04=qTSH&}!okzuI!jYJt{?W09MoxEn>{4mFKnppJ)1mG+FIUV^7oK`LcQ0S z8E2^y*m;|VF$+De^^N!$UnWS;vIkZl@_gl!0SL*$>3}1e#j={!-2J|`iqzNcyn>0b zBs0-Y*H=M_=Q|_?v+EAOsfk%hu5h_Z8}Qii-N@pb`TWpxCB{Rhw_~=_PqyonTM>30UN$<0(4RNv3Z5M`j4VJAImD*53yl5@lF)@4s@6w~6m z2{RV4m}f5E6@Ya*sYL7TZ%Znd!zJ`=)EJ1=Y*cv@=;QsLH+x zC#vUJdo8uny$yx>2&wL+~|2= z$Uoa<(h;J2H`@U3{=df>*qM9JPhn2E>+ZQdd^#J~CPw@qO(=c_ha0Wndj(~+$`^!B zm*e!>^nH?5-GM4>jTC-=nhoXE-%$WA$DYHv36$hq5iT_QNrQkbxwaVWQ5iW7M zJb%*_k0kdo=BCmJvYzJFy(iOl)^evvucVs0j5B`Fym92E`7J!<3S7|$i8QZgd^BNW zxIC|*lwx{xR;^+jc4nb1^x0KU5ATvWkq?qTXR)Ei3_)BbXr z4X;0cpw@wAl^0GQ9Ij8Vj0vc~^p+6{6nz~I5yeGmDE;80T7tjZsnGZ+!ISGphYhuc Z4$#L_PgjO4k@_VX812q>-|4Bm`w!SQM)d#y literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4157e4570faf5b2e20efaff272e816ae735290 GIT binary patch literal 1748 zcmb7EYfw{16yAGpZW8h!2>~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da290dc7bb3c8b1bcc85a9d1dc48743d221b9517 GIT binary patch literal 1760 zcmb7Ddo+}37=OR-o0~FY#-%YX?F=d`nn7~utYM~U5r#I}!&=w25sJ*ZER~aJw-l1( zQsYt~vB+iH)RJtZGDo{zs9X|TZ4Fi}soD1{)SmropYOcqd(Zp4&-47=-}8Hvca#Hw z?kaK-0R#a6fgex~0{+@~$z}lD-GM0pfC7+o2_V27^a35Y06=Bv!bzeGTiE;IPUTx* z?YTWx5-CXx3uOlEoDLZvYOw<+5Ig97|OB8C_Ml!0IjMA;5>;qxIjoP&8Ik`Mx!f zfe!3rA0R*wWaT}e3Xf4bMu+sBITSDn{~y`ii@i3>O0J2{ORrW=-e{8j@#S#W262nA zz>NR?mTR)TFlX$AuxqlqvVZ3JsQp;8hqKyz~uRI0QpF4i6wG`F$h+ z1R{!&5C-6?vw3_caUcXkfiMvw`c~WZdE+?4v5r)h?5nc(NFRUXhLQ7~xO$Aq%8mUsBB+-_lyB)$VCFrfvt}|nd6@RZKSQ-~`-FtaJ@N zt#awlQ`6bq_FeVDE^C*!d#>uN+kV{B`NA2S7Z|ywugT);6LFVzK%hnp0J}_BfQjo0 z#Rv=y4wt8{Wyu#rr@TW7xpqXJ4gE5)Tp*gwk58`Pl<8YsY9CmcTgbb7;Z$c~Q;1Zb z2((9TFAAS=FA2^XC`gHPgaww(75LB&1jQJT4i48+T~mv}7ER#j|!$ad}h zbt1pH#jb+!+GV*_Z*%mUs_#!u1q_+=yJ?t?v<3ERM?N1dJe4Wqh+>rh*0H7I4?&2k zi?BJ$p?nE|p-$A`7zAk=a(R}{VlVHI=vpl&fp9}$aLkUBV)@`)8%U1mG)qTvdTDfg zDp@PIf04=qTSH&}!okzuI!jYJt{?W09MoxEn>{4mFKnppJ)1mG+FIUV^7oK`LcQ0S z8E2^y*m;|VF$+De^^N!$UnWS;vIkZl@_gl!0SL*$>3}1e#j={!-2J|`iqzNcyn>0b zBs0-Y*H=M_=Q|_?v+EAOsfk%hu5h_Z8}Qii-N@pb`TWpxCB{Rhw_~=_PqyonTM>30UN$<0(4RNv3Z5M`j4VJAImD*53yl5@lF)@4s@6w~6m z2{RV4m}f5E6@Ya*sYL7TZ%Znd!zJ`=)EJ1=Y*cv@=;QsLH+x zC#vUJdo8uny$yx>2&wL+~|2= z$Uoa<(h;J2H`@U3{=df>*qM9JPhn2E>+ZQdd^#J~CPw@qO(=c_ha0Wndj(~+$`^!B zm*e!>^nH?5-GM4>jTC-=nhoXE-%$WA$DYHv36$hq5iT_QNrQkbxwaVWQ5iW7M zJb%*_k0kdo=BCmJvYzJFy(iOl)^evvucVs0j5B`Fym92E`7J!<3S7|$i8QZgd^BNW zxIC|*lwx{xR;^+jc4nb1^x0KU5ATvWkq?qTXR)Ei3_)BbXr z4X;0cpw@wAl^0GQ9Ij8Vj0vc~^p+6{6nz~I5yeGmDE;80T7tjZsnGZ+!ISGphYhuc Z4$#L_PgjO4k@_VX812q>-|4Bm`w!SQM)d#y literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ods.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ods.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4157e4570faf5b2e20efaff272e816ae735290 GIT binary patch literal 1748 zcmb7EYfw{16yAGpZW8h!2>~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/odt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4157e4570faf5b2e20efaff272e816ae735290 GIT binary patch literal 1748 zcmb7EYfw{16yAGpZW8h!2>~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ogg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ogg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e20ab2fcba8688bc85b520c7c8e54c8cb0870f52 GIT binary patch literal 1557 zcmb7EYfuwc7`?lj$0EdJNkUK=yP=|tA|{bXd1yc-0)h<#MFhnpfEalUp%f9Vg<{3l zN~N@lDWVh~o$81+GNK?l7%a6Y4l)6;f)BtNCfWQY>9)WU@DWSA zJbWzo!AgK47>Xe%ilJ0sbc_lH&4x*5GMG#zgT-PKb~D(xEzV+bXL4=r1S~i;V-9;J zi*3hZ38*HpoT{|NFk1o6!Ug|3EDeCbK^(}%5NCiA2u2_lJ(vTxj{%I*U^*B~93t6J zNhlvA{%(@SMCl9+w{!wKScGyg4ivEEN5dF7T|V{Yx~A36b=ZF^wz8`9p;;2?(C;R1 zxdWG`o9jLOdlQakIqVoY^nMXHyW*e%pr+%CgSFi!Hk=-NU4K&7OaJq4gG-zJ{Jb|k znUIQ*0}zY`$yj0ND2;(&OcCx42)P0h!XZ(Fj!rC>CVp%G)O^mUI{>)+jWtVjnfm>z zul0$}cHY_xk+WpYf_rt}4bTi1qQ38KKRc|iEPSscFQ}>L(DTT1UJ9jQ)9-hUU%n_d zhMu3_EQ|g;vGUfhCNJ$xef8G($&q>WQb=b$0qH;jn3WES(dYoN=aPYh&{-t*3|OI= z;soWBBBPlLIn^#$O4QEXt?KoiSCqLSfn+mlI4n$}%Umf~&PVzSo|lBJ%3vJU#1AyZ zZ9lGxpM6;6>1253#al8w_!)$pM*wI6Kx0}V5r_%w>C=!N0aJh|1vruY$KEyWA64u5 zJ|?4M(TssBV^!T%H@8gee6i=#phh|4^xd4`lw!f{)w1hec}c-pyJb6e9EB*0IFwrv zI+H#P15p5tfG|Q)1jkt%nDzO2o?M~)<*nijDLOH?C0SSchCO%CyZPT|!N5q~PjLhl%fj2H0PiBbARksh|i@O^_)@pTEQ%4yUF%(zJm&0ZRb)Au zhkGrar2Cq)heAG4=Mi?0xHJ{;cfxF4M4{l|^2Uv58JuX7Z2qzasr=H@+1l zytL_W-}6PP|j1@i(f0xGP=;=Fvhvw%%Edp!}hrY`L%8+9Bx;^zK%uP&c{F@&qC$+EAPi6!= z9#s6)A?_m_Ug%52TpkwddURN~k>7jS^}wvTH?&)lTo&|%^kog^@vrf2G$nKuE)Ez^ lY%te7Rb@%$qsyo0)s(es`YYfuavE z)~s?}1rP)P1U^8~5BSczq#*#fxd9^p00kfkQb2$sm<0=90|3oK=f1?`VRK`VGO3sX z%iJTjOSed4B%9blyV+|zoL#m^!=-F<6B`pV6N`0h*YNFj6hoDP5iw%F+YIVgFgYuDdr`_;d7;yq6grgrY}>O>TJQL# zib0D{SoP&ec~C>|vU--A-P>A`?FT;->7aFoC~53&h;bJGc2SD|8F_O0<_etx`^|jg zQ`-A<>RWdkw_C@Lsc8n}_Bei9@>R7od}BJKw+IJ-1PCN-mK^L56eHjqF3*gp&eY%w z93y4ZETM`kk&$j|1z5yUbqwf;noM9NihTCPz3dbjSNV>{M?a)DvPUM0&lOawxhEH_ zrW>Zbs%(ZB1~VAs&#EwuK~(3O&DY@Q@%Xb4s1jo0(GsifeCiP!?e^1slJ~`R79Z5V z^WQ#TqdQh9*xMub2+%up*3Xuibz`q($Y2gF@3#_{n0*k&k^!Je5h88gCmCAX;Lkp#xH9Yhe~|*w_a$udve$E_HFvry^@P6VR+VJ>|KZB52X%!Op_I$ zCO4aEWsz~IO7ls-i_89I*X|cdlSUm{67q>)qEAy|YS~cD$rrJ&=}u`A#XeyncJ@0H z-qujUhSfai4H@NqDntc%Y9Mz{44eqn)LHY8m3FG=55ofzFMQ9k_|ikE$Aa!G%sgNj zYmJV#ro3Yg_jvy4{;XWe$hXYZztCxscKU-bpo1qV&Yr(Pa4OOu_t5oU``4zjmK*?G4%Z?a5?C*8ro3ZPggiCk1>`lD# zD9%$Hf*dc9FaKie8DB=(~6BVgEp9^N_SL=86XiWB_u>{ho> zc(Faf3iaXYMVVw}HZ8>e_Q+=EJYFidFl5uFct> z(G|yD!I~c|X=F4t4*9jMEfgU#JHbmQ+Y|3wN`7osy70etBfCjH_fb3Vdxu!n_;>; z3|J8x?$_n*uRB1l9q999vYM_uDR-I3AIUMUO)z0;^{Bt{?)0N-pZB!(Z1}(~w3!?z YzC{g4`O>ny8r+H literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/otp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/otp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..802e78ccdd971db4d8429b0bd900befb86351b75 GIT binary patch literal 1870 zcmb7Edt4J&7QQo+nS_vp2}H0^N)kb+NKB%UhggD$6c!{K^wopN!XtrX7C_bQy#M-(Dlm_Dqs`$h{{82>9wxFgrD763fo8Qcwxo7VEzI)C+ z$9&Cv3y@*!Le~KV0RVv)Fy98!V6}2H01**j2>^fwkWwX}Knr?-BfJ4X8`1fZf<|oK zPOv!5&%uhw>|AB0vLG#$o088BlLd!lDzlW_Ty9s8lM!B&ak7ol3K&5llLZZp~mYnM^93Wy50H zK$Brv1Wvciw8k)N28~H${B4-e0X7XJfC3ER1C)(mY{YyXyb8AuwOQgc2b_u!GzyAA z?<>$@!JG@eDJYIm&BK6!!HFbB!uVajaJ4(-O(&!(i{J| zJi9cEydniXy}vvjMF*!puIu!&d&kfQ(3Fwp$8M{AkE&+s^RhGE^BR9JQgm6eP2V>x zDfbf*6E7B~LN$C6N(Bf?eK7=|6dc6}1PDnkPb8HkLs>K^7QxY{;(vi7$(>0XlCKIw z_^yL4hCcny+##Rt+E^RsVfR$G$!Go!LlOTk+h63vZYWyV!7=I{g!%V+&>y9&-BMf7 z#T?JN8Jf`GA9d?^PU*BpzSxg?V)7sMQz82chxq-BfxxkbEv6zU%99OHfZ@2+yeI^I zQ*gE|uZhDItF(NfXt^{nN~51u2SXizJjpq9(4Bhg!w%%JX=Uk~weRTMVq9bwa?u=i zyD72IZs?Uay`6g{$ZE}lhKduWM~{Z=hbtWxZZfSuz9i}VjXn=$x%$|+89;h33q1v+ z(6KpwNKaw&FkEZPRcY)NxC+IPKDxv>;5ui$Km+(V>$0ej_H))@pa!%FKqK|Y585&QxM|eUvt5$J(K-; z{Q0=T?Eetle%mj06>k?+R}{#~f~NMU{7#kz9Zqch$c^Q7G`KSQ(1!Om@kLHoGuoeg zRUdn4tEa(f>zU7b2~We@d8a1dPuX+v?6T2d;wHaGRYLCjdHenAYbe$~>T-_Vb@GV$ zsCb5x?s{s6-_e0RaYx(Z+A^1YdQM+Zn;(22Zq?F^`p^Guz5Df8y}S3vdvV*!i*<{} zd><~_yqLK-p(gaZON#z0^o>+P2cH*)h*jLwuW!&zAwGEvSE$neRmi( z4@=l66da#RA*@L@PZX#XM#)uDjovsROKvjUo;%$EyeZL+&-l<#G?NKr5t9wQZ9kcJcRngJeSWJ`wKQY1a zxxV}Mw4Gh!sI^2JrLLgF=BaqM<9JW6ZRoQ9#p$3U>S5(uyL)?l+G|+a-srpyrz1qt z-8V}3{^x{ZF?#to&9P78rz4@R*=7JNM-cXd7qE0z0C?rI1B?oQU9(#I!UJ3BdEm;1 zb&67m`C|(ZHsHxs+9s|D){0RmHO%hUQZMB6=C!Q5hXhaVDWqG2zIG=1yL#_@n2MoA zF{3+`-=;okQ=f_X-zO{8bZz}+MvLP>La|p#Z^U}fINmq;Q#Tu`4T|)iI=(+C?k)_N zqsCAIHn5klP&di7+`uT6MlTde|Ev`9X;ygMx(sZ=Qe({NRRgPBA2M8WCs_yGfnulU z&x~!#=NE74Dh5S+3-Q!9w2^9oaqLK$;AE%ctKXfu5+T^*bI(v3^YGdP#}#Y0Npi8U zlW^l0_LnARVOI%7QF0?G4U{Eo{!BFa+lv0~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ott.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ott.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a4157e4570faf5b2e20efaff272e816ae735290 GIT binary patch literal 1748 zcmb7EYfw{16yAGpZW8h!2>~OBlAuMzS3*Rwib+6-APAz>QHllvlvqXN9mHCSJQWZX zOMDGMsE=4HXrVz-p^Ohi6tpTbMU*O5r3Mg85l#1kqW#ey{qF4S&Ys=xeCOPA)^yL* z0oXoX-d+Gf06^deOb>z7Gf5QzfS(_50sv3}lBohDxPn$-0|x+TF*>@FT#Svbg9xMP z9hl`G9jDr$N)8X>hpPEL0iN;=swfp-JY((*=NT@(eDA2Z@R+EO^?YHHQZy&jRTS!C zY6BhsMKBaYP!vN6U^qsAOd?Tm3YkKokeN&tl|f@s=~O0@X3nKEcuXdfLNjNXGg%BK zlSh!i>%>huhS7OcCYATUVX6ZhDhL9}7-A1l4uWwIQ#}|5!^aQ^BE%8kWC{sEsnBRm z>|>vp03bmT6w`gcfZHe=W5e|6^4Iji`4jAK?lFPv$ky1V;Ju%p&YRaQnWkFf=l)8| zC?7e6L}&hd)$hgyyTYzuh2AHj?_^c;)_ESQrVplf>aQ@XFOD385+5|Lx1uU*>&DYv7yNmv zYmg_e29(*Ah37KGiDhl{#IKBTK5aoZnh3Y-$J3HF9*n1kpB}%5|NT6M`Ic?A$#c*D z{h;gFV%L>b>dsbI-=Klzwl!J3$&pQdmvY9MT|Zm-#JH8v$RPw`B}>XPmY~ z6I#@CI3?KxAp0Z^K}VvDk^=TSIm1MgKw71ClkiB1n6P1!E~{l+hC`to=Ft-6g2a%D$`|R;hqb;*kxwgPb#LE%(KN*|rF3$gUPUkHcX?wwr6_7le*4T2 zs|MeUy9(M`+HcvX{J)-@Yb9VbE*i4h5Ey)5aR2!lEXV{7S!n_^4F{jA!;CGvN-sIR zogK6FxWl9!er20aR*cDe(`Tc!%3kb$bb?;$7C-Q)Az35!T-#EV{;v9XCud93Wwp#Z zBGy}RaCO96pXHIO=gy2f7hmamM{N46M~IXSzz7J)7bs}&7bu3XHdMhkqMaBfhvPnyo{ z$kC$WG`F-cOZJ|7-JaPAofBW(JIPmaNqM#W;<)Xv`+diz@Ix22=Uvra6qdIL3|W>7 ztr?3V$c~1U3!Xm4w+%U3o^9xJaoW+!8|Ntbs_wKpDdR9hF`?y#{;41d6agbr-@Q~?tH zu|J_c$W$N@ic+=G07H+We1sFeA`pwU^Ky3g3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pdf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pdf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2080921c1ddef54ff2d192666250b86b47707fa4 GIT binary patch literal 2050 zcmb7FdpJ~U7k~HObHmUKMsi9sZXu=_m*VSU-0zo(N)bkeCPTnwV%D8wcquu{r-Nxwbr}E{o-LjaLW9>Aa;8U-ro4FFsWudW;~Mpk_X&E9>R#p}-Ew@Hab`9zhB_Bc4 zC7Eb0mPo)6i2t{Vn*o^syufh;QUfpu~zdX&dGfqo1VqF9O{@(HB8AEr@ih*7dOZzPuQ!* zGva*Gj?`H0HjGvsR4RP{@HMk9tvY`*PG}SxGb;&vtN`B3?$79SIkb8^jH6xJ3pkkl88m0H0C!3Y_H1vr|# zB2|rvH@Dz~D^Ltr>{D4K)ypVR!Ofum?CJ@n@TVrYeY71za+jO826c20DN4Qjo*R#K zjSsHBai_L8cin#W%;_Y|!WAa}>743A|N5}mNGe=xH*N2fW^#8>N4JpPOJ{X|#B8*D zc-he6--RK>GH>suotQ+|ZvS5|)?HkD{6%`u_w+k3bwORUaCr|m*u63(&*cK%?zQ^V zrALBJdxwG0EQVChO^vJW&7~Tx-J>WcH3=sS+HotCfP@pk$WyU2HKsZ%e3=F;p|Nlx z_^_#6!M=vNYLRs8lKcJme8)qAsNB-#*4pTwvt3JE2M>w7=CE4h-2u8+;(`t8gN~v* zn2;o@!8kl3`)v<&N-$V5kXN8Fmg`R*`-UQKSTLtYKfYW!h&BY9f0 zL-(_7!Gf>i8H!Fm=FcsgKb_Nc7&!2t$Uf2A_S0!s?(+jKHz)MUU)|q4kTF}{)*F4z zPHMtBRS+iNu>Bct!}xiR3;QTa9k+X|&y}gSjvonWq_h;Y{9Ldvx%|8QPdynatI_zfHoAekG@{evGS`1S%4pI2)4bNu zkCE*MDLcDzBNAQ?d7)*{BB3*mU?6mkzLfzY0~(WIjy5YNyqe`#($q7vGFfJ{MHP+o z7!tk{(yJ|2-@NJeqO;u{Wse5q3vKoz8uJzXMS9m?8`d^{myQzA(NE*`!>u4DYr#r z%H-XA%9eYpB5%PrOi5PjKi$SBLuOfHcW%AUXy41##=WR$9$~6k{?6<4D}FV3roXYo z_C?&Jnot=dpx-$x%BxfL>`mIZDRn3Y1+qgq&^&s`2PBEty_?-MTND|?`Cepj+OrNInQEV#+=<&QO*PV zNo$SHx)bnxd7shz(UFpE*DOsPmpq)L+BLI%nC8iTGkiv9&H2rKCMF(o^%;6|-d3vA c@aHkR&OiOwlJa4%n;AAy)jzAKAVNIwUy^9o$^ZZW literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/png.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/png.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c771ca3c3e3c87d3eb8409538ccc6187ddd717c GIT binary patch literal 1979 zcmb7Ed010d7QgSkY%GEI0*Gvx5D=BNOcIcQm4OI?AdG-4Wvc`T$|^x%6qk|@6gTBQ}GN)XB1Fc$jnocHeg?z`tZzq8%nQ4Op9 z18^^QPj`SI03h%Iswv>I?Lb^C06spz8UR28NKPCe!5!2BW4Hi7tI?H{%xY|9AEs8S zmVn*Pl(e{{xJ*$DE9xN2%XgbcQe1Kz%htxxhG(&w1S1gD4VX9rFhpIZ6(LioBpL>F zCh!=>{bwCULQtqzDS$Qxl{kjO`jz~}U^;8X9DvQr4{T#aLx#g;wN>?TQd_yyZ+d~( zq;oV2Tz=4GpHX%CMC;__=9ct@za4(O)}#IK&F_n(^1JfKkxiP$038gvAiF$NKl_z) z!oH8*OzU);k@>vLHV=qzt$Kv8U1bd`{%BPXHBr* zSoX%l6GpSOMoia@hVT3Wj)gvT+(XVwHypA0Fu3jSBNoG~ri!L^w+X53Gbe-Ga|zQK zi-EI8ilSQ&9h)hy4Y5zgvvNyA`i@p~TU0arYbx$!G>fCO{VmNxUdb=K`!X^L;?+Hw1MG%z0^jPK$HfJlB=dzp$?1nS4$PKTwZfq+fYJ;x0J`2AP z#r+{U{Os%@i@}(q-f4Mm@$9%@rZdF+D*+G`!)RK6f`qr4OfVp1K z3ZwRk;&By#0rJ)TLr_f`iTW-?RNYX5LDn3Rhorg;C$+AmP*_r*c^6VX^Uz)7_aAcv;)*I|?w`BmI&rapy8n}+F; zp^?FLTe349Lwf^CdX)i~B*|pFVcEdL?s$g7w6ZeLlVVy^(B$>P;FsX_p|0Ed+P^op z@p<^EJT>|9iPOdDpV@_<|J?K6Jte8>o}q$kUO%XSD1>A1^K?n>?w(h>VcD(JWk)Fp zd4<{tAk4V}j-OC0e~zqq9&q;i?>x=7&)-3!hS^psW*<&>pB|qO zC5K9s`rbgdXR>fXPHd`~}tVwP*?UKj} zBR18Q?o)xKrS!>xMu)^fn{=aQR3<^my$E9OXKF48XfDy8r_egQ4jikEOh)MKM7^BNzO)QszL-nJP3BZvLf zLP;Gaeo1|lr{C{(@O)!LxlYuq%^B0%_nvVA7^NCdmbqey!+{IQfvosLV9$WS4`*?n z`$h`IlCG7O;R||i&r7|xvhSw(ZPRzr!_kTSc;%@=hm((b+J^0dQa6;Y8K&RgE7qLq z+rjChj}v3-hf<%g z8?8S31scpI-8s7*FW`HkPuh$k(0hJoSmI4719}19bt-y4`PDHLJw}+Dz2_8@u}99A q-P?KT$Db74$!(m0MXjF0?PqdN?AKGi%o@JMxpl>DuG@&L8u>4o$F|J? literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ppt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/ppt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa13f733428128a02fb020ae18a70c8511142c39 GIT binary patch literal 2386 zcmb7FdpK0<8voW>Gh+ooD}f-nG{Ae9wBn_j`Z8_x4GiNCp7vXwS9> z5Ci~(JwP%DZ0wE&_yVwP8!!d{5CIeu0C3m}(*jNG0|3s2fBcEeMSiS3q)N#GFxwsy z77!c|>2rX}i=aAk?6w34915VWGg)t9YQl7)vJZv%gdXw^qSBA;_x9zn=nMAgtb~0{7kgTJ`4dfPKKz{( zVp}&pg`vOuH4eNNkF;i;Y8q0H5Uh-f&CI|E>7vqP;1GZ;vBlvLm>>fnItx`+U1r0< zh!HWu5FTEr>fF9+N3eVMR9|c%gYNzz(u_3B8A-U-pF#1k-q(F_B*e8jBSs~R)o7yW z?V+E1f^#ML@YX`O*0gbSuf=bo;pTvn*=FM?virJZc2Gh1d8^r!-CHcTYTpQXl^BzG z;&PVr)gg;~PQB%jBS}3}V|L}|Z-y`9&*@K04wxOU3^mQ{eKH>yqglR-d|gAQWw@?m z`oZ=Ec2*v>fPoXL?2+D#^R8>ch zzRrwk>n%(wdo{U87R#?S^eL#8>^yhX&+swVD*dO85v~smwJm$ad0O&ymd`CE;Gf0I z_wGGza;)mO_|=I832^h%FNp8at>M=8+6QUJY72^MmwzDvcZsZ&LpylcapA@8%Pyqu z(IYgrkGZ-e|E}p?)=)?8yS7cY+684BDD$;3%;qS-x*5jFBeLH^jA6zB3Lb+@XAn>o zny#&jcbKrO+>{@x%4FGac>7aC->ZsX4bOYEmX8*Erd~9n=CfJUagB?2&IFsh%#1#w zwadaGY5LB=cLVn9@utX9NVhs)wY`4FAK`my152i75)I~=EGMJ#OQEDq@mpJ;x;Lv` ze&NrW6KC$x5V}Sdva)T@Hil30ozJ|wqnVcDD63JD{k4!aiC_I?x%1Fo+T?FtW1@)p zH>Gd7C#$0M=FYUP)3@;OarW;LUVrW;8@S35Pkr{+>zLzeeO#O34{TLfPjz`-Qp@;{I*?Fx4ffe{7uzv-N?9-MAxGyGoYc=Tj#uQq*dqbh^&~nS#ROVYnpY} z>-96!+^EqX_K$q?=U13FKEKp{^rXOxMT+q8eJ%l+Sk4TkT@T~%Sl=(@i~@8RbXymZ zH(!uchIUR)*>D~#wZ65^e3{U`g{XJZ=8@2Zq42Vcpmo$CGe;Zdbm&}&n(+;J93{HK zKSi~Q-_w5MxNT^m(5d8$N7DqY%GBaff?03Rc`ikrDpoQc9+{jS?0VsB8mBERw3nkf z)C%oJh5~Z3*79T(4xtJcjyN9z%?B*DI(~ z3Jnm$9 zZ7q!mdsIBL(_ApHR5cKRfQ_X8RSiQ2s~T?sYQs+wm32;1zeB(-3~O{)#l?<-!PwAe z+&;Le6TSKALNc{D{9e!a!FX-l@Fi2Ou8QrZBl@;amRNu&3wdj4Tp9G}n zltou^Ns&S#N-Yy8;{@Z5goXjX3x+msK6z7bvz!t{WB#Jo1lKSXm3sLN^0LM0owxil zUi5}G7i$YDV+S+hBO+hHJ+i( z)$t0#t_l8g!}H#sU&CWB*IxE4?;gX6<7V2Q**?3y%iJ@Y{Yk^2YTws@w{VX~4MWoR EU*kK4SO5S3 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pptx.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/pptx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..85049696aed2ab58dda7b0adccd5fd70624528f9 GIT binary patch literal 2479 zcmb7FdpuNI8(uSeW{k^Zk4wT-gK<5{U|i>5hQyEuF^C!8dJgOW z8U>*t6dDbo#Rg#^vEeY15?BeGgoFf+K#(QM$jjmt@dSeWDtSdEC1qu0St-@Es)V&N z1Z5?05@fn~rZfaeE8z)vrT^QO?gJtoc!4+wr4GnrGJ17gaT+7f{_Z=o%!pP)6ZK=(^$S8;2UNiHNPF} zKF-+YVRSAvQT3a3*W%m;ug8lSe)YWg;*i+~5#BLW;d49B{+%biZ=EmC>D~f9+=(0a zi5AwxnY~GWs~j93mM|02)>Scgs;Y;_xK{f!)!P1&nANVeqNF3Nu7;z6zKnPE-g}#P zVf^`%_JW^z<~q3&^`}H#jeM?4!oT$=f~%@Ve_cddA_)*;6d0f|C#bh*k2aeyXm?|5D_wN!Us2-&C?eCtu8n*^- zbWT(jU--tMdMbh#dbjxDYL}tjbpe={RooW0FV5c_kLZn-6~1a~tFm0QZnyLGqc0S& zJ(@f|mA<8O~U&$abQ9T5W+gW*DJ_a_!XT~^w!{MTk@r zF(5ZrZmr>2R#tZZDmCN!`?dErLDIHJ0XSUTe{Qf(gVn(XKV9sk@b2 zN}g@r{AG-OEOu9`)2}ya&O>i&NH<{DAe$Ex(4&GD)3b}_K4~2@(FU%s5VSAWK{FGgdTy%XiHxeT}wB z_HFB719#_pN?mqq6Qb!HjsfN1;}C<^{10{WM=O$F9iDB^xR_$ns<$V$liobmrKmBI z)j!RN;f=PR`dvQFSMajj*}8o13%$sV>gw=#8(q3qO&H7LZkaYM%5Zw5J1;pHQ1;g$ zMFg@L(oYZsa5&sD<{yxWa#%I0Au~!|U4zZ3fhk5NzGoE3G={C4`~HY*{(oBxXMtwubP+^oDb`adX3ygLPbGBYEk?!w;d z_s?xgc|&)(II$VTJ|z<0Q47Mp_fisZGl3<$+_));vu%nh7dk9zdYdYavDp+YRQMI3jA_6r-DhFm~O_3SQLVm9s zH)(oV6>QWNP@}SIWN6po^DSXN;W}zbqT7XDN}lmcJt_ThhwFGiI<8x$YauC0b4fV! z^|In{W;efdU=mcRJt%Jo0h*$t_e}Wf`^bA{LW~zHmq6Vmzv$}ldn)cK3Mr21<=|{i zchXzOu#Vu4iU4=3w!WA}-Zz)cV~OzOjw^AKzeT!N<`{VPUro8vsV)rOlY4D| z^`_!$bLpzK?8bNJiQC%Z2E>W8SUYj?sK{GGE~Ng$3xWoXJl}u3Dr$>jA2W{#0~_V% ziupav*&_4_9b1y}mZUT5ybzW@)cuD%!aC&Rcyb~h;AH?Bj~h4zqw#t)2I9-y8$o

Pt^fOKD(e?!4mursha)Xj-HjME6lG= zhx;#0Mbm$*Z^&kHv&fvn8%g}1`X&|&n48k-Yq%!OVbx5&ITO2{@e#Ga zTnO)SA{hw1iZc56@{L?&){>7^jP17XDYJq6)oyuptaE?GX^l|CK z3{~m(xBun5CS(K#irPG@;4tL|25P=lJhV^LdpG=gTB9kJ_I{nSuQ}m!Z{gcD&FyCe p+N)06^2|@9do&N!oa8e_@A8e}wUV3|JzC%Lx-9 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/psd.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/psd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53028c560d07ba15c963e5136a5ca6d4246ff4e6 GIT binary patch literal 2110 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/rtf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/rtf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c0e14b3f4b883770eb061827cc9eb8497a75805f GIT binary patch literal 2511 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/stp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/stp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cab6077ed3a0644c1e190818b2de3a45a662dd23 GIT binary patch literal 5539 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 GBK;R3t(Um~ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/svg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/svg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c771ca3c3e3c87d3eb8409538ccc6187ddd717c GIT binary patch literal 1979 zcmb7Ed010d7QgSkY%GEI0*Gvx5D=BNOcIcQm4OI?AdG-4Wvc`T$|^x%6qk|@6gTBQ}GN)XB1Fc$jnocHeg?z`tZzq8%nQ4Op9 z18^^QPj`SI03h%Iswv>I?Lb^C06spz8UR28NKPCe!5!2BW4Hi7tI?H{%xY|9AEs8S zmVn*Pl(e{{xJ*$DE9xN2%XgbcQe1Kz%htxxhG(&w1S1gD4VX9rFhpIZ6(LioBpL>F zCh!=>{bwCULQtqzDS$Qxl{kjO`jz~}U^;8X9DvQr4{T#aLx#g;wN>?TQd_yyZ+d~( zq;oV2Tz=4GpHX%CMC;__=9ct@za4(O)}#IK&F_n(^1JfKkxiP$038gvAiF$NKl_z) z!oH8*OzU);k@>vLHV=qzt$Kv8U1bd`{%BPXHBr* zSoX%l6GpSOMoia@hVT3Wj)gvT+(XVwHypA0Fu3jSBNoG~ri!L^w+X53Gbe-Ga|zQK zi-EI8ilSQ&9h)hy4Y5zgvvNyA`i@p~TU0arYbx$!G>fCO{VmNxUdb=K`!X^L;?+Hw1MG%z0^jPK$HfJlB=dzp$?1nS4$PKTwZfq+fYJ;x0J`2AP z#r+{U{Os%@i@}(q-f4Mm@$9%@rZdF+D*+G`!)RK6f`qr4OfVp1K z3ZwRk;&By#0rJ)TLr_f`iTW-?RNYX5LDn3Rhorg;C$+AmP*_r*c^6VX^Uz)7_aAcv;)*I|?w`BmI&rapy8n}+F; zp^?FLTe349Lwf^CdX)i~B*|pFVcEdL?s$g7w6ZeLlVVy^(B$>P;FsX_p|0Ed+P^op z@p<^EJT>|9iPOdDpV@_<|J?K6Jte8>o}q$kUO%XSD1>A1^K?n>?w(h>VcD(JWk)Fp zd4<{tAk4V}j-OC0e~zqq9&q;i?>x=7&)-3!hS^psW*<&>pB|qO zC5K9s`rbgdXR>fXPHd`~}tVwP*?UKj} zBR18Q?o)xKrS!>xMu)^fn{=aQR3<^my$E9OXKF48XfDy8r_egQ4jikEOh)MKM7^BNzO)QszL-nJP3BZvLf zLP;Gaeo1|lr{C{(@O)!LxlYuq%^B0%_nvVA7^NCdmbqey!+{IQfvosLV9$WS4`*?n z`$h`IlCG7O;R||i&r7|xvhSw(ZPRzr!_kTSc;%@=hm((b+J^0dQa6;Y8K&RgE7qLq z+rjChj}v3-hf<%g z8?8S31scpI-8s7*FW`HkPuh$k(0hJoSmI4719}19bt-y4`PDHLJw}+Dz2_8@u}99A q-P?KT$Db74$!(m0MXjF0?PqdN?AKGi%o@JMxpl>DuG@&L8u>4o$F|J? literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tar.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..665cd0364930df93b3fd32d88df6b235796d26ca GIT binary patch literal 1747 zcmb7EdpJ~S82`>Wb8{JHObDqNvM!++W|WnTT#7DhkSi}v@U`W&Y^yEtqO;f3<3=BAdWW~QtiRHx8L|L{<5FqM9c#WH7deYpP8L0|`9 z2!Rm@h7nk12o{kU4kL%h;&FI99!Df9lNIHa2?_)vk)lLVP*f*s5S8V%w3Ud;ibSHi z>?i1U*-ixnQBWrk3F`mbq^*EV0G=Qkfph>&h7d9&y@@6cEtxFEC4=w;EDnRlv{3aB zS@cr`RS1j2BM?D402C1jz$Ao(>enM2{dr;W8%QrBO_>g$;JUMN@#i{Ao6<&SzweAo zpK8>#e*7Xl$Gq^kgjTSiYnWT-8Arb$XIz$bxZNT)G|av`a?@nllgKw=<4R%qwezAs zqGM|Y=M!%@`MVEpW)zK=SX}NNltkAd_M`vCsonE>=PR1t?q4rigb|*<58(cgh1M{X zwJr%jFb)-KnKcH%0vLyszPUyX$+Pve~|{NuMO01@}uf_7ejG4 z=t)w<4o`XhA*_7EMT4G7y<~;@-V4QiHRDvDW(F;y>e=|H;ABZM&Uvp}s71gLwHOVP zPS&Pu>uO^uKv7LlR15~j%Pr>)P*4aWup0x;EPHsPbz_-ImOn6X>^X4JhspIZdf4KS)=%Tz~7Q`H}ZC|4j4N zpFcl5!Q9nZaja#R>#ifa)l=_o5K1f#hhHi+-pjuJ-3=Zbc+W#mH-bGlmYuQxLuZs5 zN|Y`u5`rOM@Sm8XuKon%lYhMtE{m$DR5umGTuczpOF%mKhQlm6+sZ zH!obd+r)ww)e}@=CahYOzmF&B&s$CFGI}V?Oup_VSX@84D(|HCZ%nP>N@RBw$=iXFZq>|-Tq933`O)U23JND(M#Ej;>ne!-x4h%nT+J0}qx*^A6UAv;;0mFE!#L$(44_iZ;KcXQRfcru) zKxU9=wp1xlnYFFC7BV3y4 cl~nYexN1^UKBZm$LwC;87hgqY#!37C1NakCm;e9( literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tiff.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/tiff.jpg new file mode 100644 index 0000000000000000000000000000000000000000..afe2cde90e7aeed960ce94fc279d0e22919144ae GIT binary patch literal 1953 zcmb7EdpMN&9{;`XJGYo&h7l(^`;HAANi&1kRAypEg*A-m(1nr9=pwR+k|;GwE{9d& zK@B_7<}9{2rHsdAg>6N0iA-)?WVKE9Ji?rJEO!4rpZ9s6_xF3h&-eTNe6Olr)i9v$ z=I`PI2m%1Y9-vYH4lh<541k*(Fb4pT0CYhNaM%fxf;HF+09*vG{D~_1vYoDHIA(LrYtWqD`hy z^wmZ%b+x7@f@tcKC?x&=8>$9CBLP1Uhd{;vra=e|QZ)iYb&3#3ou_3G5j=qe!D``> z>@PwXherqyQPmH~2n1j%Ld6o;uiX^MSysoshHm>cy3>c!`SIDGzP4Vc6nr=M#K519 z0uB1i`GnZ&7h}SEeLg2DK5cu`82E7Px1*Af5&P{{+E<_*02I5&yHtLDM~Z&g>vuaO z!)De;X*H_b_kM_?D0^ivm-vStjGY-3KroH~;aBM45IlehM2N13T5o1hbyl+k{uomd z76yce7byAPwA%Aer2Xw@>kzxn{E@{YGbl>(!0lmQ^!1H*0;T0i`TE`trzq zH*{QPw})VH__Cl#bU3H!up3U)|2wnuFTuu0766Bn{j{O_l94uC;%ym$BnU(B25gC(Q{~9||we8P|M) z9(=3<5-cDF4L~>uhvjt{ScVar4$3fQ>oPez7DK^m7fs^`$qar4TDFw{!;m3_knM( z=6a31sn2_CEa3~&`)3ZdT$CxQ&Q)D)P%>stiiBRcr@L=lsf}Lq?+N>sy`Q2TXgx+{ zZDree?}oNCaixrme)ibbx# zlot*NpIdCcb$oS}X!!P)^QBVDHs)t`Lb&+CR%f)}={%!nDtWRdtaO0#LqhdAT&m!# z?3?KCb#A{>r~uQT)HPsbw*Ub%eX~kaQ+Lz4o%%(b`3%pELxvl4i z))m`Uclr2^n4D|2#?hp; zIioc)LdxEEEsc>i+U}xE9<(xlJ9c)hM3ls(R>=zG>J~8lV^FXawA=#_pfNlGrm0L8 zH=;AM7!~--m*>QRF=vq1`Abn*xtniTm-qGRXX~o-|Gr~q%9lphhHE6r6~ku)foSNJ za0ioLyIKo<9;H=3oT0~5S=ww>AbH8jZJA2l4fUR(Uk@1hJaRWZo!}+>lo2`QJrqzg zOXH*(-do#k=A?C;+s*KQ8+C7di#%TW@w=~XN@b#)G-t6vNBK}iR|m-;Mg>&hOx?j> zooqj60X}&9)9gWv;^NW)2o?vncm4vX9vKEe+qJ450NaiBoFx$!{1-HAh#+h+tN;t1 zi?RZ!3?|28F>3WlQI)&yv!??u<8upTT)Pdc3rW?sZI}}is(M$!_&@nVGzMT%xmdNBSfMxq|FbKVqR#(g zD&Yf3eGI zOa-HeBXUvDUdVcCI{Iw9TOm()HwpZ^b5EBzOAPo1#a_$qEe1;}N&@gbKh b9hK$e}}|o`bza literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/txt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/txt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec6d3e3f5f5b5ea808a90bb21ba75007d3802a95 GIT binary patch literal 1765 zcmb7EdpJ~S82`>W=HfEzj7yVC84N|ca+{J%lyNJ=P>B>vshN#RROmu-Yh82MbYX`? zs8FNwL=>XvGL(|gkdlYUsKsNt9|x&p7WjWy?pO^-{1FspZKNt4M5k~JJ|yW z0sz7uAQk`{yD-j90GLdm4*(znD4qkPuo-3rs@Mwv%!R*eBDl!+xwph9o&~0^`$9QE zoQQxORR3`5I+mS75N8jEYGSa;z}SH9Om*558nAzlUm(>mj7~Q(_4D@&5O)Dv07D3j zKroEJ5+FE40=$$o0Y|_S2n0NdBu|!;ktfO$NhHOe6lLWoBo&gpjM}1~Nb+(d5=9aO zTP|5Ciy*QTB8f=(-w@veWFqhe5eTFOU^0Y|A#npx$I3?_2_!Xs1%W7yL!=-)W>xx^ zdd@0-1>_J2z$k)Z)IAxSQ`6dvnf^-5$Qb?UW4~eso>>i#ak*ICe=x%RwrYT!+s}+Q z03hs&L+pf*{DKKA^xtQm_+k;zT`!i}DG zzlsUgSTZ`;52f&s6oSd$Aceyd0E{d!TnV9M1&XE(3(Jm(8eGmIJ>z!3=q+&niBj9~PTHA58?m9z}$Yxt;<@u~F8EN$8fH~+hR zHmu;|d2?*xtzpq~MSs?KK|@ISzysbMX&=)Nwdl>s>i6Gd^*b2d(h1|Yn$;&?DLUhp z$M*8v5zygnUK8UuQdE7A-($fZrKl{t?D>3n=nGjZ^k#7t(#^~hhQ?G0O9o)$b9-<9ET?xD{X+OE$ZZ+!BsDD8Ycti>2;Ihd?Bbaa<)XUb{b z!;XHTDs6?pIU{}dqnk$kw`wb@WLs-m*@oMd9IJM|vv(`?oa|Y)fPPq#d&GL4(h}da z>%om@77dy3S~+Qh+2wEFo;69(9$J02G1=#FnV(|Y^*)A4Vu-cX_+RXf&mxD3lN)1V z-_u(6bq9NRg%1n(%ks{i;})%mUuVB}b3CF!TJq$WwxD2YwBZ+>&1jaME@Rh<-tvgF z%ulsC!s^-HrVnC(ZKp1ZbtsITvG1J>k%610q0yQ#)bBVo@9rmTcji0UT2oXqptO)% zuaM3xpEx-3Qo8*bU)i*SmD995<+klwy)Iw7vixUH)skLlAGs4T;<&|c&mGSz~t+C@%A3y8MOuUXAGQO(0GNoFg5VvC*OLTzw6@8X<-?`t zD^+XUokpK>^-dJY(=~7Dfm(xzqA(4x!7kY! zp9b{5PQzCR3BNGFNdbZ+xC9Vc6QG7hZZ>QD#;B~|yb8YHJHO~uNqox8(WOqqN8nhQ z2(DKhHMJ1G;YRjxl;WX;pb5SznVWvkjt#U8wBEqtTsL=n8O^{Mbvw_BE^{mYSlX9x zF1)E$aEU%dQFc&`*VG&Fs*iW|++anvke=!99ebv#;y%uxT0}7(ExeT5G;s7R>sg0;Tf8-%H+AQ{bIqHKT*OJTGTVly_in$NlplnuaV~1Dof7W5*X6#M Rx=kP#X|PH7&OB1w`8S?lY>xl{ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/vwx.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/vwx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c56cad7ec6b5fc5ef19911d191292e0b99afe5ec GIT binary patch literal 5463 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xls.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/xls.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f656f73dc2dc53e6ee67b95bf8ef0b08365f3da GIT binary patch literal 2691 zcmb7FdpwkB8-Cw8na0eR8KfL)sAN^M!#E#jL}g+av|FeQN|PLB@QKp0R^*sdYuTI{ zr%IWSQ#qwnPC2#?B`b+g3aN(q-cj3r|9<{Z0He780-8ZtKoNQY0G12;{v|XQ{(bHuNs3ni z9XtO(t`9f#m?zmigv_+J+Uvvh<&tR>Ly9&<*M@BE8+eTG%Q;1+p4QgacGuF^;)sWV z-2e=P!{8tc28T%kj)Y4Bg+RcOQYa}YDHIMRg~no}(9&oW4ui)?W3f0KP6~sU!Q*70 zDOR!xv|O@M8V;AnqH$>K{~h9HfQSZMfKWK72Ed3QoCu0r02K*E(9RMPz6A^=1)|{y zDv}e8c?ubY&f1T6uYX_IeBLp8GHkN`?YouI zj?tXl`4#T_#XI$_)8}6G8f0EJ~hk(d$ z;E)hD2pT|^rxNsuvT~|)dk7{Pf)65LVgPP7bJnZ;v_qN>yGA)By=u!1Gg`09K$OkZ zgqu${zSL8z$X3P?kN4o!Pur88DBTF<=3KX0FH4@Sc-Z|iS(N{jBK*R1eOwo0S%Vxj z4d}I5@u)gnVpc{<~m-#{b;AbGfKd%?CnoYb-D(OgFdc%u8WO|yZe5izx=-U z(ridUXA>fIVd~~}Z^oWx(;&E9#6W|=$pOjV&U4I-n9Rp|virlIqe6;#s;M3Z z+nM`)eC9;yrWmCYoX@L?@y+J~vx@Bf%x3G~!i4{K|Ao?gYa+;jRG{;HMtXU5Z}O2SHq>yL^Y=MSFP_@?W^Vt0mJXW1*Ys>XdY zG-(Kk1_T7UVp896tN|gC5hN{HRc%I|u$#)^MKrBJfJq=M+_Uak_K2a%+P*e8L5wx& zd)Ci-kf`KY*cj$G!7(ttlEv-HzaR4U6eYgw47m}vSLaxg?k{#x#+iXNw+y&`P)$=v zJ}?9fg+%{D9|(gi14$&wqU2Py7;M6NHL8RB7HvIFK=Q4v+vpbd?mYfjN@|`!_)S$P zbC}5a5%W^W)+49`lpweHU1OVN@jAk&2Wj?s4-?-r1z&n&T^}=JNx5kW0{#-cQtNj) zgWCN$OFR3@u@Numc9!FpkLT;ThMjCI$SSI=HRa}t0ls?Cw&{i1j8v9K@$dX;X2?gU zod28)kS?sG#RlE^`P6N}+~}R%BtLJwO}lj7ZFbDtvhY)myy|zcsYk4Sac-UtF!|Fb z$#>+Z$p>3qGOpB$9xH;aNb^lwzEnTRFy6ki#M+U$4|j=wd$z%=R`8|#Lq^fmjvvZd z)wI&T$LDSAxU!9ZSnoAUl<%4op`OR4nz{u4{5WXiP>-q7rv8R@M`!Q7%9$K&cyy3p zJ2jw!8&^)+ll@7MyPnxR+u+k0Wc|@=QcE@e{qzT}zouJ~!n=%|?xMcktXlrMdH+?x zf>ZjacOW_i#UGQK ztnGG8ZTD18GrM?cCAkp$rmN4#n$a0_FfDkdAxM>Vj`JvZqQ@b>uygai%YU16u&jIA zbdHWGAc!-s|Fl?e(QTe1P&+Y3B3tcwio{eEcOKM|JGd#8?;x^wfx zDT0~MvC%&S{H5LKb7{gv`qh!HA#+Gy+X!oY1NE;pgG2z*6_rh(Lw7PSLfG`~A9pfW zed)?;RsK58-hZ=!5gHjgxN*wz>QA`pm?Cy@!G>sg?ejBJNr=0QIvZ&dJW9*|Sjw(G zXE`!^q@^~+lQ~snx0*-S%YZ9cPQPg#L3GsZ-qsF2>LxW$Rm+4-;Pt~37dNq&K{+IA zc42b=b?Tm2g{5jOvp^*7is%nzyv9MCb%Qs#d%BQvt^mDOh5TXe6gC1KP})bR;Xc6Q4=nEd`YOa>Y57Fm1S5~&DtoD*tP&v}Ys zs9}w#=+wh#1V!Ny523-(>FqkRqZf|y{eu0&4NZg= zmjjc2IE&eJ$ZJR;pI3eM%f{%>cZa!dYIIMklS#qvG}7>}6i{kxlEMf3`N`eX%QRZI$vh@65y<4w^%jYr@$&Q?; Mv?2yX5#quB0v?}=2qT}5$u2^RNMS}M5?PZzV(c-I8p#rgu~hQP zT4@nUk}N5N7nRqRR(#s#eMYM9-|v3T^ZT9W+`n_4`@YU~U$?MNI06VZ7S~NBegSn-jkG~H|N6SEquBB^Bvi1-03i4+iB2kZWSaf|hjiW1k0ZaiB0U;p- z5(yzi2B9I5VNfV68jHbVu^2pFnkXqQjg!FP@#0dl5|RpdJRU19B`t-Qmc-)~M2EoJ zMLQ)RNJ0UJ$0_{ZCcFoTIN%D7K?qfVBqAUpLf8zHMG!$tLzJY*kO&M83!%_ruv-cC z!l8>G`e{hmg+XA213(hqha^A*7{d3@Xpg?OoTjM$80Q}KXJ?osVIS51$4EUKfXDaC zv&xvfHluHxvM|%Wkp5$I~CeQM{sj*JR`imrb<_Roj_$udt<1! zw*Qy3zb3zXPClX=)cN-6-T3pXZ}#UM*>epep3_x8`%U|3-Q3!)$HP^x`m&=7CG=O+as;nPVnY8C@}{fN)~!=T$|N!a134QqF7HUtRAeBwy$6KB{)&FsHZB+{$?iJ!G0<-EEN5B3N{dE@L&nO?#4R zs(HVyx%v&+BH8A3&w6I-_K;N0`>UC$nOhT6Q#R#7!9!>96Jwf?nhlRfePDYg)1uoT z?O=TBtu9aZ`}JT(2m)wRyY>xjyIhm(lALjVZONC_AIuTHo|Wm+7b2xakPrbtp&=yp zCnE6GB4r>Hfk-3MnP`%%oT^Si*SjT1U{)9-0}{M|gQLuo7P z;KL0FOSOtb<8aFmz?1+eB3ee4j8Uc1m~!$f*3$KY(g}_%c3{YvYbFld)BK{wWsYEs zk>CB|EKhyweY{H6rlAiLMn9xnE_m8K+|hIIbjGlJIIpu`;Ho3N%E*h&U?)Z1M;7mm zAB@}oUHKCOeItavW2(_ski3=UP%~BS!LOo1f)AV7M}#Xh-kt92k6G6z$b= zuc2(yp}kL{$h%(1?BCyWR*6q(Z8$nWPqYO2&NKJKL5M+sFk9e-n@Bkx`}pfc1^am+sWS@xKPbMX8ZJ0YMX z?Q6%9_r&c8IkJ_Zj9EO{t+)AJIX`62ZbzBuVdwl^AuTQ*dR4at#G@(xjjtaqAFBD7 zW}Sl9Rnao68ap0wX}YjZ+4{|@Y(mtUYhM?8{O(2sJ$b%|d*gPuS~ZT5BDXJNMs?<4zYWws{F-?$$$@Sq4plj$`~wr`G6oBzEI(C*Brf{7O$tG6 zuU4jK;nggBdyI9OT3+Vc15BTvyI$08cM{6YI_im^tfU=D;!!LFk{vL=XX) zMrAs(xCJJG>4eIz(I0gKONlZ0)B4qc4@Bd5#Y9_s;H#CBBz@oA?nRBJWaicPFIjZA zy^umD!Xr)GmEaX%wMN5$ye5VeRrvSTjbhbaIMw`Y2i5cCW2rdxn63>TE+bp8d=9b_ z(Anc0!OlZ}i=FCND+GkRCkc7#vg#v(d39w;Tv7bEd*KYLzH?937^V&oTjR%XHtU3L z&@dX|CT$t7EJ;S#fWCsTr^j$s9lN}b9yis%#Y8YH=GVUKW3+E*eq19z#6*#@&b|y4 z#8MIbgms(Su4p>-))+=Nr{WYEEr&U@>ZB`8HT}Kk);+jrCOtbBQC;75afs;5VytwV zaes{?kYc39WX~@YuSzS{O4~jaH5%@(&wcHgkSIxCMX0iTQYHj&EiE+`AS!W!s6mT5 zH2gsU=H25|3Syg;Gl_ygn+y^t03{2r!|;=ca4QmZ$lqEHh$J$N>Db5$RJa0(4sO*vQOKjh=$_M_5LKi>!058Oa_7 zl&HOs5--SHLizl--HF)l6HJ>pw`qxewN!pr(d8@7^0C$3lP~m6UsbK0CT9n`X~!!) z|KK8bdFAv+haguQmuT`L(<tYkg!sU8;m6@>uc>IxPD07w8z6#*QkVOB5~TL8ck`0JNA3G!7BP#P7V!4K{c zV$l{+T=06Pa2wOb!@+5bC``mOH?}f1Gqza46oiR`qr!qVGfiX7EX{;$OLmZ=3-AF9 zAus~LFaj%q;1MMVI2?i}5{N`1fkq&bsAM9ELL$(}s$>e4N~6(;WYrm}v>BL6RUU$E zSMH=B2!%?bk*NP0iaJ0ifdCMPKso@XLkJyG)B^@a(G-+9PJ%>KAz;74j2cS%{s~1V zpdt`}Q3S=9>wovfs(pL7{IqcIY2iMHejWfs=bFncIU%c0|Jgn(p(C`h$*Tzi|2s_N5aey9{yZrFDO1VIIHx+n$qUDGKYb} zAzZ5ZK=ERyt(V2^-Ftr-F8_V7b>&M@tG)l8_Hc_kmtI%F6*96H*rH+{kblCLE;JAH zo@>zKWvRJ^XO;zxY|7HPv#!KLb11L#v6OQ%ogSSWp2?!hHb&OJ zD{p#Ons$D^32cp|xK>7PSpCUM(0cD_%0$SEx6-@vL)kKGp8Tv-NiqH36i;P=rD+54 zzvBQ;J8-Z<;1GmJMpQ5+mB9GG0X$t@T%pD?weSpT(a>Qpwav`RKGaB)KK|#om&{^crY{64#hTI(}1~bmOEUZc$Mq8mjxd{&3>d z=HfQ6`Tg_f{Mg%T5FcVXV~A}~qsnf+cQ*LC%JRIX_K;U;umfwJ{(cqS3X3B<<2UvH zD%nS!l2*}6@{LDhGApgzUhRHx5h^D$ie00$)*bzA&D|vR$Yt>zl_L_Ik=sXxkIi;QoYjF0}hf7a8hg-#xe_ z%P^<0Vr`Yn;NUz)TaSrb;FF$27jjhyYp10vfpcN)^1+6c>HW2r2Abo?t2GBw^*0`V zW?@w7GyZ0t0_0-F)}QQg1i?=gQdvtn3z)KPJ<*^cCU4jyGBLAxy31`?quy%C32?JB zoLyX|UG(JgRuPk&k-$fM7<1yeXrXRW+K~T{zjgAhzPiU;lxg$GurxHh>csuyypM7| zYaox2T1Tn10c=Cf-oI8Z_PM%hkxQ0DJ1}fM3DIw2kbc^K{0?da#t#%bwY)!;qn<9@ zxGtF?zs4*x7^ft%k!b z)Qyh5T4XCVGFi)w(Jb>zq>MhsO{iAegx=(*NG}y#&>eW{$xTxqOOZDUjA!e&?`Y8Sa3?B&qT_EXr#u$` literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/zip.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico/zip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36d159166e47d37b44fd4ed6dd800c2eca16f903 GIT binary patch literal 1718 zcmb7EdpuNG96$Hod3lWH65}z}jFeQXnPG}z8A+&Nrc$J0@-Bvv3aQ3!QlgDYeaPlf z5?fw9cGvcx6urIrc&iqxQh9$$W%gV)yZh&U&*z@cx#xGz{eFM1t87+22Mkvy7bk!q z03dJxP$MFPF2;Ip+TRaPNy@8kHG81 zO*ITtW76m}=KqGW3g9&04Pr6G7@#$i3;`$uW558`CqAma(JCAD43`Eeao)5>W%2iS>b!Ts@wZteVlM_ zj9DQZ(mQ{0q!;_M=QIAto^Q))oAvrg=}w*RqGi3S7w)MYP0qZs-7tvNJowO>UpcG< zK3Bb#VzwZyrmf=%y}8!ui(1AQO9>)+vYuI=?U7`*+eFOY@xZG5}fwnuTW zifL1vjuu=hd1WMm8ccBj=@3L^S_6z3Mj}%fI7gGs$2CthC5H1u4O)>=Lu*J`(^dwAg9 zn`=-a7iNhlDeAOD*ermAGc>h0v$#A6Wy=^F^^kKQUFZ??j$B zD?9haWcHZz!f*6r2jZ*!Gq0E5+hEHtlVi@oy+=1UAF8$s7U}+GDPeo$uVk)uF|er` z75vaJ-$?s?a9fkk?FEA2aWB*RKKhlfPW)(A9E9yn$=of9EBa98e*6Y;aH%zRm>a%W z9%ptUE$-aU%jCC0&2{`Qrwnh-|7G8ZL>(IQ|R9vS7&@~R> z8Wq4c`3eN*00x&Qkq(G`D|5cqo*idIoa^j-RCmShF|=6IIr>Ns&$uY(f;AG3-PH~3 z?@R1sFPjiK(0^AA zVBkECu$0Y}#t%s3sX29%;)$ANbSo0b5J83aTTpR!V#TPR&&iz?O?zHqhZ`Q>G;r+< z-SFNcBiF@YJVFufR?}_omZi4o&F!6#$YiQLNQAg4AOL4@ctVMk&6TGP1dt?EX*!=IdZXNJaxP1_c3b6))-Gab04 zf|IJEwrG3Lz$$Knd7`Tkq@2Y7@E=e4Pf`G6WN_^zQn?s%PN#)2AY)lYj8+|@B*}P literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ac3.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ac3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0530f2800a2882ca5aebdb09e9bbda8031849ff4 GIT binary patch literal 3462 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/accdb.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/accdb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..13607b106309e9ef258633eb883fe7ce779fa780 GIT binary patch literal 4130 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/adp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/adp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..92d67d93e94f02deda3cce2f8c27016af09a6799 GIT binary patch literal 4126 zcmb7H30PCd7M`1Xvj{XKfb8I9Q7Hlj*%c)$fv_ez(O30}QV|tgaK+k6#kDHw+ynyj^J~91fw_Oq`RB}k&MX(So!VP~ z5fd352@nJUT=)Un9%^HBc=%$zfEO7Z$AJz2sNV>cN*M_UAWN=M38KRAdGi=S{cgc#{t*~F7X`QUUUE$34nIb_xne)|Mtx|O{^9HfY6{_k){@9L7WQ! zSte4dGyqWULVMscjS^z2J;W9&C=g;6fz$Okg21VIJWt1&EeMAkLMvUAAxwjK1;iey zBkbuTuwDaXz&KH2xmYC?;Y2O?DuqNU6YCuM?qA#^nEwQ`WH~TrU2}xJi8^yuEPT2V zxo4=jfeR;|hr5ZYjTtWBum zL_rMWU{A&JM51mGldaQ)5kzghAf5r{AVMGp3XlqW5s-s-00#mP1;XG{2~^M{0a74? z7BTdSp+$;(05YNN{XD*oqaQQONY{;iNQ{QFyq}|=p?8p@z^pJ9<^zAHVR6`WED#F< zI2MAju^Ctdv<6|*3<~%obmAZ#^g^ZjIN2Zv&P?c-1H#H|bKDGL@YSltQqhIdKB#6m zOU1As#xZ0JH7iC|0H|RFhO+YpT#eaUyp56PEdf0f)d zJf3`=+yy^ZK`2}SnNCp_R3+7|gxbLK9F;>0WNLsA_O~HV0ksY(9krqod7167hp2>j zUBZh5u-aqT%DTe(jdhu|lU2?7b<`Zg5l2-CEk_&Bqv#Ll5%e6u(Pp#-J&v}b`_Uf_ zG2g%T`Y49A*X2vth-`^f7@BWnt;Ik_52M@BUFZ??arE)@I0Fl(ThYDgT>3=lu`{fj zY}h|47b%zzYc*8W_s>O~04Yd>N~B;Jp*i3-a>9*jEjoD3?(95HV!`fs~7kl4#Z zDkvOE1SJ&U6n9Dx#hVgC;GvU8nFxJBu;&=m>rak>F)9P`2o|i0A&#eR*AaV_7`+tg zmO_QU&%x)FeP8?@Rtm0In)Dj2^DfM%KYHdw{Ul}Z4Jk0)+@ zKm%mN3|`dmWk6^{Yynw^0f<5D3|N4;4RS~Ttdjz4kVD-0L?iB6IC}6&+Ceff@^_#H zoJ3Hy1HhN3)JU_W`QkJ@H4l&BbE2}Oaw+cP734L=%P$VrQX^K$g)*F#>+kO!5SZrY zqrDEo0f}fR(UHj{luE&zyYRDLg61s zL>2T6A(5#x3N{9XZi^B2LAUlAFhSuU2Fif7yI5VeVGKk6L;f}e&{j7Cqk<)!XqF;L z6IAC~Qi;6By(KKFHg?6zn!yFrFr%d?j^&5+-F+xtZQ87ru3Ot0@mw)!>xjb-hs zX|dw|;|X7E7ry(P+I(L*vHro$g?DwsK<&CKPyD`nGlN}*@K-`@E)1fu2u30{fv#a> zlmbWy)sp3F;mu_8p;Q`703nkGj^FqwZ&Hr4EW4zA?6s6<`E9SJwqdtR1kLjg%zB)i z?Q33gc-?Nt4QraQ4{LtDsVKegB4M2mUY=zv;^*cIdvoxCsO0VO`(BtxvlYy*9zRH? zOLp(=dv@Z|4`oRKOQU6K?swhuC>`xyyI;!cZ`Ew|PrTi`u5#==P%+Oe>}`a*Ki6*V z*#U*JrU+Lp7ca8)+#EBHa$u*AUwQni))L0s8%c9Tt@LxkJw<=ChJ~U}{f?dSVg`SD z_D?M!mVr6EJo;4ixxs}CLBjumKpG+hG5~^-Pz*Dn4u(SDH^3yDIZ@16GrdFAEsU|w zEI!y{&p*t*v>6<4^3G_!r9lACf+2G;G@4GjQa5&!wmz1&N$5P4?1DuidJ@ojQHL za?kzf#EJ}w`<`p78`77wp0&~Rr53#0QdI;zz9K)geo`~J+dTi2>z&74^_%0G21@BG zJfa$Yx9D=sk6uE$aiM#keU$08kKAN$ProyzxY#6ZKGDhSjVA-9c)J1icF4tZfl~T}Yr&AHh5qVvC_snejbkpv@n`K+T*^d+Hs;Q3L#8i`z zPa~AR4OKq1uM=}SU0o-=8Gkf$$vs}~-lp2|)48_KmGzES8fO=0(Hr+FBo|L;O4qm> z*NJ~|3-rU=bF()$#V$K==FsNC!;>XdH9Jr3$=$Xy=GEn%$2BR(FFCUpZ>B(n`Ue({Fx><^J9ukN^TxszcqNxjyDH5^Q|ij@BX%Bp#7=iv$~Dn%U6B_ z_rwHvJ`fZ|F~j*ln83+9lvS{Erf>rzyZ$!L?;AQIAx`fa>$HFq$>0`{nLBMu$dhc? zZTtoHrpv7UTf~lf*3Vr}eO_4Qygp;AZN-d+TUI`^KD;xP*YrvB^QVq&{VgA6b>3@P z%Qr4aDfo@m>Plx+Tv>DKb)tQ*dZUM>*IoC#2UZzkQM^QyvLZl2HgK0lu{iSC{#YjU>S@xMw+#l{{gN!?e^T|90)|4VAOQ{CD> zFSJQg238K;b-H&5yzXG5!GBhWCmF0>1^+oSX@=O;t%rC7!|or>B5_z5|8`h)1UKSl zL*VhGj95A+AbV(55w9q{^Yh;yI?8B%+;(&-|o*E(nBbhx<7AQ z-|uKqe=$jR==7AYYI(FG5j$<_o_i~oJX(3wcgruI?%3ZkCi0VyB=17AEJf`~!8SjK zXO;VGvm@e?>n!$8F#dXLP*kDS;(A3v)5}R$?Oqurww7NH=o(u(dCS-kFwh)Xe5xdd z%5hT)R>%S}PbPEY=kJ=n-B~o*ZlOg`*qT#ktimhq@hn`;7WmD1?7&{Wyt>ON`0$ez z?%{Vhjss_GeXRxk*wUr0rSVffK50IM7rcCx`P%-n%Rg2hK67PG%f{TOs$zPsOU1(F zwAF79E_hDzK~5+suASTOIaO`4F3(IU{*RUaFRxS0zD<}jyR4|t`(#o;p67`>yEl^- m=S=9rC&$jc@x^je>lpJR%QncS#o8Wt6#HmV9Q&9;d-X4{{9~~I literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ai.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ai.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b7c353b410632b2c9226647d236ad3b8ef887e40 GIT binary patch literal 3416 zcmb7G3s6&M7Ctxk<{^X_5Jkbq6P%_7_1X2++U)t0kbvXp?4QYhznt^^ z=l{<6A2;qx?jDe9Gc*}MQ54L@54is=Zq=w%@91)KGBjCgbO4B3^me;NzyefQoqTR) z8e6!qh!uB(07gJCL_)CM;IJ!ox-7s(xa2voJ^ThR62RA!U+f>qe(qPWk#iUTC<)qa zMu(vSaW#O@VzBd00MRY9CsjG^h{Yojhw~^9v4Y?-FHR@8#ET0(ocvrBa)?%$!K61L zUXD1fq@TU4ANFcM2FA(ctQ>DPu%s3`-d1Y1a2|)Zdxg6n^JTEY;=-IgZ8Y{$M|s{n ze8!U8P5j(kA8s<})p>|tL;G2~GmY5CBmR%8yg-R~B7h*Ql+P&e@&ze1ru?@M4@0}r z?9}A@>^0Vs>>R{6R?u8-n@8dh&RK&)g|&oe#MexmhO9B_p~1+ds}aW`9&K{X^~I;P zj>0|z!J!QKE?cm^!wLMEi)(+)g(O2G^kv~cL<&|;=S zpd4*4=IJ~f@0b9i%rm-|jK*1B%<<0fosVNt6wIUKi#0j z6|i^|RiG-fXC)kd-sAx}oIs`%^w{4(o(;A3DIKt)rPeKx0S~DJw=Vl(Hmr#YSQQr) zKPtKu+Z8(%KMa^75OF}2==bTv^v84?eT+T_EZsq$pg*Bc)BEVZ`(wU%?Y&X_YwyXI z*hscy75e7uUuzC5vNTzgY@94zHb(ZkEX&VgWf8Ij*<4u+dZPU6W(oKQ`{H>5Ydk-Y)u71c&XVzM#GV02#r6$nV9Nhic7En;YFVxf=`NyMQN ziC7{D3YJNOhJ*x5BvQFFL^c>(kTf)G%-}GBNf1gP6ym55h6x!QBncvn|F5}ELZ}25 zK@CksgCLZmLn-$uh$8=iXitqulB7`rk(g$L=nN$*ZZ+O3-K$Lre;7IF-I&v~iCQLEKJLzcj~`M#*tDvC z^n}KVRYwk7ZZ16f^m@^eqZ77W%-S&R;K|lJKI`OD8_7EK`K)!G32BO&L#bXu5cCnI z%7LPB!Gj0&MWO_BC=&+4u|pK{@aTjo$~67b+55A8EKk?O#yS|J>a|BNo{#kQ4 zsLSZ0)_!l^mbd$O*Y!yI_`^dTe<~bQz9jkEx04^WZL&U64>~-%sPXjFi81rLC~frb zo~Z8B%^W#n>+kniTW*~_x-06ktLQ++yL(G^gUULp zImHbJ*RT4`;`{XtuTyXB>(GB*6tO1K%ud=O-81C0@^*L3h?SOan%T#b7W{grb4<>@ z>YL{h|2XW>l}Xz~qgHfITFPmA9%{GF``}*0h}QC??A%2;5jo|H+P>{^1J-CfE+IuT z0uc8tAr(3n5^5F71$y~*UGdWT{U^TaTgN$LpG3PhS}wJ{ccHg*BR^3+mSJZE&mI}G z>{jil&H2GO2|aVRhTpDii(0XEg1lqHrr5_0+0E@&KF)Dfv}?-Sw*Oet*C6e9B)9<1VgVFsQhG|LR@$c6~bi z)cFs8`J#GjY7_h3vBo%=>2i7F;#0=Q4GkN9a4G)s=^qYRRwjr4vm>JC=adaS@26Ir z-F+!YrWt?p?u|k>II^$r2(fIOwzCm>JIiKoo>0=1sz_+sTvt#vde`7dDs|Ah40`9G L{Np2x?(Y8q`&$$H literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/aiff.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/aiff.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f0422da52b1777393733719c441478a6a9209db7 GIT binary patch literal 3454 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/bmp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/bmp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f479380fb0db7d03a6580c674582f7f2fa9acc84 GIT binary patch literal 3754 zcmb7G3s_WT8vf3lb7m$kb3p`UL=T9~{v3fgYcF_8<7qJKz8Q-~aya ze>vm$%yAhc8L8>1KoA6^;RhU71c%a-lb5RVRH^A%3Tyxn?A4gfdL9E{Fxo76$|R;} zaWNz41s+TWPY3`{jn-;TRI9T93&-W2 z_zdIbUTI0o8^MiQjbb6<5R7-4ZAn~wCgQK{RRxKNX94hh$}On{!+hSub(Q&x5c^@g zOlM2aABoo)OLJ6+u`h3Tl_`_U!*M#b)@1Y&f)QV=WYf7dMm;2yu_+3~vk_0Nw5N^a zCo`-y3%R&6PhDkl4r0thT9#=t)QAHRueX@;xUo<(xtrB1xv?-m*LQFMtu%9 z7S5Lvu~z3CF()}-tIWrJ%JrpUZI=9zzEp9!E;W6Gzsjt4?nTr_?XlSNIBl4p>e5&g zO2n9ly2Tm`INuP{lgczHoVO8(AAv$b11y-J6l*OQ;Vv+c2TDl7rx`5RQVu%MV}!+4 z79%>s8>%pNf1cXO8Sdj|R5*JNaJ_Mq`*VgzxIV%$QT~*iipKx>R2CIa&7d>!@@%Pc_(aWKKsRBy9??hq?MNYb{H4+K)HhL^bYNn%wP} z$2DWrY#QqTSkZye*@chw>4Q~AC%IafZtBpZpLl(+3RJ)6FWpZM(A`+~(ihzQ=|1`b zetIDhS3vJnWI$Cq=So;zyzp^zXh)_EG+2LuJQHdiRXT1(%Z-}?+%23F>@zt( zqgSJ@-hV9a1n8gumFQqOaxLg8=dclKG3(fKGNP24N<~uXzuL9)xV=28g0JAG@DqXI z&*I1NBl#H|9zA*dP;86CTH#VZd~#fjaWi1Yu+SA(o^a=`7v8&9o|=h%>Z{B9F9A?9ge$AnEwL6alPXUSgly0D+kEV=5Bou0!{efMU5{5P8$&b zv=akl5Hc6eBf>^FJb-6(K#g#?JD)4uU5mX(p1ek$i&57|y6_T?>bM6nDzi;z(ABYJ zOld8Xp;jmjI-`z>j);qhig+jsy|l3wqejojS43)}*oPwL#X0&Q8F*YFxr(NFq<~Ke zNKzo6X^JltNTou7Q0U<)^75GA?I{#`P4oAbi30-zJ-nno)5Ja^aiEw>LeMlVAO+qO zhZ}t}8Xka?8&h^Yc08H%&a_hP4p{s#CYAUml&Czi5Zw`Ev?G%H6(O zL!B#E+?g@}WMD$%!&!G#nHhf9x}zeB{?k%$Hg-oE{&0bgL#wZ1I(Y^Dot}W1fqaUHhr|BkhYD z{9d=0?tWkPhpqKRp`D)$eYtqsrMYJ!mS3K@Wmfn5>XlE&-+A}-!invM#)6iL_Y;WZ-yrZt3G*aC z;2siq(A-|<3W26XQnb{^5+sk!-Mre z*B(3g;khE!hi&&JzBbDNky8g+BKMzVgPrRJH&21?MiUWfbA01REhYWA-F&H;a zIv4wn@_C(XNmEBm{p)A12Bh{33_UCR^vLaIn_WQnJgd6WSGw)H)SjMZiG5=)w`QTZ z_Xv{5Cq@kiLJC2VxrrJHBVW_dUacwRXu$@D;xYOf%;;b`)eOP?L|w#EAOeEZ(joSoTW;(^w{ z?<1a5nW`JJp6^uTp8Lz9)qn30{&@78!o>rk4YGxhd#mtpcC2{Q(A6{lJiq_IB;Tq- z3m^a2-pVJQL-EcN?Yt-PP`eAy(}~wkVel4yfk{4&w=RR#Z){a=FH3%JFFOh7EE-Ew z?o&;G6rGhPYS!G8FxBk~N*Z>(>2g-`v+stm%=(}O4IYw{UIkO%p7+bN&oAHWVx(au zr8(=TzM%J%0@HcwXx!|*zMkzj3%ddieJ1(3{Z6rBk4o*=06k5mD-BP*t&@=-9_!zi z@xo1U$K|*DTkS=J_~lEXf4*UWq4iU;!~xf4bS+qW=#;#*_pSG;jCS7qn zN*&zKK3O(7yJFM7L%h$QnV8vMFrhI-)}JuB-0!71GsE}YI?~^68Bizs&}V7$t6|L( s93WA~MXQ$!D&}N$h9zznl*EKBIp+Cd1JAd-bB$CxC3kX^sov51KS1K1&;S4c literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/css.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/css.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c80e1571791a5144ae7af5c824fe8e3b7bb5153 GIT binary patch literal 3444 zcmb7G3sh5A7CkTTB}51zLDY&Co+y<%h~XnbQISu8AYu&Q54DEm0g;fzmjs2TVWn{dq*38aQM9Yh1P~f^7TyLR`UdSuD{L0TexnhG@F)tCce%fM7C-yfGKd@I6r6HaGAP6qyvx;1N!PJ`a!g+{? zqg`*XsS4fp8dFLBY{WQL&{$!fN#YRBX`M9#YY7pEd&)T#S!2{ggPzM&B92BJR&LL6 z$ES0xRRzTEj8jvdk&hVT(EKuOt{QPD;Jx{)(xlUx{|K4r0~-5TgVlQEy< z!uc{%&gz^a#-#gf<%PIU$yg@Q#uvKBG7C!$St>Wb)?#$-MbySL@pcW-hVhy6T3(rr z7~?PxIa3j-8)D&WdTl1DZ4Bb+FqhH-2WBY2UI!+44lHOO8`AM<0UkZ2U;rapIP`L8 zF;Ia}fwmX()J~3TjF(a79NkAoW0n_lTp8}VIc8=AqhR9ko5JKV)0iYC8CWKjnZZnF zGSQmMq<9pleRQ%=26s`ZE6#GTV`idbE~M9o+M_&U*gF1ggYMjKzDG6QS(?3mjN_Rx zYBu{;0IXPnf!R&;ty5?1vDZ8v_A=A9=%S>v7G}SyzQS*WeZtGwcL{HJ#|y6uZ{Vj3 z(r^WgPDPcd%HUiHtA{sn&>T)6(*|1XZzIo)S_hO4TG3KdeW=$%D#5ME@6U(2Xs=aq zRq?IjvZ6uJq_{sQhd1J&D$!f$Pw960DE%k;46t+ueS$ttpP~=YpLt@wct^)&2hGI*3$RuL zRefL*PG*E44MJw!@{a~;!JezIN;|C-|@$i+|$ zH8d3g0y#y?DaYq{Vc~xu0V$)W`3Xc6BSc>a`Fk|DIl4hY;{X{g!@_M{ zp$HVit?pJ?JsXxy*Fv;2cy)t!F;8>{Qr zZ%9<=5*MZq@k=;s-4;0M%1*9+mlf7rsrrzFrqC~9Cc_P1fKkLGV+Tw(g zcaP-!HpKzqfs*mRpboe1T-M$Hm&d!<&RKb3ms3Nl^vWE5BfG%jlYJ-6xcHi>7DH*yMk;R z*{imVlMo>zFC2wc8`yw8RU<|7)J*o{$dI_U_`g5xpaOb~BX54#eBnkwUBDJWL&?=+ z?<+nY-t%~IQPPwp$^IWFeibLHmd{8mfcE4)f4kN(NxtyxHBr-|iL1L~U%&f($L>G; z`=7Ajlj4G>?>xSvi>6yA)%Z2tT^qUlZ0Zxc_3_BI4J8s@+btX-YO0i)9>f=qC=)?z zp*i5$3e_#^>9PCwt$~zXQT7Fj%=?jT(SL5P5Z}Ie>r~{7C~D6S;~xHNXh`z79pR3y F{{feV5BLB8 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/csv.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/csv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b81a32b0fd8e7127b883b7a59e63532e41f6720b GIT binary patch literal 4189 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/default.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..433adcfbaa07a89b1a9decbccabd571d48dd70d6 GIT binary patch literal 3783 zcmb7G3s_S}7Ctxk<^h2aC`_m(+&QiIJrDcku)tjExw%@76d+q?)F;J6NN1)h zrTk040S^#@1cWNJAvav1hzD$hOP>AP3GnK?4oD*t;9CHbth_7a`ab%BC4-FY?WEA2th=*k5#aiRj zQw$4d5W6`}L6$rbF~*_wZ>gpz5K9ohqt8hqbD?Isg4M>5xiCI`JlCkOYM^iHw25Rc zTrVSH4dyjsO!~GlD;duz8OuyG>XWTw8D*v>I?l>3%+;FDB5GrH>hqF_HjK}lRq3N* z5MvzXcUG4|@`jk}o}r2)xgCo*1YW09z(NkBW3L7sbb}OB3m^|?COTe+h;@=YZ`&B@a($Xc-MY35)%311r`L~h zY%501Iejw#2FyUu>U{d<>FdJ7?lzCKojEl7oWs|JFzxU1%e~3H&27j261SswJogH> z1OF~TIPQSftSB2*Y0NueuCfL%%$BD3f zOs`dTL3U5pF54m7DZATmj^2p@csTZ_6`BfA*i z9RTv2+Z$GsXgW50Y^J50cF9 zH)>#Oug#bMF!@)kS!a7~$~=HQ1^~C$dTriV69;SqI5bh6r(bA^hcDh107ItVc=LD4 zAp&dDRg>uf)+_!7fbR7s)3XYbsk;*6cK|eMP1m6)YOy90AR&QNeGmYba=}84F9V{D zk^t9?0j5xcY&ePXwsJTCr5a$Y98&X1BefPsTc4cm92=uxJ8i?W2-S223C{+GX_)=Y%G3-0;8Pc^I17J1W}SS_*4AQuCHhnija(1j=8wYSAHS_&`~|)Zgv0 zVb_+xKlC2u1NNOf--wZF>Y{3PRz0l>D_m~xF)L_D0FsrG!{aV57e1O6Pz10P^$ZsS zMKdH7=ruPUaQQUj=FgE);+F=7g)2~>098|5&hr|@(Py32!G1HlTGU4;taWJb{P2ol zQ?h(l@ORgLY&{iM`1z(av-3x(^BzS`$}M&e>^LfkIVFiX5s+P6aCPSQZ%-F}G}L3w z{nH^^T=rHU`y}wAlHUt{#gj55?8}v7bpQUOG%@WT?@bCy zEfMl#>4ifzv|>!mVIvN@&mUt!W|q2V7@gmzRcm$|f3&>-T-@I^J)>^bH?;*mi>_ z4qqT07N$_`Y_evH7s~1W?(R2Lx;Yi{*=08!l#f;K{gD6pVYUC&>~Zcb|JgG2xZm5i z+I}lZ4bj!S5$7l>Ul#6AuDrbMrXo@C%3)*i{g~Lqhv{XGkKLEKKS z^~%o3gWoOtIit#+np>h3objKNzP8$L^@Xy^JEfiL;|DBBIX$auYm;kTm8Qk%rs{c# zPvgm|e}3vT_{^=Q}o} z_hXVwph-&(7{0m8Z*((f?=ANW$@{)7ed>CU996#_loE2 z-|$6vTXcOw#QCbhNBpgG-^_Gn?nKUx|uZKh?I*zSpcjT}(BuDLvp@DSmHk znAf7)ryrf^7*Q`CJYmc?@wLv-Ltxy)ai8Jg0pc zR~lA?CEOu`^kNS7q|(A)oOp62#D8}s%!J`$QUoxmwn{-c4+YxZ`H|2p6zb@YicF?M(SNM-wu&F;RQseT)dU1>Pbuvy6|&kkBOa_pYXblHs6 zqecz%b4vX6@`J;}uHA4M!S(DsTQulF3H7e<-nS7Uqm|OnnPVP{7GCiASJAy|GQ%L= zyYFvo94@X~{Cm*+Lm!t%Wji_A`PSy#5U-r*yTV`YHuBXY+TE8M?EPf!t0Zx4-B0ai U)s)3AZ5UPi%|T&En(5O20Ih7m)c^nh literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/dmg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/dmg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..509039ef7c0c6ed1a1c0fa5a661330d0eef53204 GIT binary patch literal 3619 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/docx.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/docx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b0bc4b3940e66cdc5ebce60cbc4008af13c41c6 GIT binary patch literal 4075 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 S&G)qb@Qz#3g}fEI*8c$n9ZWy~ literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/favicon.ico b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..73837074b18ff48735fcf5a33cc8c6a09498853c GIT binary patch literal 1150 zcmbu-O(;ZB6u|NO=J|@vNGT~7>yF5rQH494Viy&5I&Gh8V}RNt4k7#Ky=XkK>*W2- zO72CiAJ>p`7qO02Ea1U$oT%-W-*A8$w4oi%*u;)^PtB=^>5tj|M&_4z#U9qM4cW8L z)8jBtJa=M*{xi?KoBRnCcF$b$Ki`|I)f!Rz^<8&TyGM!b*K;zdWh2W*egE?*&X@1c zulJiSvMxlwe5-m+5BW1%QG^PVB`LS{eBuT!p!eTE{(=Ww;Rf>Vyrd@NS$|>+dVUUh R2Z9KsF=E#Y5-ahq@dHtmFyR0I literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/fla.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/fla.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e8757e637d54d25ea9463e59e533792973abb335 GIT binary patch literal 3608 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/flv.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/flv.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c53f1357d26860de8075242a2f0abe6e14754d10 GIT binary patch literal 3572 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 Uj$G~U_K%LB)Y~C%Y_zrfADhWeZ2$lO literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..a5fac96d05b3ba566375d81fa94f660acf7bcb5a GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0vp^RX`lg!3-q3%M)FJ)an4A5D*On4h{~+#>RSjdfM9B z*4EbM=H@`Ifq{Xpt}al-$jC@vU*E*U1jsNnGz5wR0gw&h0!4rTs2)Nhi^CPb1>p>^ zCPPdGKykPrL=9BL$gt+g^AkX~T9gF&1v4;maB=hS^6?7@3TbK^8k<;I2Zm?l=H(Zc zl$KT0O`W!M?fQ*-_w7G&?D(nEXV0C#`RMVhcRzmqS~IV32GESho-U3d6>&)l+&xW! z23&3jH6&OUCx{e${xq4VV&{qk!)~31SgTu#5*O23ZhQWB{+X@2 zFVD3tH2%+Bb26nyvsb&jRC?-ecg{B#7+)@BF+ct!PR!3b=To7qU$}F}J+2FE6Qjdh z${ObQ*mL}yw{(B6&{~_5*_}~Sms?eSnDSz8$@SZvj@6>In-_44zSVuv-nB3K!aS4A zOG~6(W`QWr$!fkZ#@qky@j5Rycg00q&=$RGe{}l(;D;#+TpK*HBmzV;JT@BesKY$N Zz`zmUek&^CzCO^q44$rjF6*2UngHF~w6g#J literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder_back.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/folder_back.png new file mode 100644 index 0000000000000000000000000000000000000000..dc0786ec6cea1394a7bd1c394727ce9604c9141b GIT binary patch literal 1128 zcmeAS@N?(olHy`uVBq!ia0vp^RX`lg!3-q3%M)E07#M2L^NvAv_Sw|~OKsWav-ShQ@-+I8zUZQinN`;MKvcJJMP;NX#? zr_Y={cj5AtYu9hzx&QFV(`PT2FPYU7|t)Hku3cJ}G-&`8KU6hAq87==kjTKgss` z3im7Prq4Y3|MX{@^I+sJ+563aVM>$D(hVQ4ggNY6+j#l@iR@3gyfG@Wm8?>Wc&ze_ zi%Ql!NxjWz#Gk2bl(bYlYRjHQA^OHCo?nusOZqNuiu<>VF{4JNat;cS?{w6kwl+^nZGMyT_}1@~(|4b`Rj$vmG!~4%eUWdGvtt+AyJJr~xZ4FB zH20p+@m5sjlIUFTd;0W=1(s89X;)4)OUn87^~;sbpPn4~@#Dsg7efA7a(8zd7yUhS zbKxSdm1_(8^fcXbj`o(6N#|@X@p0Lv_D48-ZE>Fs&*W1te)Iec*O7NvzUdc_ZnW@K zi*#)nztpWvUTgIJR+@b+w14~dIW4^Kd-mDcpKMT#?^!cAwpZUXC<(25)zVb5ySm9# zJyAio!Oq^ais@}a14BRtdn!Y-+0W_a7ooAaCw|FmjY&OoIxYiKEQ6=3pUXO@geCwO CHQzk| literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gif.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gif.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f479380fb0db7d03a6580c674582f7f2fa9acc84 GIT binary patch literal 3754 zcmb7G3s_WT8vf3lb7m$kb3p`UL=T9~{v3fgYcF_8<7qJKz8Q-~aya ze>vm$%yAhc8L8>1KoA6^;RhU71c%a-lb5RVRH^A%3Tyxn?A4gfdL9E{Fxo76$|R;} zaWNz41s+TWPY3`{jn-;TRI9T93&-W2 z_zdIbUTI0o8^MiQjbb6<5R7-4ZAn~wCgQK{RRxKNX94hh$}On{!+hSub(Q&x5c^@g zOlM2aABoo)OLJ6+u`h3Tl_`_U!*M#b)@1Y&f)QV=WYf7dMm;2yu_+3~vk_0Nw5N^a zCo`-y3%R&6PhDkl4r0thT9#=t)QAHRueX@;xUo<(xtrB1xv?-m*LQFMtu%9 z7S5Lvu~z3CF()}-tIWrJ%JrpUZI=9zzEp9!E;W6Gzsjt4?nTr_?XlSNIBl4p>e5&g zO2n9ly2Tm`INuP{lgczHoVO8(AAv$b11y-J6l*OQ;Vv+c2TDl7rx`5RQVu%MV}!+4 z79%>s8>%pNf1cXO8Sdj|R5*JNaJ_Mq`*VgzxIV%$QT~*iipKx>R2CIa&7d>!@@%Pc_(aWKKsRBy9??hq?MNYb{H4+K)HhL^bYNn%wP} z$2DWrY#QqTSkZye*@chw>4Q~AC%IafZtBpZpLl(+3RJ)6FWpZM(A`+~(ihzQ=|1`b zetIDhS3vJnWI$Cq=So;zyzp^zXh)_EG+2LuJQHdiRXT1(%Z-}?+%23F>@zt( zqgSJ@-hV9a1n8gumFQqOaxLg8=dclKG3(fKGNP24N<~uXzuL9)xV=28g0JAG@DqXI z&*I1NBl#H|9zA*dP;86CTH#VZd~#fjaWi1Yu+SA(o^a=`7v8&9o|=h%>Z{B9F9A?9ge$AnEwL6alPXUSgly0D+kEV=5Bou0!{efMU5{5P8$&b zv=akl5Hc6eBf>^FJb-6(K#g#?JD)4uU5mX(p1ek$i&57|y6_T?>bM6nDzi;z(ABYJ zOld8Xp;jmjI-`z>j);qhig+jsy|l3wqejojS43)}*oPwL#X0&Q8F*YFxr(NFq<~Ke zNKzo6X^JltNTou7Q0U<)^75GA?I{#`P4oAbi30-zJ-nno)5Ja^aiEw>LeMlVAO+qO zhZ}t}8Xka?8&h^Yc08H%&a_hP4p{s#CYAUml&Czi5Zw`Ev?G%H6(O zL!B#E+?g@}WMD$%!&!G#nHhf9x}zeB{?k%$Hg-oE{&0bgL#wZ1I(Y^Dot}W1fqaUHhr|BkhYD z{9d=0?tWkPhpqKRp`D)$eYtqsrMYJ!mS3K@Wmfn5>XlE&-+A}-!invM#)6iL_Y;WZ-yrZt3G*aC z;2siq(A-|<3W26XQnb{^5+sk!-Mre z*B(3g;khE!hi&&JzBbDNky8g+BKMzVgPrRJH&21?MiUWfbA01REhYWA-F&H;a zIv4wn@_C(XNmEBm{p)A12Bh{33_UCR^vLaIn_WQnJgd6WSGw)H)SjMZiG5=)w`QTZ z_Xv{5Cq@kiLJC2VxrrJHBVW_dUacwRXu$@D;xYOf%;;b`)eOP?L|w#EAOeEZ(joSoTW;(^w{ z?<1a5nW`JJp6^uTp8Lz9)qn30{&@78!o>rk4YGxhd#mtpcC2{Q(A6{lJiq_IB;Tq- z3m^a2-pVJQL-EcN?Yt-PP`eAy(}~wkVel4yfk{4&w=RR#Z){a=FH3%JFFOh7EE-Ew z?o&;G6rGhPYS!G8FxBk~N*Z>(>2g-`v+stm%=(}O4IYw{UIkO%p7+bN&oAHWVx(au zr8(=TzM%J%0@HcwXx!|*zMkzj3%ddieJ1(3{Z6rBk4o*=06k5mD-BP*t&@=-9_!zi z@xo1U$K|*DTkS=J_~lEXf4*UWq4iU;!~xf4bS+qW=#;#*_pSG;jCS7qn zN*&zKK3O(7yJFM7L%h$QnV8vMFrhI-)}JuB-0!71GsE}YI?~^68Bizs&}V7$t6|L( s93WA~MXQ$!D&}N$h9zznl*EKBIp+Cd1JAd-bB$CxC3kX^sov51KS1K1&;S4c literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gz.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/gz.jpg new file mode 100644 index 0000000000000000000000000000000000000000..414d5da6fc4e3c926d0d2c3fad61ded968eef4a0 GIT binary patch literal 3372 zcmb7G3se(V8vZ9UlSBw1AiluLfEtli41ywyRzi5oBZfzPZ8eVpQj!oR!3WD$+Ox-& zszRVppvmZELNH?yC5}t*-92wxznh+EU%tF1xz+tX<9icM_7&aOa!< z|L%Xk|G#(cjOPo_4Nw*47UTj&QIL;6@Z6FeD$wZ`>J6p21w}dN0Fdo8I-NEN2Vi%& z1w&pIH)rlVPSyhw7y+RW4WUM}%c<4tivSzplIy_s;4{ET0G~{JvVS1^XLq3%-em@$ zw1^V{B#~7@ZiSaGnci4a{sQ8m zXt!A11?4__qr+5EiWtXA+H31(kvN3YZFcFfmJpBlS`A-7))@8BVBxcK5Kllns-_{| z7oRS4EiNN=F-~KRt^_g0p@o->g?hx%h+h}#3}i0UOtCJ z=E8g#CGQe*#F+GLcTG9&Q!K4j87J{>3{gNZk;#!!5>aQrjfN&qF0;1RmQ6s=x|1wD9QV z(PE{-pcZXU=IKR_cT9j$EsnlTM&m3`=6GkgjhK z8KdU9;0k~XE6|_a#NaxeZ8|#K@8K>phZcOIINJoJ&#Eu`HG7-AjC~J#H87sN!d}H+ z4`^`(Y@#ANs%O-`Cpgtc_@g2QOzG)q&aO-(lO$rjHQ(1CMVK-?{JHQDMMPw5cqHO*5`-VqayPAtWZKf(xsTH{+0O4{JGgbu@ zsT)~lZ)4CPRcY8Esgn4VC@wBjkLu*8nPMf6)TbWz9;MHhR-W6vD_hNE<_v1tS8}i1 z11YVOcG)vWQ0wUz+j`r7>aAFasI_-{MwJh>cgJ*mQ}G|ol>6h`M;`mU*kDU3J#uIF z_Ax?ZU)m+xbyAp!pn8d7yi;Q#XHvSS5G4JCi7NcQq?tj1bSS)!U{sNV<3?+eC#MRo zby4xN^@c^JdS6!3nUenwOU$a|)AH0!zg6^PSM-Jd`>nb}B?z&RD_wb9~UifUn z4^gq>2feE}kl0}``>m`$HP4x*GE4{oBPX{nzn;S>Nh(_mv(&g z*6GwodmGkoJJ@oic6HmOhb!79Q6srunQzqqV&h^IG_th@w(?;Ko9^F=& zJhZHO^Kf>`$=ds5VaBL%KLAU!{+dt_5vNJk&Q{g;W$KNuym_;KU1r8Th<{=KnnPjV zuif_hWnVNcS^3=J!Ldgw(ps{Yk2^DeRBP{olPj0o)d{~iaN}jw2KRgQ>sM^(nsR>1 zTcP#MW507u*IBvg#?o1%ZWX~b`suD|a1ljiMD73!Xlj*Z2gJGYE~`}p>aO+~GXR{z~z IzQxn?KLAko>;M1& literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/html.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/html.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6bb674362029da0c86910b8b32cc3a6b1ce55c32 GIT binary patch literal 3719 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 U==pE^vdV2`T8G0Y*I4fS5AsT9EdT%j literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpeg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpeg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4f258a742e86858281211ae7605b69cae66e2f8 GIT binary patch literal 3700 zcmb7G2~<;O7QQd9KmyR;yK+3RtynWja*5=(Ig>Mmt(tJ5p%ozLyZ7$79d@f%m@L`~CO- z?)|s8{^|M#B-t5R89)#OEW;1Dt_wfNQYxQNYw|L(a#ZL55dKwbwHkRefXVEzX)@F3 z;*wRgupf9Z4g4Sk{Ioi|RiRer05+D(z9+W3{{V~xaCyP~{S(>0`{t)->^cBKgm#PG zt}`L71K=BVR+|Gr@GaVt*Ep<*g<*&TZ72}2oW+%HoX+BMH!kKlg&HMtSgm4Rl~#|q z0daKsID6$d?ACw`jFZWj8Jj^zv$as$EENVL!#UiKKX8v@J_wqOPRyBW5%~1CR~IbD zcNCj@m2H{EgWGgkRRQ8zXz#T;(pdW(#5bJPMGD080Co_Ih)9ZXROn%iB|JSc9*mK!XM{Ar0SFu%V{{3}8eHgI)$L z24WIaqwW4YHOF!H8Dms(y$9IdILiGw?hyt(919gp$*Fk!e}u}R7E{So3eZ$4wUk;y zrK2^4dc>dXI@Kfv$9XFvbySbzQ%{#E?+ zg92y3$SE?RDg!qYb}w(igd9#H(*at1UPGP*wT>#CFryXb=8!QDTM4Eq_iipUMvqzL zpUZE``{eENH|77HFveKK2~{Fn$b;lD@-TUXJPR~=f;>qcC%egg5mEOrMNpa_*1U=4C@SXH*dW>||+$L|x5QYwOqrLumvYLnTuJgP#V5~K?hKnvyx zQUtMrY!;91Ji%P_rQlQLRqx(8UdDtBm~kwuiZ{*zZq>1CmF-=Nx{autaWHjwcK|3Y z*0nZ6WtD@DlgpE61zu$gon_X=MAKTMk>*@>+Q!%!TP>rH0rnnb`vKh1aQ7P#bbid{ zSOKv32RySbjM-K>0Xpme!3krwC_EEoy8%8()H!Xn?s$0do&&H~#K&>p3I8-ao4#_n z?%;VP+yyYQ)8+bgkIOak2FAY%aKh-i2J2OIh6;ccE7(&XM8GE|<3Wv=0jrG&0X~NT zvWZYH)(}x14iBKo0F;Nrp80HJ&syy5dGp$MUPgTz>BWz+RM&5ikY{xmOon6hlfi7D<6}}{;$jx&U@aYt&8#)j^18&t*ra6r!g$vePy&x_B>Uj=d8AN42}x2Y zd1Ff1nh(P}d*3;g+A<hp!AS6C{zF&#u zuHT#*eoJ!W>AxuSpV9{^B_;7&=3XxJn{9dF;VnstPPus{4H z{gupeZ{WGC885$d_*&exn7u7?!)~rBY3g3S`*y_RJ)MJBe)#fEXWjG!S;qH{&lE@J zZL113?prWj6`oK!?ZZ2PU(O_sSk{#akKOLQQhYlDQxwgPTAwfr4@DQCSSwg?)sUI(&1pN z@*K8^6#lX22iFLY=10aVZk?3KwRBDUes$T-(Iu4{IpUvoc)d^5vm43fpC?{19Xb(n zwz(`+7BRAO$9u1DyrfI=*%4i|eesP~eA@7@(XT++}~mvrG- z_u!Q(`J(rJW{A(ws>xn^inz~1!Zt?6eJy9W-=xoA==tl7?A{5SUx6bVm$man+^ zv!*oT`5?y&=Q<=$J0(B9d^-AE>m(mqBTCp>@l996*#JS>z)!`iV-+nw%}zTr_dmzq zd1LFpUb}FhX%V!yg%HudHrKA3S{iWvy}u{=S=qT@Nq7{ig nfrouJ%HD=b{lS=9v(h$%o^4A?m28|9)t_Ge=a-YZUH$(916_s= literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f479380fb0db7d03a6580c674582f7f2fa9acc84 GIT binary patch literal 3754 zcmb7G3s_WT8vf3lb7m$kb3p`UL=T9~{v3fgYcF_8<7qJKz8Q-~aya ze>vm$%yAhc8L8>1KoA6^;RhU71c%a-lb5RVRH^A%3Tyxn?A4gfdL9E{Fxo76$|R;} zaWNz41s+TWPY3`{jn-;TRI9T93&-W2 z_zdIbUTI0o8^MiQjbb6<5R7-4ZAn~wCgQK{RRxKNX94hh$}On{!+hSub(Q&x5c^@g zOlM2aABoo)OLJ6+u`h3Tl_`_U!*M#b)@1Y&f)QV=WYf7dMm;2yu_+3~vk_0Nw5N^a zCo`-y3%R&6PhDkl4r0thT9#=t)QAHRueX@;xUo<(xtrB1xv?-m*LQFMtu%9 z7S5Lvu~z3CF()}-tIWrJ%JrpUZI=9zzEp9!E;W6Gzsjt4?nTr_?XlSNIBl4p>e5&g zO2n9ly2Tm`INuP{lgczHoVO8(AAv$b11y-J6l*OQ;Vv+c2TDl7rx`5RQVu%MV}!+4 z79%>s8>%pNf1cXO8Sdj|R5*JNaJ_Mq`*VgzxIV%$QT~*iipKx>R2CIa&7d>!@@%Pc_(aWKKsRBy9??hq?MNYb{H4+K)HhL^bYNn%wP} z$2DWrY#QqTSkZye*@chw>4Q~AC%IafZtBpZpLl(+3RJ)6FWpZM(A`+~(ihzQ=|1`b zetIDhS3vJnWI$Cq=So;zyzp^zXh)_EG+2LuJQHdiRXT1(%Z-}?+%23F>@zt( zqgSJ@-hV9a1n8gumFQqOaxLg8=dclKG3(fKGNP24N<~uXzuL9)xV=28g0JAG@DqXI z&*I1NBl#H|9zA*dP;86CTH#VZd~#fjaWi1Yu+SA(o^a=`7v8&9o|=h%>Z{B9F9A?9ge$AnEwL6alPXUSgly0D+kEV=5Bou0!{efMU5{5P8$&b zv=akl5Hc6eBf>^FJb-6(K#g#?JD)4uU5mX(p1ek$i&57|y6_T?>bM6nDzi;z(ABYJ zOld8Xp;jmjI-`z>j);qhig+jsy|l3wqejojS43)}*oPwL#X0&Q8F*YFxr(NFq<~Ke zNKzo6X^JltNTou7Q0U<)^75GA?I{#`P4oAbi30-zJ-nno)5Ja^aiEw>LeMlVAO+qO zhZ}t}8Xka?8&h^Yc08H%&a_hP4p{s#CYAUml&Czi5Zw`Ev?G%H6(O zL!B#E+?g@}WMD$%!&!G#nHhf9x}zeB{?k%$Hg-oE{&0bgL#wZ1I(Y^Dot}W1fqaUHhr|BkhYD z{9d=0?tWkPhpqKRp`D)$eYtqsrMYJ!mS3K@Wmfn5>XlE&-+A}-!invM#)6iL_Y;WZ-yrZt3G*aC z;2siq(A-|<3W26XQnb{^5+sk!-Mre z*B(3g;khE!hi&&JzBbDNky8g+BKMzVgPrRJH&21?MiUWfbA01REhYWA-F&H;a zIv4wn@_C(XNmEBm{p)A12Bh{33_UCR^vLaIn_WQnJgd6WSGw)H)SjMZiG5=)w`QTZ z_Xv{5Cq@kiLJC2VxrrJHBVW_dUacwRXu$@D;xYOf%;;b`)eOP?L|w#EAOeEZ(joSoTW;(^w{ z?<1a5nW`JJp6^uTp8Lz9)qn30{&@78!o>rk4YGxhd#mtpcC2{Q(A6{lJiq_IB;Tq- z3m^a2-pVJQL-EcN?Yt-PP`eAy(}~wkVel4yfk{4&w=RR#Z){a=FH3%JFFOh7EE-Ew z?o&;G6rGhPYS!G8FxBk~N*Z>(>2g-`v+stm%=(}O4IYw{UIkO%p7+bN&oAHWVx(au zr8(=TzM%J%0@HcwXx!|*zMkzj3%ddieJ1(3{Z6rBk4o*=06k5mD-BP*t&@=-9_!zi z@xo1U$K|*DTkS=J_~lEXf4*UWq4iU;!~xf4bS+qW=#;#*_pSG;jCS7qn zN*&zKK3O(7yJFM7L%h$QnV8vMFrhI-)}JuB-0!71GsE}YI?~^68Bizs&}V7$t6|L( s93WA~MXQ$!D&}N$h9zznl*EKBIp+Cd1JAd-bB$CxC3kX^sov51KS1K1&;S4c literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/log.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/log.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2fe0e7c6934d35614774e055b9079361c736c03 GIT binary patch literal 3804 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 Nx-%|O*PHC@`X45_7oGqB literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mp3.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mp3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd66149082a8a8484c4ccf579445183f5810140d GIT binary patch literal 3335 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mpg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/mpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0da2aadb1a51c1bbbd4d392a0f697be2b4a5848e GIT binary patch literal 3459 zcmb7G3s6&M7CtxkCWKcYh+?tDtJp%V(tu!L6_ocIVgN<0N=Pn}8X(*RL`16AT~X0h z*}ALlC?Zz7wRRPkVr$1owYZM2^?^kwJ_ZM>*ln@PSRc)v|K>sHI6D0^`R|u=zW@B+ zIsfCv{H^&Gc%~#ICjdoJkc1yF-*IY5j*VTQRAnY4r^TZKz-gb_V9<+LfTCg(uS$$z zb7#+Co!UVJuYfD~f~#6%G(;N=20MG1;Gm~IF8_a3(gfd*{WFN5Unyzp<0W$ z3h{(|2m3+?Y|(%WjFZR}bG%N&l3FPFk^-Hc6C9TAC2j}ii(rwy409HmANFp>MOmr% z3?#W1@<}QyuGgsJvk;F%`x%2NhS=Xg+*h_JCmQj10FhS#pO9nWi>6iV#Uq}8*sriG$r_(d zF_vc$yAY?cFg61*#-aK5)G12DzKCo15*3*XHPa28K9S6Y@#$|2CZ$ya-CL~BAah~9 zjEpl1Ibuw@*HoB|`;?4jCY$(d>sV$^fi5B0%C9o$g}sQ{m`1)#MYLgj=8~F^PehDy zn0~G}htv(Rc%)VxM`{~{I0|M`YT%#*^0C)IF+2knRFDWU_%r~Io&wN;9xWVtIke~~ zcUXkB=kt^T$1-M+u}~P@OGe`?&*xZX_} ztr5%=y8@+yP8Jrz_o&norxeO?W};&z#BB5}3$%}6SMm#Vnu~w_5!DQ4Su*IyIQEQD zbBSXGz=##FWjE2WPOVi(N7_B?HKyg=D{ie-komIuio3RiLRsnMSn#fp}(Nd0ZSjJPteEcZ|KkHFYPg(zxI|W_O%!C zB{q^RSq0mCjy8*62& z>htF!CqM@|s6+>gk;`LMNrj7H2}X51Csw759}~Qlf7(HA&Hm7Nuq(3jF&`6 zf+Z;g+fJS&0DTeI$J^CgPL7>1Bm>TYg;lY~nJDZ!vRBFIa@4Iy-JFT5z;_2gY>8nB zuUlAXVnY;)ci3orm2qrxu_kB&tJdpT!DVE5&dBlQoHhu^dytF+c&HNIZ`6p3gEmt- zK;#d2XI&b!%_#%eZv^lO9kd1Foj80aK+9xJ8DDORhcDjq0LFqzA;NFUEe7wVF0=U| z-d9eW0iJC#o1Zk8&ChmY{7!)5dh=~q9$%p=07y?Kw?0TgOnKo&jV}YDjq(MtfB{md zQFg4N0<9boz-k>ZRt~xINh5bHjLiuAxXRpIhPk^+rEZ>X?lKRL*F0R@DJPL^i{$PO?BMHp|ryT1E6wP3@tTz1rLo;HaL{6TH&@j0&4+Th379|!vZB(kqU2wj~ z*WPViugzG0R(7*dbLC-FVDG-hs`=xJB3rvnwUyQR-kDx& zJF63uHs$vJr{xd&Pv>QSno+Q;{oAv;fVzebRdYx4fwud<9J}^D$zSeJ7D13wm>vr@ zjf#B%L1ZIDkaQ?oBK5FE5@C9B5RZ{~4O0Z4VEsd)jb#U$JiUi2RatrJ{8E0!=DI_d ztyxN@i3XI~m@i#VuiJdTars;Q2RgDhgg?tX(B15%slIH6$*Pgd??$Grx|td=Lc@5) zZt3_SKJ^`6e};E2bZ-vJIjlI^5f|a!v(~vMtMiNfJMOhjIecsWxsZOQe6Dt<>0m>k zF(C5r;;QP1tlEtgE$=UDYkBN5B`c@yyE(1pe|I}jlpgv=zmS^i!|OF2w=6DGT>mGU z@lz+?DBXK8;mFC*o{slEXNN}(i*F7JxXaC+wR=ov#`HaVx~_+wK9_cW*n_Jx8$wT> zKY2F0HSYrT>y^qmcft=br!`y0HZS>i{JUY>tFB=o{XKC{Q8X>Kl?f>M7zmEuq?n;r z=9RA4bz2QEZ{zIh$l!FpkY%%?K13zL5fCmG+upTp zSMpm5q$k&rwY^}ckgeqTvaKW#NQtmQ44yt~qvS9qSP?zLQ(gL_GH=Budx<=KF z?au29o&9&XaU*cP{$yRLb!ghF@m6 z)+BAsjp+)@^#9-AN+&9U^HTr0YU<9BU>{+IqS%_3p>*H))npD lu*Q4q@cM literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odb.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f40c746036378c31397e2a0cc49a743daebd865 GIT binary patch literal 3590 zcmb7G2~bm67QH|J|0Kl{0w~ZR^3hfq6$~HG-F6v8 zQCoYe1VpiIm%`H4aT&K(anJ#^U2y4c8B1|m9m{p5)Xv=Z69RNuTJutQ|K#5D?mO?k z``(Z3rtKGyrzNK*14U6V20vhHl^jk@Oq`)qjZaQZPeKQPWT)C_)QdQPqGF3lm6E_s znmmP*w15ac16S||SGC4$j8`ht0UP0xXV>=nI$$J#tDztEcV++Xmuntx)&Njav>Wow znj*w=09d`oXtDr^@1s5DON$Y)qzB?|CKQNRL2!W`k0vj#yGTTmO4#|*dOt7lR-u1Ld|pyuTLR!VSM_W(V}!{pxcV|8DuV8 zFC*j4!WuCq-Dc5dW1W(*Oti(6?HJ2U$=4;PI{0Nqy-FbagxZDcgg@?nmBhDQ#Lf$?P&OeB7XG3m?*CWeUxj)`MNF(aAL zXpLotITa{7>ExgQ9-&fuoD#6&%tXfoNLcG{4RMa)7Mf=0G)-%sp_-0W8an(K$GKwE zZ0MW;Fk=SVR~OnjPv^^y`8hq@HRkXaSKZE+!T3+*m%Y!nvDdI~VefQ|XK%B2@Y4eE zxC44YQ4y-r2|HnS@WbMJ-q z5*t}9*@gD`I_H`Py(~c%AnPp~Een$Mk)=CXoXl4iE*m53hn@iEzUe#sUDl$5$(XD5 ztbTYdasqUagGzMpC2~!eRg&Rin2S+6pA&~trY955r2ejIV@NHxs}LuNM~mZu6ZaR# zio?Ze1h=0&aX<9MVxQzxZ$CLsMwb=vomiL^XPi)>>PW4U(X&yv9(D5;eh$7n01^$x zxh7qK*1|<76hpXpe3kKBYOyA4Ag9*rIl*P-OuU&l&F1sMfV>CEIDi)_;r&MWGAhVkzJoYdRyL3z>~T|U6LapcwqDX^3mUex$9AlfK@U-(@MIez$+9TmlU_4oGuU-kNit76A!MzoU%1pJU z#I)e@z3_CED8BCo6Vc$_(7#yWiCit*T#l zEUWvh%(Jq}?a46{D!2OeUa8`DTrb~uAg!=wz>z@{&+TM=*8MoN=Xw9ujrW%yH(8SkavEo*$#W5C{>uXcUI$Y1T4GGpq(BW~WohVLJ? zwPvs1QQ11EAHQ;WkL5AJ(;mbSKV`>r=fnBO$- zi<^{vwAb@_in5*mRu~>iwa?RA`~AEn4wD=r#}W`REKSb3&?xW>4v$wa$SkR-ex|6u z%#Bjcyw_eVal!8cq<^oT%^e!@++7)3I&J&p)s0KsH*c$cs9ce`rf==}xUoTWz;}a_ zSF2x~TpCmKbkSS)=EKJhm`0qs@cPJU$QyQf#mLmfL1&t^C6E5Igqj}sh}v1`|7Mjw zyr%5wj%U`}-`3@~WldbrCih-CKEQRLPyUczo3yv;4&7MuV8gsU8LAs=LRUZOcCwja ztS(2dD(-si+AE&E{FQ%G-I7h(`ioDz7man|P0}djicQy=Z=DV{f0j7iJd`E3G+D-lt!}m7((T z!4V?=a_`+^j*N%{uj++Ex1#5p{yA;_OY!N@Wy#>bnl zHZ5)#(DHRuQlV$aP|6VCJt83ci(jV{)KOGa;qd)0Q%Vg_znLtG7+mtVioQN~pnH|P Sck`w#)b@*CMP58%Yxy7chgaAD literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odp.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f40c746036378c31397e2a0cc49a743daebd865 GIT binary patch literal 3590 zcmb7G2~bm67QH|J|0Kl{0w~ZR^3hfq6$~HG-F6v8 zQCoYe1VpiIm%`H4aT&K(anJ#^U2y4c8B1|m9m{p5)Xv=Z69RNuTJutQ|K#5D?mO?k z``(Z3rtKGyrzNK*14U6V20vhHl^jk@Oq`)qjZaQZPeKQPWT)C_)QdQPqGF3lm6E_s znmmP*w15ac16S||SGC4$j8`ht0UP0xXV>=nI$$J#tDztEcV++Xmuntx)&Njav>Wow znj*w=09d`oXtDr^@1s5DON$Y)qzB?|CKQNRL2!W`k0vj#yGTTmO4#|*dOt7lR-u1Ld|pyuTLR!VSM_W(V}!{pxcV|8DuV8 zFC*j4!WuCq-Dc5dW1W(*Oti(6?HJ2U$=4;PI{0Nqy-FbagxZDcgg@?nmBhDQ#Lf$?P&OeB7XG3m?*CWeUxj)`MNF(aAL zXpLotITa{7>ExgQ9-&fuoD#6&%tXfoNLcG{4RMa)7Mf=0G)-%sp_-0W8an(K$GKwE zZ0MW;Fk=SVR~OnjPv^^y`8hq@HRkXaSKZE+!T3+*m%Y!nvDdI~VefQ|XK%B2@Y4eE zxC44YQ4y-r2|HnS@WbMJ-q z5*t}9*@gD`I_H`Py(~c%AnPp~Een$Mk)=CXoXl4iE*m53hn@iEzUe#sUDl$5$(XD5 ztbTYdasqUagGzMpC2~!eRg&Rin2S+6pA&~trY955r2ejIV@NHxs}LuNM~mZu6ZaR# zio?Ze1h=0&aX<9MVxQzxZ$CLsMwb=vomiL^XPi)>>PW4U(X&yv9(D5;eh$7n01^$x zxh7qK*1|<76hpXpe3kKBYOyA4Ag9*rIl*P-OuU&l&F1sMfV>CEIDi)_;r&MWGAhVkzJoYdRyL3z>~T|U6LapcwqDX^3mUex$9AlfK@U-(@MIez$+9TmlU_4oGuU-kNit76A!MzoU%1pJU z#I)e@z3_CED8BCo6Vc$_(7#yWiCit*T#l zEUWvh%(Jq}?a46{D!2OeUa8`DTrb~uAg!=wz>z@{&+TM=*8MoN=Xw9ujrW%yH(8SkavEo*$#W5C{>uXcUI$Y1T4GGpq(BW~WohVLJ? zwPvs1QQ11EAHQ;WkL5AJ(;mbSKV`>r=fnBO$- zi<^{vwAb@_in5*mRu~>iwa?RA`~AEn4wD=r#}W`REKSb3&?xW>4v$wa$SkR-ex|6u z%#Bjcyw_eVal!8cq<^oT%^e!@++7)3I&J&p)s0KsH*c$cs9ce`rf==}xUoTWz;}a_ zSF2x~TpCmKbkSS)=EKJhm`0qs@cPJU$QyQf#mLmfL1&t^C6E5Igqj}sh}v1`|7Mjw zyr%5wj%U`}-`3@~WldbrCih-CKEQRLPyUczo3yv;4&7MuV8gsU8LAs=LRUZOcCwja ztS(2dD(-si+AE&E{FQ%G-I7h(`ioDz7man|P0}djicQy=Z=DV{f0j7iJd`E3G+D-lt!}m7((T z!4V?=a_`+^j*N%{uj++Ex1#5p{yA;_OY!N@Wy#>bnl zHZ5)#(DHRuQlV$aP|6VCJt83ci(jV{)KOGa;qd)0Q%Vg_znLtG7+mtVioQN~pnH|P Sck`w#)b@*CMP58%Yxy7chgaAD literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ods.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ods.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/odt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ogg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ogg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..23ed22b8925ceff4621392d15a022715ca9dc0ba GIT binary patch literal 3440 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 ADF6Tf literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ots.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ots.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ott.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ott.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eb6522c84b5ddfc8dfb785525b64adea20581b95 GIT binary patch literal 3581 zcmb7G2~bm67QKHSPPk&Kfl=o-E9nfwxInwi7 z_Hv6pI|nh2rPmf)hmbggbJAc>#9BgU#Mg_2bh5^%hXJFIl#DnWai^lvG*^5k!(KLw z*rhn-MTyynF%Bb6&}C>5cSQV+Xw4;ap=M^SU`{1-VSMJe&7pN^VD4GW*<>!vmsJXO zDMyUS+;bG=;XWl}*=UED=NilA7noAgUHqvwv$Pjc8@paC%_Z6}KKqkSOio3Nao8t< zWjLuDVlKd_OCq(6Ks*RWP&yF63VQ4fV1akQLoTF30zPdZqNe~%U`C68UI8s8$_t9o z_FG7Q za4XQZ(8)s~)T7eII1`~1XC^vEK*EBKrD5(d{0woN$#Cx522|6WrM20QaoicBW^2m| zfE_E)lwGfubviNiV1V1h*RlJ?T=YCK6>>gRU+xZfkE_G}GIzCkJa>h=il566k1Jr7 z6qTSVle7|cH?LQ#9BPs203G%>k!MA%O-fs>Xn|!x$7Tv0sUNEA z)RpS>>IbdnXpY#bO3Y$r5AzRZKXZUN4LnoB)G~*eB$Z6PHr96RTm<|FCOg$X;$zAxoAe$>M>R^^nENG_nkW zn@*mrJNja=Pj;(sJUMPgs|J}WrWPEo3BwB4#L{njr zgYTnO_v7R7RVMK17DGfhuQQu@$z|t7!7hkpf-wTfdytF+c$zD{->44fnr)6OfPs(j z&ibj@mR}06%?{un)ocsHJF)$0fPK-1Qn9Qt9=>?b0N4v6`$)ej&jh@it~;Gi@xGET z0(iI3>3p-+>3p{i<6i}+F*|RyE+F6TH_rjV;t z3b{hj)_EmZZd6OU%$8mB-?!~fR-fb0az5nm# zJOU~OjD~WC>I}4sVpNp#CHXS-H*iQxP{%1G;Wf-*1~3E0zbIY*^~W-0y#}zO;Wo zrtm@CtN+xTR(corK34nVq`i@khIFY{&yp>Bc7wN_>-_jZ_O7o6^z>Z+g?~m-;Nn%o zdnPnk4pwvsK34pFT(bE2;w!=D{_eOvdEly-S8^)mk3Cd#X~` z3&!*i4sGqd(r1y4EEA zGGYF-`bX+r6Q}%YZ3ul3RCpmWbM2UQ&(G?op6;`=^6Oi72Whi|hHAH;Sy{R4?EBlZ zqqb;{R}T6$@8RC?(N|9Oj!tXiAG7<76Uydp>~`02J?8Pug>z3Sa!xFL^<`>k-v~d` z;@9>K{#(tqrF$~(8YTp-I5ZS1+|37f1IJRFdnG7PVeJ-H#_J|d*YfJ|wGHQ+w#nd- zmm1C0GvWv~z;}C^nm<@Ko({QWEU?(ZnAz!ij`ogPP%VZW&FsH%;AU0TsOVan4(m|X zBOq>h%3q(I+T?vU?nuP(=M2oQs#t1xX|l~~*FN%b(3Vzp%<(Q=hjT=XCO$F{B}j-JBgfH_-Z9 zvia#o>V<{&e3sNTcgLhP%fCCLT;#iNdj1+V&tvztx2heFerKqlCzZA}-B*+_<&WEW z=qqNl?=VvH!`x6-Ngdvnecn{(w@F>69a&L6R}(dXy7=Jzu&8%ypTxvb`nYvhr#;iW zYF~Y};z)jI^%9k3Ov3M-^aGENf7114(AtKsQOV`J6D(5`A@BCxuq8*jZ`$bu=jHza DNg__S literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pdf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pdf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..809b5e605e76730d02b0e17dbafebe7db8bc1a87 GIT binary patch literal 3705 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/png.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/png.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f479380fb0db7d03a6580c674582f7f2fa9acc84 GIT binary patch literal 3754 zcmb7G3s_WT8vf3lb7m$kb3p`UL=T9~{v3fgYcF_8<7qJKz8Q-~aya ze>vm$%yAhc8L8>1KoA6^;RhU71c%a-lb5RVRH^A%3Tyxn?A4gfdL9E{Fxo76$|R;} zaWNz41s+TWPY3`{jn-;TRI9T93&-W2 z_zdIbUTI0o8^MiQjbb6<5R7-4ZAn~wCgQK{RRxKNX94hh$}On{!+hSub(Q&x5c^@g zOlM2aABoo)OLJ6+u`h3Tl_`_U!*M#b)@1Y&f)QV=WYf7dMm;2yu_+3~vk_0Nw5N^a zCo`-y3%R&6PhDkl4r0thT9#=t)QAHRueX@;xUo<(xtrB1xv?-m*LQFMtu%9 z7S5Lvu~z3CF()}-tIWrJ%JrpUZI=9zzEp9!E;W6Gzsjt4?nTr_?XlSNIBl4p>e5&g zO2n9ly2Tm`INuP{lgczHoVO8(AAv$b11y-J6l*OQ;Vv+c2TDl7rx`5RQVu%MV}!+4 z79%>s8>%pNf1cXO8Sdj|R5*JNaJ_Mq`*VgzxIV%$QT~*iipKx>R2CIa&7d>!@@%Pc_(aWKKsRBy9??hq?MNYb{H4+K)HhL^bYNn%wP} z$2DWrY#QqTSkZye*@chw>4Q~AC%IafZtBpZpLl(+3RJ)6FWpZM(A`+~(ihzQ=|1`b zetIDhS3vJnWI$Cq=So;zyzp^zXh)_EG+2LuJQHdiRXT1(%Z-}?+%23F>@zt( zqgSJ@-hV9a1n8gumFQqOaxLg8=dclKG3(fKGNP24N<~uXzuL9)xV=28g0JAG@DqXI z&*I1NBl#H|9zA*dP;86CTH#VZd~#fjaWi1Yu+SA(o^a=`7v8&9o|=h%>Z{B9F9A?9ge$AnEwL6alPXUSgly0D+kEV=5Bou0!{efMU5{5P8$&b zv=akl5Hc6eBf>^FJb-6(K#g#?JD)4uU5mX(p1ek$i&57|y6_T?>bM6nDzi;z(ABYJ zOld8Xp;jmjI-`z>j);qhig+jsy|l3wqejojS43)}*oPwL#X0&Q8F*YFxr(NFq<~Ke zNKzo6X^JltNTou7Q0U<)^75GA?I{#`P4oAbi30-zJ-nno)5Ja^aiEw>LeMlVAO+qO zhZ}t}8Xka?8&h^Yc08H%&a_hP4p{s#CYAUml&Czi5Zw`Ev?G%H6(O zL!B#E+?g@}WMD$%!&!G#nHhf9x}zeB{?k%$Hg-oE{&0bgL#wZ1I(Y^Dot}W1fqaUHhr|BkhYD z{9d=0?tWkPhpqKRp`D)$eYtqsrMYJ!mS3K@Wmfn5>XlE&-+A}-!invM#)6iL_Y;WZ-yrZt3G*aC z;2siq(A-|<3W26XQnb{^5+sk!-Mre z*B(3g;khE!hi&&JzBbDNky8g+BKMzVgPrRJH&21?MiUWfbA01REhYWA-F&H;a zIv4wn@_C(XNmEBm{p)A12Bh{33_UCR^vLaIn_WQnJgd6WSGw)H)SjMZiG5=)w`QTZ z_Xv{5Cq@kiLJC2VxrrJHBVW_dUacwRXu$@D;xYOf%;;b`)eOP?L|w#EAOeEZ(joSoTW;(^w{ z?<1a5nW`JJp6^uTp8Lz9)qn30{&@78!o>rk4YGxhd#mtpcC2{Q(A6{lJiq_IB;Tq- z3m^a2-pVJQL-EcN?Yt-PP`eAy(}~wkVel4yfk{4&w=RR#Z){a=FH3%JFFOh7EE-Ew z?o&;G6rGhPYS!G8FxBk~N*Z>(>2g-`v+stm%=(}O4IYw{UIkO%p7+bN&oAHWVx(au zr8(=TzM%J%0@HcwXx!|*zMkzj3%ddieJ1(3{Z6rBk4o*=06k5mD-BP*t&@=-9_!zi z@xo1U$K|*DTkS=J_~lEXf4*UWq4iU;!~xf4bS+qW=#;#*_pSG;jCS7qn zN*&zKK3O(7yJFM7L%h$QnV8vMFrhI-)}JuB-0!71GsE}YI?~^68Bizs&}V7$t6|L( s93WA~MXQ$!D&}N$h9zznl*EKBIp+Cd1JAd-bB$CxC3kX^sov51KS1K1&;S4c literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ppt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/ppt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b87590a2b8d7796fff1aec41d704d499337364ee GIT binary patch literal 4035 zcmb7G2~<-nm`bGU(g*tvG zK&oObR1xP|wXLGniXyEd!$)i@YORW3OV#}Qk`SQF)vo`t^4`ul`<}bcIrrWd%{|S3 zfgKYW9SJlV4W^nt#apoi?a~Ssl z16weG;b0;ZsT83CK`fw);!@ASSI-ZCA^|i^_^^L4`!Byt#1fSVfW}1jY_Up|g>Wta zDHAD_Y5@8pWcOdHRv^r%)f(KvK*AN_OeHJQ&r~7Y3S)n z<({FO8n4HtA|Y=k!lRMBPN5E??9K>3%gIa(MR*(lW|^jpOw{qQN%|&`p zIzeyGm#4<@5k_ON^33dMR2+&^CsKu@T7o0Otr?PNs>etV4q{0J4`DZi?K5(w>f_@v zswFciyEaaKMtB^;C=RY%B#aRtJRIS5%ItV*E~FVRm&l^1xlnxkib5^WYrr4NWpUJ8 zC|`mlQE78TG4aRhj0Ch!sj-BwTA839OC+aBBct{F0)Da{Nrk?q4gftI5i)6YoPj($vyMzegFqnn{q&&eii2rl7;zClDRF`4iu0)RsV z6CuPDA_7?hh#-Rk!2q2cNQX|OR2OG48%kUgm!x+wL2MvXCmNwi7A?Z^ED)E+M8Ggy`Omc-cs6pVC1cO_OgK-tVC*At{RM ziG$T{{Z{Ue++Vqk+%j$j_vxTH`Xdgi68;HZi+_oq!O!A1fP-JeFX3O|SMX~5oFV3i zd#{UP=)E>y%0^{Nb)j#*fwh)^j1|Tj!E$0nupC%pSg{5chh@X^U`=JYAkPRx-(>y% zLAgjF3Dv5vsvn+<+5u8XL`tNv6mgZPs#JyLkcXlU+$VaaggxOwME_;g`crGUPX(Pv zkD!MFhdz!TK=+`>P`GdB(Or-)0Nr^8^}3y7U<}GYGJu7uVu&+AyXvU5N{wEEbjy%# ziCU72-W>qp*@`@+G(AJj@#J#-IHBlOCgDWOMec4Kp-jfnx>OvcL?ux!k%--adJj_L z0J`F}?>E}eTm3fmbb!gv(V11>Z%fVrII04$@$R>|qBGHYKfq~UQI2wnE*^UE-ULvk zd3kDo(@ewA+0?4hbfNQ#Q3CL;Sflx~T%&n+0L57I^pTvra|t{XVEqAkGefMtCCb2I;WjfW>YF1oP(aqvh7dF=pa<@=zWKd9IPR>n}lTYaG7%zM_=a?ts*dX6q`8YOB{ykT{)&0oU7yJ;ch| zBSe7IGEojR64StZ|Fqq^uH@WGj`?`_CUVrIlvT!y&usE;pob>?sR8@XZ#GtP3jed> zh{xr|KY3|UzHPUBs?kwdsM=#EYvo~qTyjmRW1B+9$h?u=*Pq&SjaWL{>A>yfk5V*HE3TkDujJk2ysxpW!j$yx z?v0x}XNn)6sTx~X>Q?sXp2hK^2QTXviBFV$z0X?J^ijqgqijcRZ8->TGH(H_~Zk>F&01YYt7n>%M#M#h>OE zY_fZLbbD>V$_u%b9uBuR`@VbmDc__ZbItNOzugb}_4g;kGCLLJZFYGx3%70c8Qb&8 zvI01m$_;S-wlXew0&Q$7&t|v%(KZXtn;(q=kF`*(pv>t`=VR4)DC}5b3r<;WewbJ1=AQ_0U(}B{e+55)Q2C z+W7QWtNc6HUVkP(H)hlqYx8>ctoem;+O?^sWT>A%8ThI<&hqG&8puUGbYY`?M8inJ zuzqP^G0I~GH&j@5EM#%)&z=H&G^~9CWn2c>uvf&+Y+nqu2tDA{kbT1{Na`b z4c_J*ju$%PFBLSf%bPC<9zHjlEPL5GrCR;qqqe*>^*bW$Lh0PUOPlyoo~WdU)peKi}Qxt zThGYj3Q}rvyVjZK^qgHFeZAm@(Ssku^S_$pW$V*9_9?&KE~X>@lyc_+n<2cTe{9X_ zM4Lr_9%+wxbR?OgS3@aSp}*Fp;5y@?YpFT3hq#s!P=+i78w1zB**(i-pBy?2y|p42@%JfSsJ2P$`v4vqGyRDGw6nMxCj7WAj@? z(W!u>m5(YSJNA0Dl-8Y0DQa@N*s^@=mmTNo#vlDX;mP=a?K3`i{<_VY7MF}IYfD@0 zmsE4_OQK#$J>kcTlcyF>i6ZcBQ^| p{7aVq?Zf1B(^l(dq3q%67>i-oCSSqEpEPT-zkATNBdK0<|9`B#M1}wW literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pptx.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/pptx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62cbe2faf4eb2ad4ea9d5ae0fdfa114d31048ef9 GIT binary patch literal 4089 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/psd.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/psd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..312af5c8b938e172c7c61b6c461e6999bf027619 GIT binary patch literal 3859 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 KZjXZWSN;#Qw(cPS literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rar.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6057cbc5447e64c29d3c4017f7464d7229973ca7 GIT binary patch literal 3387 zcmb7G2~+^_;jw zt!Tocsi)P%Eiv(g*4EQl>vEKcL~E@Jbs;WQYjdzt>vBTVMl=2In_++)PjYhS%zfYd z_q+f7{{O%CzHwc1-3C=&wmusuih^AHfa|X8kY1}@WH1(G>+^Lu03iF=R9|nSIe=Qb zQ!wUaa%J=8bFx05VLbRk2>6;Tj`|FPAs?_2E_se_gI54O0rbYbcziVbJHLD@c!vdm zlB2z@!eOaJ+yo%8S?UERfb<^PQyQK1h-E)P94Meb#2SLD+&GJ1vm2L*oD!oJIYg_{ zQf;b0yaI8od4#=c1a@mc2Kve2?Yv;Ma3mK7p{~+u6~qG#HKiGdV*u!YN+G+{&8KHHSC`C1 zJQnR0R;RwiV{f*b3yTorTzYp+-7MmVa86qsTFfOxAih=2>q(7K4+9l^mJV?&;?U}b zT#tVy&#`Pav5S71tF?uQ(GMdmG36N$hampBP-i4-p=M?`Z_6QTp?{{Q-f8e?VEXO0 zLb4Xd%PM(?7$f>*`kmD!xKGJkcA8Tt@yuoCS6Z|69{!4Yo46NI8~cIKU?kemKYPI> z=yDLFANC1vFC}?HEE!i}$|AXqNBla>p-jL-9hkAVfE}I#2S&(&OnlaZfFqS)1shs; z9OcnsrTm}sTFr!MG-A`uYDlg`^SGe!t)Um;=hE2lnYivF{lTBe$fn(Fy zboO;N3$3Z_YhDG05jr`jg8Qh{?Pn=8;L1eD9LQ`7X^8gD;Z_Tatd{ewk5J8Uly$@7 z=*Jr|YOWiZ0dQajhN6obnWxWJ93AH!;V!d>7W67UUjaowlwZj`Nx$SW_I;8Y!}BHA zB{%TX2N_rao2aN3RawPKIJ~^LQ89EO(+MW*?;x)ZwGJsARnba&TgdPT$ppW?aIg?o z#|~RHS2h3AT-NN;e4u$SYK>u!qq4+oW$C(~xKXb(E^ToAy zd-2v@jF;F*w4@3{>y6Ac4>o0{a)L5anWYRgmz5C>N8KWZLN3bv}UO#c-t|NPu%wC4NZK#`f@=f^e z0MOReFBhy;)lM!^qj{Cfz*ia1>Ft*ISk7d#apI7J6L<$NEaNNUfxHLFJbjG~S6pI{*$%vor|H-2U*zdk(-+nUpC0rWBcY zH{Ei%p5lEa>i~G(?s9#z+vR$`2mRjwIAL?$ft9)@Yb8KI0lD=-4iYK=FKT=l5N%Wl zNJI>fM@{fzBNgr8&;aYLzlSpVrCS_#| zBa=xatW+*jtK~Ae+{ag`@EPOhE0-%&3O}X)#EBDq6zYI5{{Y1P#0e#lNMwx6k7fP* zedIp=Kf1X-1GOC9fM$k@09s8kYRc6O6UcuchWtVDHky*kk6D{VMGJ)^%ge_ds!D z-rEm!w_39vmtXDfJ-9UfdiN(=HdHQ2hjXVkAM4+?;eKJk(VCxL{JOQ^-ue{ZBqK=e zv5aCV5B8?5f|t7qsZW*^ct8r`oND&zid1j%GiIYuVI(<|=#CPRBc@n3I6Pi~LDjr!JZe_BOz4^jxNFAP_$xxXdr57*u=1TP}mU_PGYna)^ zc8*ic=(tvyyUJO5l6!Rc_NCKZjoWnx-a1&eSsH!m({k19sQg@+-{PL%g_OU#pnYX) z^>-ieNE2fl%DbC<|DZa Mf3yBi@TRNp|7IcnbpQYW literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rtf.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/rtf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..122d3825b90e6a38dc8f628296c3a45ffe78941e GIT binary patch literal 4081 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/sql.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/sql.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73485f1521ba06efc0e66d441cb1b9994c245580 GIT binary patch literal 3766 zcmb7G30M=?7Cw`iEG!M62#6vhs4M~viXejQ0oh~3Em|dnfkXm{lR$-H>-MzR`YLMs zs#c4LU6Izh6t`DV6t&_;tp%5-wED!YwN|WE%sUf8fPQ}M_bzbfpL70u?z#Ux_YS5X zOxM6MB{4Y>2!en~_yeYPVSRFZ{9KtlGch?$iVgtbCrZ6u%cB7bi;S#1DUO~oQ$Y(` zfd_-Z4&1>`sWRweWwJED#&Nl4|JM0EU?hN+z!&@bv;XvFm&+Jb0E7tbx?F>*5b**4 zzE-7YjR1n5&_4cEqaLwvC}L+86GSZGaDF#V;BZbio?+%>$>Wj3nzk-F@VqCMi4a45vP%tGGpT6AM z)$Am>1y`w*(kX~Xp#8Ys7{}R1A--E&Ff|sjKLBq)9-BC|o6n0ZQ)f*_?1J`OjWIdP zVlOMo$;d>EV|mpDx>PO>$2qPt#G{trh4`wPN#^z#^C2OZNsuBAKs-!cJjoKDOfi&9 z;q2x(W$O40#2ANU=P6TUh}{vt$?D|XT$nRi&1jRjxiCI?OmCD~av*ONX*0OFaJ`h6 zF__ngG09s-br#ksH$T=u#N4PFwph;PhViMhN>-YL7~@dC zGDTB4-4OHLa+L|3wn2!aU>czW26T{vy$Xt;3uur-62#$C4=j4}Km%H|Fz98_q9I;_ z0<^uDCo^-p$MiDt&7*H|qj8oObGm2fuyAygDuGf!otSiQx zb$t~811iw7y1>3VHI*N5vwG+YRQ>E0`=)Zp{5yU5Kk;wzFJRxwzuY^Xe~Et?e_A0H zcR*{-s1UQ#n0LZp!>wBk7N5V5y7LF_3WDNeJpXtAp}SUgGWgPtMQebe^(`>jO-Gf}G^ zRbM<8cLFpp6*JMmtH@HA_=2o@l(do$wjK509vWl(q@-|W*Gy+mN2T=K%L!i#hX=4i1C)is-T7SO?phpedGe}wRz_JBX~nZRs_8j|Wa^EYLQNTyOXrl* zDKcqNp{7Vfj|~bB8WS`w4Yf2fY>`q+OBRHN28WH$9XHl=3F3jrHInQ2d>$zjP(qRv z3i*6W;N;-sBytdmYzK+$Z3hmv6Ny|sT?Y?w@bK`kwRiHSJqCz9JRGLrJPqJa+ocQYLZClSnoGLrBDo)bYj5vE2MipwX>zuX$ljV}<22$HfvuQT@#QvYUZ z1A836b0i&6y0`i{ZQSm!r|(_zJ@VE4!=9V&jLSu@(KYI4LB)?3BjcVt%{g86ahv}& z+|z=iVFuMx<-D5}vL}H)Bc^|(T!dVo!qWPK=MT~-b|ZK@0>K9!L2-L*ZWQoHzJQQ8 zI}IGTm6H)ef%Xq2g>{BvW_mS8o$Kb=JO^)_OXmpYXiRZyl|@UV`IYQ{rOV2 zta}p%iA@3 z-@W?&_N=s9A>)C8)`U4t&iYc6kA zbfu-8c5d-6NN+oH_;jG(AF)SHhW`-dmnJ*2I$~XBo9z|-r}?$DnKw*a^^M}B=VR?* zt#>y9oQ4O-Dz```FRq-wqXFyhK~Dij4}b2ub@bzqB!O?lP6xHY<;sU|CjU6AeG~Do zSqGj!vRRrxp|I`^s&f7N?M%tS@GBd(&@t*ICWxsON4*ylw|QCuE1mOuKxoa<3jtLS zrD>~MyXsnF=Ti9c<&6#NW7eOUDbl|3)Mt;KDrD7CAK#5ON51w>SbO8Q6UXAS&oy`q zS9N+S-5#y3cssICx9&fpI)zR?Pt@QQ+j^p9NQ$yqVzZh-&j}D6Dcz<5ZUf$4*wxUtH<9rQsL)K}_}ztL~0nE~gJT zjIPrvsvXMSHx70^mH9*EK61%2idZ=7_geR9XVcn#e&%eu%ei@<-Fzl&TSDzush>TO zX&T@ADZTXE!cTX3PWE>5`9v1*?7L;QBR>yQ#Ee{?TitQqarL>p=GhMl6hoW*SFNZL zjY_Ldok3UZtvFRloVi(3FaJZjvfy_8nr-{1XS;T&ls<3I`SkUBO7TLS$;b!&|k2jxF|@tsNO|aaXRr J9x=t#`ai+~z0Uvu literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/svg.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/svg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f479380fb0db7d03a6580c674582f7f2fa9acc84 GIT binary patch literal 3754 zcmb7G3s_WT8vf3lb7m$kb3p`UL=T9~{v3fgYcF_8<7qJKz8Q-~aya ze>vm$%yAhc8L8>1KoA6^;RhU71c%a-lb5RVRH^A%3Tyxn?A4gfdL9E{Fxo76$|R;} zaWNz41s+TWPY3`{jn-;TRI9T93&-W2 z_zdIbUTI0o8^MiQjbb6<5R7-4ZAn~wCgQK{RRxKNX94hh$}On{!+hSub(Q&x5c^@g zOlM2aABoo)OLJ6+u`h3Tl_`_U!*M#b)@1Y&f)QV=WYf7dMm;2yu_+3~vk_0Nw5N^a zCo`-y3%R&6PhDkl4r0thT9#=t)QAHRueX@;xUo<(xtrB1xv?-m*LQFMtu%9 z7S5Lvu~z3CF()}-tIWrJ%JrpUZI=9zzEp9!E;W6Gzsjt4?nTr_?XlSNIBl4p>e5&g zO2n9ly2Tm`INuP{lgczHoVO8(AAv$b11y-J6l*OQ;Vv+c2TDl7rx`5RQVu%MV}!+4 z79%>s8>%pNf1cXO8Sdj|R5*JNaJ_Mq`*VgzxIV%$QT~*iipKx>R2CIa&7d>!@@%Pc_(aWKKsRBy9??hq?MNYb{H4+K)HhL^bYNn%wP} z$2DWrY#QqTSkZye*@chw>4Q~AC%IafZtBpZpLl(+3RJ)6FWpZM(A`+~(ihzQ=|1`b zetIDhS3vJnWI$Cq=So;zyzp^zXh)_EG+2LuJQHdiRXT1(%Z-}?+%23F>@zt( zqgSJ@-hV9a1n8gumFQqOaxLg8=dclKG3(fKGNP24N<~uXzuL9)xV=28g0JAG@DqXI z&*I1NBl#H|9zA*dP;86CTH#VZd~#fjaWi1Yu+SA(o^a=`7v8&9o|=h%>Z{B9F9A?9ge$AnEwL6alPXUSgly0D+kEV=5Bou0!{efMU5{5P8$&b zv=akl5Hc6eBf>^FJb-6(K#g#?JD)4uU5mX(p1ek$i&57|y6_T?>bM6nDzi;z(ABYJ zOld8Xp;jmjI-`z>j);qhig+jsy|l3wqejojS43)}*oPwL#X0&Q8F*YFxr(NFq<~Ke zNKzo6X^JltNTou7Q0U<)^75GA?I{#`P4oAbi30-zJ-nno)5Ja^aiEw>LeMlVAO+qO zhZ}t}8Xka?8&h^Yc08H%&a_hP4p{s#CYAUml&Czi5Zw`Ev?G%H6(O zL!B#E+?g@}WMD$%!&!G#nHhf9x}zeB{?k%$Hg-oE{&0bgL#wZ1I(Y^Dot}W1fqaUHhr|BkhYD z{9d=0?tWkPhpqKRp`D)$eYtqsrMYJ!mS3K@Wmfn5>XlE&-+A}-!invM#)6iL_Y;WZ-yrZt3G*aC z;2siq(A-|<3W26XQnb{^5+sk!-Mre z*B(3g;khE!hi&&JzBbDNky8g+BKMzVgPrRJH&21?MiUWfbA01REhYWA-F&H;a zIv4wn@_C(XNmEBm{p)A12Bh{33_UCR^vLaIn_WQnJgd6WSGw)H)SjMZiG5=)w`QTZ z_Xv{5Cq@kiLJC2VxrrJHBVW_dUacwRXu$@D;xYOf%;;b`)eOP?L|w#EAOeEZ(joSoTW;(^w{ z?<1a5nW`JJp6^uTp8Lz9)qn30{&@78!o>rk4YGxhd#mtpcC2{Q(A6{lJiq_IB;Tq- z3m^a2-pVJQL-EcN?Yt-PP`eAy(}~wkVel4yfk{4&w=RR#Z){a=FH3%JFFOh7EE-Ew z?o&;G6rGhPYS!G8FxBk~N*Z>(>2g-`v+stm%=(}O4IYw{UIkO%p7+bN&oAHWVx(au zr8(=TzM%J%0@HcwXx!|*zMkzj3%ddieJ1(3{Z6rBk4o*=06k5mD-BP*t&@=-9_!zi z@xo1U$K|*DTkS=J_~lEXf4*UWq4iU;!~xf4bS+qW=#;#*_pSG;jCS7qn zN*&zKK3O(7yJFM7L%h$QnV8vMFrhI-)}JuB-0!71GsE}YI?~^68Bizs&}V7$t6|L( s93WA~MXQ$!D&}N$h9zznl*EKBIp+Cd1JAd-bB$CxC3kX^sov51KS1K1&;S4c literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/tar.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/tar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb5adaf98c1aa16496d445a1fd43cb78bf126f33 GIT binary patch literal 3346 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/txt.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/txt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2fe0e7c6934d35614774e055b9079361c736c03 GIT binary patch literal 3804 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/wma.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/wma.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9dfa9fee6dd23939e537b615a6c28e09734df3e6 GIT binary patch literal 3461 zcmb7G3se(l7QU02JP?S9pdwftMSQTphUdajOCbad0)}UWq7ae+0wIJXC{R4Us?@r^ zYt^bf&DNae8VdbY6D7PVS;mCfEiFTmr`vv&?NU+(?>`+xWT z|NMjXy7eYVQj(NOKv5J-#|x~tg@=`Ld7&zEW|A^hfdK$vv)X9X^H_jNgT<7YoWRb? z%V&ihz=KiX4!+>7)|id)Dpe|=5iWTSw#U~1GXY!;d2xI&`?+84TF$HiphW1e(wa4u zh-(4(dX3R!0TA3lf6P3K5wUPIVs8@)L@Xn?)Q%GgF1F)YHcob?963a*SW~9fB5pt& zTs**EIsn@>AOrIxa|X_&)3Br$DpOU7PS4o__S-AM1DG#^mHHa2*=GKD_b^vv&A{g* zQhS+cdZq(!*Qga)h{vP6}3r`j2QDU z4>&^(=^J9ck5-*XdK-%Pb;zaEz(Exh<6Q#==mQoqAsG_zX#^8SNrt@t%TXd3mH_yNn~0;jrUu~t3s_#rGr+q#IVMO;GAz@uQ||*6U2Vv0CA#tj5tu7>SD3tk>W7%bn!%t__@|i-ya`Tiw^RzSI(}! zcrNk==pYA`=wKdlP1se^VFT1*)`9PdLn-6WgfYtJc5MvV%T5&ng&ei!f&cfB=w*x?4Wvnyl zO3N&4xJ>p3HXc7^9IG^FLW5bgUeDS>X4b@+In!KD8w%t*NX7v?%(Q*qs1cX@eU>zU zX+Ptcb*0~zUjy)&8DL~&zi$$riNpT{a5!31W14HvhacW=0n8;4;kMtDM*^NrT~_Nu zJg8Tqa9D)cAkq-znymBw+PkxUx=J(wCE~z^_-S1u47YF zisVY2LB~df#)gK6Mx|meEu6`q*0Zu&tt>KD8>7)$Z-5+l#AtHk98?FhY?JYP&_^#M|m=g=g=XdA%yY&ne}Us zir_7%r>SwklTx&lvYvv`SUzeZJ#d=HO(4YCXpDN3e~<>7^#|}kI!{7Nuyu{>py;J} zl;66I7Xsc6I=#y8_oT@qB7$!3`V`*nID2Eh^uhjny!|Ht+)jq~sAm7NIi*ke_Nt_e z;wW5Vn-N6;5}+8o$a30^541qYP!d@bPwF*NRfG~mD2(Fso^9Xs@AV(HQEW4o{Zk+-DN7w-F9a8zUxK$#;&@_7b1N;9w%-*(=lgBd(20V4nA1j z6}|al)c37vKL$S1b(Rk|1V?XM^JLG;FvF7k(%|+PiqN}XPW;$=cWUU)qodz%_FlBg zf90N2*Sh>4cL};w^Y7((eONRiP-8?IFxKKRL`c3!9aw=!w?=&dOw%yPHolZS7G4FwCY{aJf|+U~?dq1VH< z_!S(SkR?c1d~O6ggU^dumS0d8@RNQ?`pM7z3cgz%c-=iu&>Xe9z5K49@yO1}S!=H> k&Y-7EOUd6U?tV|?Kff$##R5f0{m`YS=~3GnCR#iG2ah8hu>b%7 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xhtml.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xhtml.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3420b3359ce45ce5defb7c0ebccaf9eee669ce9b GIT binary patch literal 3653 zcmb7G2~bn#7CtxkCZrHTK&uEY*9D=B&;YSQwIWM^AWPWXXsaQ)KqLvtO+et`dy3Yj zIx5;eowh3A?%4W7u`aEORrI~Oj$0A6ZgjL&Yt?7#Li5g_ga93yUR;jjFqeEPc zctk-rdr>#+)PM|(lgyboUaw_IE!2Ezq29nb9M0}9+})Ue291U?%-PWfVlT0l z2+6&ePsw)SI;}>TgLoL)kDG1r#6BGHy|R+LIK-g<0>45&DbL9ljHxQlort&(+I4!H zD%WMNG8JTGBF3?ThLY0pBo5&m*IE;>mM{eIwPH?1))@8BpyLvih({nESX`FkichCn z%X5g`5vQs+AptCu&S-dLGGdIw zJmO4wq;80X{yI$}scksou`q$s00*T|fV~z>&;cxDLo&qU(+oU%3PBGBv~cL<(4wcj zp#*KO=BXVV=a?==kz@27G8$)jHOD!_T^Fa6>C4EODEy9Q(wKLcXeI_&CYBk;jAath z8pDisD^PdS$wCp_MWxO-7AV7+iH->nzbv3E#65oR zSIf9lt3_Jl;*$?Dofa zUwJGC=%}^ZUo_b59qTau6@Wtq`wf_-tk4$%q^FZxAH*P}{P3d2mjTg61%S|j0aB?z zH_oO)TpR(wd_6EO4!QG5BX=#1c0C1k0ym?oj&|dGLbd-6icGUjZ`4bM9Pl>PJARj-1Nf1gP6yhjvhVl0C6nhfJ|JUq?!B-6V zP(@QiK;TQ!zLfn4^e6v;P!!3~)jTL#C>Agx^!6ryka{-zWsuM~L`KW7bPH$o^cI}! zgG)*a)!(1!D9S$-TlB%)_VQz2^Yh=huUPyka=*`CvN&r~LZ9M`-p^^)Ihe+o2FgG{ z!gdLv8G%p)l)R668qO(3C6rL`vZZq5#O?pRc+0qE(ePvEyw>&0Jhd5S>Hbi&)zrIk6U7RCkC@3Zzuj3rulCFl<85J3#-RG&5B{uQ z_>u4|cy4+2x3|AKsMz^ST_a!fFrV{Z`FFq9ZjS9}T|PHhHC>U?-)PnC5ABGWsn}{U zzZlzavMFfAiWy6mEKR%AJaMg0(+)}9`^z$R9qd&yapgY>_V&7Q({KH(`F>Q+)GRK2 zZ{wUVJ_(!@oEw-^-Q=Slp*^u=^LC%wBj+Nwzc!`*y^}WwWIfn?_2r{o`Y?6W%$F<{$!VuZ7ln%ZR{Wn#Tp9)6hn3HVyy9Ch=`NP zvuauOG>v7pyS}m)?E2N$m#n$Hrs~2jI_aMOtjs&NWC!*=DcKqRFHc2SCI52Blk%-8 zx~y70`bO>w^VyK|9u*;Ni&|37)gSKjpIMdG>_;J!*681UviO=YPY#J~n&pd*)_t`n z??AdaVPk#k``5&hek4`Y7~+{ku`YSCld(+#W%xf2$ z>O@atn)BKOFJB(2_~7j2$-8CBpi^o6UT*oPW!dS_lBgqT+cvzxi<8-e{4G&JTu_=oA%cK0giBoivR!s literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xls.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xls.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62e21ddf236050f1c0d9ae46b96d2bda00c2b735 GIT binary patch literal 4183 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xml.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/xml.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b2d75b9ece1ca16ca87b4be2b2ce76566ffd7af GIT binary patch literal 3774 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/zip.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/ico_dark/zip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..414d5da6fc4e3c926d0d2c3fad61ded968eef4a0 GIT binary patch literal 3372 zcmb7G3se(V8vZ9UlSBw1AiluLfEtli41ywyRzi5oBZfzPZ8eVpQj!oR!3WD$+Ox-& zszRVppvmZELNH?yC5}t*-92wxznh+EU%tF1xz+tX<9icM_7&aOa!< z|L%Xk|G#(cjOPo_4Nw*47UTj&QIL;6@Z6FeD$wZ`>J6p21w}dN0Fdo8I-NEN2Vi%& z1w&pIH)rlVPSyhw7y+RW4WUM}%c<4tivSzplIy_s;4{ET0G~{JvVS1^XLq3%-em@$ zw1^V{B#~7@ZiSaGnci4a{sQ8m zXt!A11?4__qr+5EiWtXA+H31(kvN3YZFcFfmJpBlS`A-7))@8BVBxcK5Kllns-_{| z7oRS4EiNN=F-~KRt^_g0p@o->g?hx%h+h}#3}i0UOtCJ z=E8g#CGQe*#F+GLcTG9&Q!K4j87J{>3{gNZk;#!!5>aQrjfN&qF0;1RmQ6s=x|1wD9QV z(PE{-pcZXU=IKR_cT9j$EsnlTM&m3`=6GkgjhK z8KdU9;0k~XE6|_a#NaxeZ8|#K@8K>phZcOIINJoJ&#Eu`HG7-AjC~J#H87sN!d}H+ z4`^`(Y@#ANs%O-`Cpgtc_@g2QOzG)q&aO-(lO$rjHQ(1CMVK-?{JHQDMMPw5cqHO*5`-VqayPAtWZKf(xsTH{+0O4{JGgbu@ zsT)~lZ)4CPRcY8Esgn4VC@wBjkLu*8nPMf6)TbWz9;MHhR-W6vD_hNE<_v1tS8}i1 z11YVOcG)vWQ0wUz+j`r7>aAFasI_-{MwJh>cgJ*mQ}G|ol>6h`M;`mU*kDU3J#uIF z_Ax?ZU)m+xbyAp!pn8d7yi;Q#XHvSS5G4JCi7NcQq?tj1bSS)!U{sNV<3?+eC#MRo zby4xN^@c^JdS6!3nUenwOU$a|)AH0!zg6^PSM-Jd`>nb}B?z&RD_wb9~UifUn z4^gq>2feE}kl0}``>m`$HP4x*GE4{oBPX{nzn;S>Nh(_mv(&g z*6GwodmGkoJJ@oic6HmOhb!79Q6srunQzqqV&h^IG_th@w(?;Ko9^F=& zJhZHO^Kf>`$=ds5VaBL%KLAU!{+dt_5vNJk&Q{g;W$KNuym_;KU1r8Th<{=KnnPjV zuif_hWnVNcS^3=J!Ldgw(ps{Yk2^DeRBP{olPj0o)d{~iaN}jw2KRgQ>sM^(nsR>1 zTcP#MW507u*IBvg#?o1%ZWX~b`suD|a1ljiMD73!Xlj*Z2gJGYE~`}p>aO+~GXR{z~z IzQxn?KLAko>;M1& literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/info.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/info.png new file mode 100644 index 0000000000000000000000000000000000000000..6baffc3307de0704eb7a515da29edaeb2285a9aa GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}W`IwK>;M1%flNApZDpIffYvCL z1o;IsFbc9U3w(b6*6+pN=feL!+-2uya=-t^$CZ`k9p6I{4xz{VNA|e^Ro8mDIEGZj z<@Ry%H9K&)9*mqLS-M5(SCp4pC=vRg^dro%TLIC+vyZ=a0{oyPt94M=4aF?JzVB} smLt)m%=R{;CG%Y6IG2Zkj#)pSaF&L#uQ=J&=>-ZMPgg&ebxsLQ0GQ@qmH+?% literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/key.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/key.png new file mode 100644 index 0000000000000000000000000000000000000000..463d08262dc74d741461f60e6643339e03b5f6f2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa4)6(aH8wW>|NlRb#00EYOb-B+ zag+r41v4-(GO;&oKBK<4X)jRB)zif>q#`a^poM8q&xQ~;HUWXxFFY8!T}n!}w6?Xe z8KiKOG&oq#xOguxkYO4ZM`~(90#HF}Vp3W{0*5ziW}3<|J%)flF=6i3f;6Ck44$rj JF6*2UngD%zHDUk& literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/label.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/label.png new file mode 100644 index 0000000000000000000000000000000000000000..fa65317110b69e3e174d9c885e191cf79aaec208 GIT binary patch literal 479 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

j18u&F);XYTzQ4ESARIc40xcFMNx;gYyfz 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/processing.gif b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/processing.gif new file mode 100755 index 0000000000000000000000000000000000000000..7c99504e10b085b4d083e7473df26e4e1f4ecf18 GIT binary patch literal 3209 zcmcK6eN4z}Q2rbDSRQTqiegkVMdcOh*)yl$90>MUHO; z$`puTM1;T!MiGo+m3fqAYLQvxXtjzut!L|YXxFvO(^-ylmi4qdoVq8Ac4uw>ME>Hx zocsO!zR&Zxvt0|GTSFoe9Yl!B<~B4nTzL0_!{wN~HyJw=vs$d>FO`q~c|5u=8u&$E z`rp$d!y^Wr0TW~4*6`T%v8gYo7Cpac;**Ks+TexJ3tT?e=kZNFn2Ha@)1OMOsjC_P zXgt;*3#<-Ie=|LDb|lgsxqa*Q!-o&i6ZkVfl;k+`^X!>Ro%83;zjs-6o^)Wvce| zZqW)6eWXI%a||6<_iJLECXwi6I=XNFG6NgG=#Yq4NL#MZ@>*%3MR=0z)YW;K6q>plt6OP!bKnhyus2S=!ILt)->zn-N}q+ zGe8?u0Syen(?A(O@=4I~f4jK7GAmuT%f$-Oix-9rsQwGX^R^x=-(%crz4R;MJ}y>l zKeUvUQop1B#KpJUwuV`6zW6EkX(G#{saf9Gt9M%9;sk*8foPYtGYPQrszc3jFH3UMy z10i6WSr7in#T`kBoH?VJ3qz?W<$=Ls>$@?}akN)(zrWgu+foz7K zr7WgvqXtKoTvk)m*p#MLhg=lWtlPn;D^W`$o82DiDtf~%)*$h2M{{gIrKa7a*sRZy zDG)|DRo2SmF4bF=0*57HW@x?OXh($aAp86WNS>d^rEmD#3i}jf8Y{vot`u=ya!Z*m zqGR-Y;?8o;4Gm{NIg72#eN18d4#n06$She3h!$c74M;9o4H!i*z<>zC1{Me#Vopr8 zD`Nl%sRKoF96}=i6B<P!NEHc7Pi&&J+lLcyZ*v6z(Og_pC1| zn_pPJf?R%h>EGjRsB$~+=_8|?4Q^CF@aBn{ofE9myQg#h@zwPG;5)qMZmrK8MrO6PEVU!6Gi5$LgB2Rt3I@0tB_!$zU!vV!e75p*n_mf zA-hbeyynY%Ja&JW19r>Z$;6oIkHKyM3xI%rz*Y+|VeIen~i2W>60 z+|K$D;&i}^PqD0R9ekZ)o=aI23sNg7k%8u=)n$td8nex$#mtBmip^fLFd%GI1Qd$QM2i&~%O*oUNC zMoth~rXLBn+r^l2_O5lvR3v^)D6cbK3K;FGL60CHIORyetslF$KK4lcPCc3$AYypU zurMHH7)nqE2r)6EWEg~-NE~)RX%I#hJa$D+BOuwEbifLD8Nee#mi~TETclLyNabIlb4}{ZBp$rtyd_QztL)1 zX-XAp#QmX||IonEkbV!^+vaPJoH`TY;be}~${`AP#%0(N(K1ef&Tm}Oi>!8)Ojbqu z)j1SS+v8e0W>i;&))tO1IHH5PmRzT$; zN^!BzRE-24V+F$N@=Pq@O0S92Qq;TOOOg&{PoG()Qpp%4n?2A=u0^Vt@%T_tJogl1 zJkv`YB@X8uxOC+TFXmGa`|_lSzpgEZRm2NOy-Lc^$#DK?Ch^>Ny~bN+eXiclkrJc6 z5c>QoL#Cu$|7wne{r&SWaZAC$1gXN>fSC@XD!DcwcHl^?U^t;Z8i#nH3s4*&fbd~= z0}3F5AoK!?1Eol;7FZ9%BcK4RfC5(mutI}ich7huk}mvs;=G+Ie^%6AmF+7=^_lG} zGq~ialo;-l{WQ1!;L#5^xcQj-Kt?&Md$;N-P^o&s0cyFiqhWpNO-T z@72qM0(>=PT9NU@zwl49tL`UDj%F~VXY=uL%^JyFY2%dra0(CRokd8j$Y92u+< zNF;*1^H;~Njp6JVn^X?lrRe7BHNWx7rR7DGLy3gyt2(Xrue6Hz>?*dl`?_8H%P+5I HqM!T+FLlTe literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/rename.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/rename.png new file mode 100755 index 0000000000000000000000000000000000000000..a425ee7529301df781a5c3f21f23263a7c3e3c81 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Uw}`D>wg#!6cmh%j0Exo1O!x6 zRK&!@fb7GE56_u1XZiBw;^N}&?(U+ZqCkecyu6l{mY$xTfq?-~8Bjz?Nl8sjO;uHu zwVY`O&}8wFAirP+77l)K8F^)W69?b$!k!BkuiU(K`@@HKla&jBN&-Ax978JNde2&m zH7E!;UtGY!RVQ%q;NSd^Q$4N6OTI6u_!0F!?%uh;o6mm-)ptEj=w2dmV{2OW6z?DT v^QUgyA}3w_dgI(FS0^Pt&rCR6qGJH{an^LB{Ts5hht&W literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/size.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/size.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc302f200c97c361acf473d0d8f9bd4a868b47d GIT binary patch literal 660 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/trans.jpg b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/trans.jpg new file mode 100644 index 0000000000000000000000000000000000000000..147175ee8e65cf8d678b66368995de1b70123c06 GIT binary patch literal 4024 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 aK4MRt&fO?7DRw&0ZU#?RKbLh*2~7aatZW|u literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/url.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/url.png new file mode 100644 index 0000000000000000000000000000000000000000..f18499afb62d9ce8961936ccd9a358d2da20362b GIT binary patch literal 593 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfw*a3I*Z=?j1DW&zy1Kgbu?Wo; zV`F19kuwuz4+Dh)OM?7@8JJlcz|j;hs_CjCY1%U^9+?9iMqY4gVR;b%?h zUT#6H2O4MYU6vCNeZN`l&Lid7&!Y~e@APzW45^6oJ)7Eh*g>G>;-UDf^!NQfYXX&i{{Fe-RU4DBeu=b} z-%d79UEZf0eXj4<%%3nJj6ZhnO|c*$mf`~?*U~sAPT^Udc6`P3?{*5|j?IS;&RG2H z$bS9P@vWBPr$w*N)-9hJ5pv~RW#H;hpI*%}XH}SXdw0_3g9&{7IV{J$k8W7>@#W9f z^&Q@>8Xw>OeJpIny5xcO=`-eabwAl>Hf=ffYrp$xM<R#a>3ve0!aO@p;+@f! RR|cR!^K|udS?83{1OP*>n)?6% literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/zip.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/img/zip.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef55c7b72fd530e37881c36f0bfd697250e297a GIT binary patch literal 819 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47<&SILR|m<{|^*F2BD#$wzl>_ z5eSJa1z|flIM~>L6aWDm8yk?cu&}kYwPR&v<>26e=<@aTwXv}SN*NoQ0!g42paMNT zJzHA`AlJ?gXo4LN4-b&d!omX7%*n~gzy!3>PFh+p8)7w3pP896kd%^=1_}b*1|)55?7_C% z0PO;DK_XzIfTX>hqk(}DPz0h9$glw#WCwD&jI1m(Gbreg0mK$pcfz_ z5H&zo0rfgLxwyKz0}Xd{bOxH>;NT1lFpDBTy%fED z3#hrMB*-tAp_1`;MHTZ-rr&in5#Rp&tY-<8ydOBtddsEOPiwfo1%7Yhc_?<|(vL%z zA}6FoP2Bk7QV+L_vn+?*=aX)exBiF~`F1w%pIOM?qG;iUuZ9kP=Y~(M+M?dZRzK7-e%HH|>t5YnpvX}Za!6iO#MbeqG;^}k^F=%Yp0__-wUu-` zl6mX%Pu|dvX*@HcUAa#&yj?ga?!R#DX)}{W9YQL>?`N91e|;YAn=8vHdu27VgNbO= znf@4?r*mcJ#@;+CxCZ3|_WMQ88~L + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FtpClient; + +use Countable; + +/** + * The FTP and SSL-FTP client for PHP. + * + * @method bool alloc() alloc(int $filesize, string &$result = null) Allocates space for a file to be uploaded + * @method bool cdup() cdup() Changes to the parent directory + * @method bool chdir() chdir(string $directory) Changes the current directory on a FTP server + * @method int chmod() chmod(int $mode, string $filename) Set permissions on a file via FTP + * @method bool delete() delete(string $path) Deletes a file on the FTP server + * @method bool exec() exec(string $command) Requests execution of a command on the FTP server + * @method bool fget() fget(resource $handle, string $remote_file, int $mode, int $resumepos = 0) Downloads a file from the FTP server and saves to an open file + * @method bool fput() fput(string $remote_file, resource $handle, int $mode, int $startpos = 0) Uploads from an open file to the FTP server + * @method mixed get_option() get_option(int $option) Retrieves various runtime behaviours of the current FTP stream + * @method bool get() get(string $local_file, string $remote_file, int $mode, int $resumepos = 0) Downloads a file from the FTP server + * @method int mdtm() mdtm(string $remote_file) Returns the last modified time of the given file + * @method int nb_continue() nb_continue() Continues retrieving/sending a file (non-blocking) + * @method int nb_fget() nb_fget(resource $handle, string $remote_file, int $mode, int $resumepos = 0) Retrieves a file from the FTP server and writes it to an open file (non-blocking) + * @method int nb_fput() nb_fput(string $remote_file, resource $handle, int $mode, int $startpos = 0) Stores a file from an open file to the FTP server (non-blocking) + * @method int nb_get() nb_get(string $local_file, string $remote_file, int $mode, int $resumepos = 0) Retrieves a file from the FTP server and writes it to a local file (non-blocking) + * @method int nb_put() nb_put(string $remote_file, string $local_file, int $mode, int $startpos = 0) Stores a file on the FTP server (non-blocking) + * @method bool pasv() pasv(bool $pasv) Turns passive mode on or off + * @method bool put() put(string $remote_file, string $local_file, int $mode, int $startpos = 0) Uploads a file to the FTP server + * @method string pwd() pwd() Returns the current directory name + * @method bool quit() quit() Closes an FTP connection + * @method array raw() raw(string $command) Sends an arbitrary command to an FTP server + * @method bool rename() rename(string $oldname, string $newname) Renames a file or a directory on the FTP server + * @method bool set_option() set_option(int $option, mixed $value) Set miscellaneous runtime FTP options + * @method bool site() site(string $command) Sends a SITE command to the server + * @method int size() size(string $remote_file) Returns the size of the given file + * @method string systype() systype() Returns the system type identifier of the remote FTP server + * + * @author Nicolas Tallefourtane + */ +class FtpClient implements Countable +{ + /** + * The connection with the server. + * + * @var resource + */ + protected $conn; + + /** + * PHP FTP functions wrapper. + * + * @var FtpWrapper + */ + private $ftp; + + /** + * Constructor. + * + * @param resource|null $connection + * + * @throws FtpException if FTP extension is not loaded + */ + public function __construct($connection = null) + { + if (!\extension_loaded('ftp')) { + throw new FtpException('FTP extension is not loaded!'); + } + + if ($connection) { + $this->conn = $connection; + } + + $this->setWrapper(new FtpWrapper($this->conn)); + } + + /** + * Close the connection when the object is destroyed. + */ + public function __destruct() + { + if ($this->conn) { + $this->ftp->close(); + } + } + + /** + * Call an internal method or a FTP method handled by the wrapper. + * + * Wrap the FTP PHP functions to call as method of FtpClient object. + * The connection is automaticaly passed to the FTP PHP functions. + * + * @param string $method + * + * @throws FtpException When the function is not valid + */ + public function __call($method, array $arguments) + { + return $this->ftp->__call($method, $arguments); + } + + /** + * Overwrites the PHP limit. + * + * @param string|null $memory The memory limit, if null is not modified + * @param int $time_limit The max execution time, unlimited by default + * @param bool $ignore_user_abort Ignore user abort, true by default + * + * @return FtpClient + */ + public function setPhpLimit($memory = null, $time_limit = 0, $ignore_user_abort = true) + { + if (null !== $memory) { + ini_set('memory_limit', $memory); + } + + ignore_user_abort(true); + set_time_limit($time_limit); + + return $this; + } + + /** + * Get the help information of the remote FTP server. + * + * @return array + */ + public function help() + { + return $this->ftp->raw('help'); + } + + /** + * Open a FTP connection. + * + * @param string $host + * @param bool $ssl + * @param int $port + * @param int $timeout + * + * @return FTPClient + * + * @throws FtpException If unable to connect + */ + public function connect($host, $ssl = false, $port = 21, $timeout = 90) + { + if ($ssl) { + $this->conn = @$this->ftp->ssl_connect($host, $port, $timeout); + } else { + $this->conn = @$this->ftp->connect($host, $port, $timeout); + } + + if (!$this->conn) { + throw new FtpException('Unable to connect'); + } + + return $this; + } + + /** + * Closes the current FTP connection. + * + * @return bool + */ + public function close() + { + if ($this->conn) { + $this->ftp->close(); + $this->conn = null; + } + } + + /** + * Get the connection with the server. + * + * @return resource + */ + public function getConnection() + { + return $this->conn; + } + + /** + * Get the wrapper. + * + * @return FtpWrapper + */ + public function getWrapper() + { + return $this->ftp; + } + + /** + * Logs in to an FTP connection. + * + * @param string $username + * @param string $password + * + * @return FtpClient + * + * @throws FtpException If the login is incorrect + */ + public function login($username = 'anonymous', $password = '') + { + $result = $this->ftp->login($username, $password); + + if ($result === false) { + throw new FtpException('Login incorrect'); + } + + return $this; + } + + /** + * Returns the last modified time of the given file. + * Return -1 on error. + * + * @param string $remoteFile + * @param string|null $format + * + * @return int + */ + public function modifiedTime($remoteFile, $format = null) + { + $time = $this->ftp->mdtm($remoteFile); + + if ($time !== -1 && $format !== null) { + return date($format, $time); + } + + return $time; + } + + /** + * Changes to the parent directory. + * + * @throws FtpException + * + * @return FtpClient + */ + public function up() + { + $result = @$this->ftp->cdup(); + + if ($result === false) { + throw new FtpException('Unable to get parent folder'); + } + + return $this; + } + + /** + * Returns a list of files in the given directory. + * + * @param string $directory The directory, by default is "." the current directory + * @param bool $recursive + * @param callable $filter A callable to filter the result, by default is asort() PHP function. + * The result is passed in array argument, + * must take the argument by reference ! + * The callable should proceed with the reference array + * because is the behavior of several PHP sorting + * functions (by reference ensure directly the compatibility + * with all PHP sorting functions). + * + * @return array + * + * @throws FtpException If unable to list the directory + */ + public function nlist($directory = '.', $recursive = false, $filter = 'sort') + { + if (!$this->isDir($directory)) { + throw new FtpException('"'.$directory.'" is not a directory'); + } + + $files = $this->ftp->nlist($directory); + + if ($files === false) { + throw new FtpException('Unable to list directory'); + } + + $result = []; + $dir_len = \strlen($directory); + + // if it's the current + if (false !== ($kdot = array_search('.', $files))) { + unset($files[$kdot]); + } + + // if it's the parent + if (false !== ($kdot = array_search('..', $files))) { + unset($files[$kdot]); + } + + if (!$recursive) { + foreach ($files as $file) { + $result[] = $directory.'/'.$file; + } + + // working with the reference (behavior of several PHP sorting functions) + $filter($result); + + return $result; + } + + // utils for recursion + $flatten = function (array $arr) use (&$flatten) { + $flat = []; + + foreach ($arr as $k => $v) { + if (\is_array($v)) { + $flat = array_merge($flat, $flatten($v)); + } else { + $flat[] = $v; + } + } + + return $flat; + }; + + foreach ($files as $file) { + $file = $directory.'/'.$file; + + // if contains the root path (behavior of the recursivity) + if (0 === strpos($file, $directory, $dir_len)) { + $file = substr($file, $dir_len); + } + + if ($this->isDir($file)) { + $result[] = $file; + $items = $flatten($this->nlist($file, true, $filter)); + + foreach ($items as $item) { + $result[] = $item; + } + } else { + $result[] = $file; + } + } + + $result = array_unique($result); + + $filter($result); + + return $result; + } + + /** + * Creates a directory. + * + * @see FtpClient::rmdir() + * @see FtpClient::remove() + * @see FtpClient::put() + * @see FtpClient::putAll() + * + * @param string $directory The directory + * @param bool $recursive + * + * @return array + */ + public function mkdir($directory, $recursive = false) + { + if (!$recursive || $this->isDir($directory)) { + return $this->ftp->mkdir($directory); + } + + $result = false; + $pwd = $this->ftp->pwd(); + $parts = explode('/', $directory); + + foreach ($parts as $part) { + if (!@$this->ftp->chdir($part)) { + $result = $this->ftp->mkdir($part); + $this->ftp->chdir($part); + } + } + + $this->ftp->chdir($pwd); + + return $result; + } + + /** + * Remove a directory. + * + * @see FtpClient::mkdir() + * @see FtpClient::cleanDir() + * @see FtpClient::remove() + * @see FtpClient::delete() + * + * @param string $directory + * @param bool $recursive Forces deletion if the directory is not empty + * + * @return bool + * + * @throws FtpException If unable to list the directory to remove + */ + public function rmdir($directory, $recursive = true) + { + if ($recursive) { + $files = $this->nlist($directory, false, 'rsort'); + + // remove children + foreach ($files as $file) { + $this->remove($file, true); + } + } + + // remove the directory + return $this->ftp->rmdir($directory); + } + + /** + * Empty directory. + * + * @see FtpClient::remove() + * @see FtpClient::delete() + * @see FtpClient::rmdir() + * + * @param string $directory + * + * @return bool + */ + public function cleanDir($directory) + { + if (!$files = $this->nlist($directory)) { + return $this->isEmpty($directory); + } + + // remove children + foreach ($files as $file) { + $this->remove($file, true); + } + + return $this->isEmpty($directory); + } + + /** + * Remove a file or a directory. + * + * @see FtpClient::rmdir() + * @see FtpClient::cleanDir() + * @see FtpClient::delete() + * + * @param string $path The path of the file or directory to remove + * @param bool $recursive Is effective only if $path is a directory, {@see FtpClient::rmdir()} + * + * @return bool + */ + public function remove($path, $recursive = false) + { + try { + if (@$this->ftp->delete($path) + || ($this->isDir($path) && @$this->rmdir($path, $recursive))) { + return true; + } + + return false; + } catch (\Exception $e) { + return false; + } + } + + /** + * Check if a directory exist. + * + * @param string $directory + * + * @return bool + * + * @throws FtpException + */ + public function isDir($directory) + { + $pwd = $this->ftp->pwd(); + + if ($pwd === false) { + throw new FtpException('Unable to resolve the current directory'); + } + + if (@$this->ftp->chdir($directory)) { + $this->ftp->chdir($pwd); + + return true; + } + + $this->ftp->chdir($pwd); + + return false; + } + + /** + * Check if a directory is empty. + * + * @param string $directory + * + * @return bool + */ + public function isEmpty($directory) + { + return $this->count($directory, null, false) === 0 ? true : false; + } + + /** + * Scan a directory and returns the details of each item. + * + * @see FtpClient::nlist() + * @see FtpClient::rawlist() + * @see FtpClient::parseRawList() + * @see FtpClient::dirSize() + * + * @param string $directory + * @param bool $recursive + * + * @return array + */ + public function scanDir($directory = '.', $recursive = false) + { + return $this->parseRawList($this->rawlist($directory, $recursive)); + } + + /** + * Returns the total size of the given directory in bytes. + * + * @param string $directory the directory, by default is the current directory + * @param bool $recursive true by default + * + * @return int the size in bytes + */ + public function dirSize($directory = '.', $recursive = true) + { + $items = $this->scanDir($directory, $recursive); + $size = 0; + + foreach ($items as $item) { + $size += (int) $item['size']; + } + + return $size; + } + + /** + * Count the items (file, directory, link, unknown). + * + * @param string $directory the directory, by default is the current directory + * @param string|null $type The type of item to count (file, directory, link, unknown) + * @param bool $recursive true by default + * + * @return int + */ + public function count($directory = '.', $type = null, $recursive = true) + { + $items = (null === $type ? $this->nlist($directory, $recursive) + : $this->scanDir($directory, $recursive)); + + $count = 0; + foreach ($items as $item) { + if (null === $type || $item['type'] == $type) { + ++$count; + } + } + + return $count; + } + + /** + * Uploads a file to the server from a string. + * + * @param string $remote_file + * @param string $content + * + * @return FtpClient + * + * @throws FtpException When the transfer fails + */ + public function putFromString($remote_file, $content) + { + $handle = fopen('php://temp', 'w'); + + fwrite($handle, $content); + rewind($handle); + + if ($this->ftp->fput($remote_file, $handle, \FTP_BINARY)) { + return $this; + } + + throw new FtpException('Unable to put the file "'.$remote_file.'"'); + } + + /** + * Uploads a file to the server. + * + * @param string $local_file + * + * @return FtpClient + * + * @throws FtpException When the transfer fails + */ + public function putFromPath($local_file) + { + $remote_file = basename($local_file); + $handle = fopen($local_file, 'r'); + + if ($this->ftp->fput($remote_file, $handle, \FTP_BINARY)) { + rewind($handle); + + return $this; + } + + throw new FtpException( + 'Unable to put the remote file from the local file "'.$local_file.'"' + ); + } + + /** + * Upload files. + * + * @param string $source_directory + * @param string $target_directory + * @param int $mode + * + * @return FtpClient + */ + public function putAll($source_directory, $target_directory, $mode = \FTP_BINARY) + { + $d = dir($source_directory); + + // do this for each file in the directory + while ($file = $d->read()) { + // to prevent an infinite loop + if ($file != '.' && $file != '..') { + // do the following if it is a directory + if (is_dir($source_directory.'/'.$file)) { + if (!$this->isDir($target_directory.'/'.$file)) { + // create directories that do not yet exist + $this->ftp->mkdir($target_directory.'/'.$file); + } + + // recursive part + $this->putAll( + $source_directory.'/'.$file, $target_directory.'/'.$file, + $mode + ); + } else { + // put the files + $this->ftp->put( + $target_directory.'/'.$file, $source_directory.'/'.$file, + $mode + ); + } + } + } + + return $this; + } + + /** + * Returns a detailed list of files in the given directory. + * + * @see FtpClient::nlist() + * @see FtpClient::scanDir() + * @see FtpClient::dirSize() + * + * @param string $directory The directory, by default is the current directory + * @param bool $recursive + * + * @return array + * + * @throws FtpException + */ + public function rawlist($directory = '.', $recursive = false) + { + if (!$this->isDir($directory)) { + throw new FtpException('"'.$directory.'" is not a directory.'); + } + + $list = $this->ftp->rawlist($directory); + $items = []; + + if (!$list) { + return $items; + } + + if (false == $recursive) { + foreach ($list as $path => $item) { + $chunks = preg_split("/\s+/", $item); + + // if not "name" + if (empty($chunks[8]) || $chunks[8] == '.' || $chunks[8] == '..') { + continue; + } + + $path = $directory.'/'.$chunks[8]; + + if (isset($chunks[9])) { + $nbChunks = \count($chunks); + + for ($i = 9; $i < $nbChunks; ++$i) { + $path .= ' '.$chunks[$i]; + } + } + + if (substr($path, 0, 2) == './') { + $path = substr($path, 2); + } + + $items[$this->rawToType($item).'#'.$path] = $item; + } + + return $items; + } + + $path = ''; + + foreach ($list as $item) { + $len = \strlen($item); + + if (!$len + // "." + || ($item[$len - 1] == '.' && $item[$len - 2] == ' ' + // ".." + || $item[$len - 1] == '.' && $item[$len - 2] == '.' && $item[$len - 3] == ' ') + ) { + continue; + } + + $chunks = preg_split("/\s+/", $item); + + // if not "name" + if (empty($chunks[8]) || $chunks[8] == '.' || $chunks[8] == '..') { + continue; + } + + $path = $directory.'/'.$chunks[8]; + + if (isset($chunks[9])) { + $nbChunks = \count($chunks); + + for ($i = 9; $i < $nbChunks; ++$i) { + $path .= ' '.$chunks[$i]; + } + } + + if (substr($path, 0, 2) == './') { + $path = substr($path, 2); + } + + $items[$this->rawToType($item).'#'.$path] = $item; + + if ($item[0] == 'd') { + $sublist = $this->rawlist($path, true); + + foreach ($sublist as $subpath => $subitem) { + $items[$subpath] = $subitem; + } + } + } + + return $items; + } + + /** + * Parse raw list. + * + * @see FtpClient::rawlist() + * @see FtpClient::scanDir() + * @see FtpClient::dirSize() + * + * @return array + */ + public function parseRawList(array $rawlist) + { + $items = []; + $path = ''; + + foreach ($rawlist as $key => $child) { + $chunks = preg_split("/\s+/", $child); + + if (isset($chunks[8]) && ($chunks[8] == '.' || $chunks[8] == '..')) { + continue; + } + + if (\count($chunks) === 1) { + $len = \strlen($chunks[0]); + + if ($len && $chunks[0][$len - 1] == ':') { + $path = substr($chunks[0], 0, -1); + } + + continue; + } + + $item = [ + 'permissions' => $chunks[0], + 'number' => $chunks[1], + 'owner' => $chunks[2], + 'group' => $chunks[3], + 'size' => $chunks[4], + 'month' => $chunks[5], + 'day' => $chunks[6], + 'time' => $chunks[7], + 'name' => $chunks[8], + 'type' => $this->rawToType($chunks[0]), + ]; + + unset($chunks[0]); + unset($chunks[1]); + unset($chunks[2]); + unset($chunks[3]); + unset($chunks[4]); + unset($chunks[5]); + unset($chunks[6]); + unset($chunks[7]); + $item['name'] = implode(' ', $chunks); + + if ($item['type'] == 'link') { + $item['target'] = $chunks[10]; // 9 is "->" + } + + // if the key is not the path, behavior of ftp_rawlist() PHP function + if (\is_int($key) || false === strpos($key, $item['name'])) { + array_splice($chunks, 0, 8); + + $key = $item['type'].'#' + .($path ? $path.'/' : '') + .implode(' ', $chunks); + + if ($item['type'] == 'link') { + // get the first part of 'link#the-link.ext -> /path/of/the/source.ext' + $exp = explode(' ->', $key); + $key = rtrim($exp[0]); + } + + $items[$key] = $item; + } else { + // the key is the path, behavior of FtpClient::rawlist() method() + $items[$key] = $item; + } + } + + return $items; + } + + /** + * Convert raw info (drwx---r-x ...) to type (file, directory, link, unknown). + * Only the first char is used for resolving. + * + * @param string $permission Example : drwx---r-x + * + * @return string The file type (file, directory, link, unknown) + * + * @throws FtpException + */ + public function rawToType($permission) + { + if (!\is_string($permission)) { + throw new FtpException('The "$permission" argument must be a string, "' + .\gettype($permission).'" given.'); + } + + if (empty($permission[0])) { + return 'unknown'; + } + + switch ($permission[0]) { + case '-': + return 'file'; + case 'd': + return 'directory'; + case 'l': + return 'link'; + default: + return 'unknown'; + } + } + + /** + * Set the wrapper which forward the PHP FTP functions to use in FtpClient instance. + * + * @return FtpClient + */ + protected function setWrapper(FtpWrapper $wrapper) + { + $this->ftp = $wrapper; + + return $this; + } +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpException.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpException.php new file mode 100644 index 0000000..6311665 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FtpClient; + +/** + * The FtpException class. + * Exception thrown if an error on runtime of the FTP client occurs. + * {@inheritDoc} + * + * @author Nicolas Tallefourtane + */ +class FtpException extends \Exception +{ +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpWrapper.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpWrapper.php new file mode 100644 index 0000000..e8de4a0 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/FtpWrapper.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FtpClient; + +/** + * Wrap the PHP FTP functions. + * + * @method bool alloc() alloc(int $filesize, string &$result = null) Allocates space for a file to be uploaded + * @method bool cdup() cdup() Changes to the parent directory + * @method bool chdir() chdir(string $directory) Changes the current directory on a FTP server + * @method int chmod() chmod(int $mode, string $filename) Set permissions on a file via FTP + * @method bool close() close() Closes an FTP connection + * @method bool delete() delete(string $path) Deletes a file on the FTP server + * @method bool exec() exec(string $command) Requests execution of a command on the FTP server + * @method bool fget() fget(resource $handle, string $remote_file, int $mode, int $resumepos = 0) Downloads a file from the FTP server and saves to an open file + * @method bool fput() fput(string $remote_file, resource $handle, int $mode, int $startpos = 0) Uploads from an open file to the FTP server + * @method mixed get_option() get_option(int $option) Retrieves various runtime behaviours of the current FTP stream + * @method bool get() get(string $local_file, string $remote_file, int $mode, int $resumepos = 0) Downloads a file from the FTP server + * @method bool login() login(string $username, string $password) Logs in to an FTP connection + * @method int mdtm() mdtm(string $remote_file) Returns the last modified time of the given file + * @method string mkdir() mkdir(string $directory) Creates a directory + * @method int nb_continue() nb_continue() Continues retrieving/sending a file (non-blocking) + * @method int nb_fget() nb_fget(resource $handle, string $remote_file, int $mode, int $resumepos = 0) Retrieves a file from the FTP server and writes it to an open file (non-blocking) + * @method int nb_fput() nb_fput(string $remote_file, resource $handle, int $mode, int $startpos = 0) Stores a file from an open file to the FTP server (non-blocking) + * @method int nb_get() nb_get(string $local_file, string $remote_file, int $mode, int $resumepos = 0) Retrieves a file from the FTP server and writes it to a local file (non-blocking) + * @method int nb_put() nb_put(string $remote_file, string $local_file, int $mode, int $startpos = 0) Stores a file on the FTP server (non-blocking) + * @method array nlist() nlist(string $directory) Returns a list of files in the given directory + * @method bool pasv() pasv(bool $pasv) Turns passive mode on or off + * @method bool put() put(string $remote_file, string $local_file, int $mode, int $startpos = 0) Uploads a file to the FTP server + * @method string pwd() pwd() Returns the current directory name + * @method bool quit() quit() Closes an FTP connection + * @method array raw() raw(string $command) Sends an arbitrary command to an FTP server + * @method array rawlist() rawlist(string $directory, bool $recursive = false) Returns a detailed list of files in the given directory + * @method bool rename() rename(string $oldname, string $newname) Renames a file or a directory on the FTP server + * @method bool rmdir() rmdir(string $directory) Removes a directory + * @method bool set_option() set_option(int $option, mixed $value) Set miscellaneous runtime FTP options + * @method bool site() site(string $command) Sends a SITE command to the server + * @method int size() size(string $remote_file) Returns the size of the given file + * @method string systype() systype() Returns the system type identifier of the remote FTP server + * + * @author Nicolas Tallefourtane + */ +class FtpWrapper +{ + /** + * The connection with the server. + * + * @var resource + */ + protected $conn; + + /** + * Constructor. + * + * @param resource &$connection The FTP (or SSL-FTP) connection (takes by reference) + */ + public function __construct(&$connection) + { + $this->conn = &$connection; + } + + /** + * Forward the method call to FTP functions. + * + * @param string $function + * + * @throws FtpException When the function is not valid + */ + public function __call($function, array $arguments) + { + $function = 'ftp_'.$function; + + if (\function_exists($function)) { + array_unshift($arguments, $this->conn); + + return \call_user_func_array($function, $arguments); + } + + throw new FtpException("{$function} is not a valid FTP function"); + } + + /** + * Opens a FTP connection. + * + * @param string $host + * @param int $port + * @param int $timeout + * + * @return resource + */ + public function connect($host, $port = 21, $timeout = 90) + { + return ftp_connect($host, $port, $timeout); + } + + /** + * Opens a Secure SSL-FTP connection. + * + * @param string $host + * @param int $port + * @param int $timeout + * + * @return resource + */ + public function ssl_connect($host, $port = 21, $timeout = 90) + { + return ftp_ssl_connect($host, $port, $timeout); + } +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/Response.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/Response.php new file mode 100644 index 0000000..5adea55 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/Response.php @@ -0,0 +1,364 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Class Response + * Simplified copy of Symfony/Http-Foundation Response + * to allow compatibility with frameworks. + */ +class Response +{ + public const HTTP_CONTINUE = 100; + public const HTTP_SWITCHING_PROTOCOLS = 101; + public const HTTP_PROCESSING = 102; // RFC2518 + public const HTTP_OK = 200; + public const HTTP_CREATED = 201; + public const HTTP_ACCEPTED = 202; + public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203; + public const HTTP_NO_CONTENT = 204; + public const HTTP_RESET_CONTENT = 205; + public const HTTP_PARTIAL_CONTENT = 206; + public const HTTP_MULTI_STATUS = 207; // RFC4918 + public const HTTP_ALREADY_REPORTED = 208; // RFC5842 + public const HTTP_IM_USED = 226; // RFC3229 + public const HTTP_MULTIPLE_CHOICES = 300; + public const HTTP_MOVED_PERMANENTLY = 301; + public const HTTP_FOUND = 302; + public const HTTP_SEE_OTHER = 303; + public const HTTP_NOT_MODIFIED = 304; + public const HTTP_USE_PROXY = 305; + public const HTTP_RESERVED = 306; + public const HTTP_TEMPORARY_REDIRECT = 307; + public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238 + public const HTTP_BAD_REQUEST = 400; + public const HTTP_UNAUTHORIZED = 401; + public const HTTP_PAYMENT_REQUIRED = 402; + public const HTTP_FORBIDDEN = 403; + public const HTTP_NOT_FOUND = 404; + public const HTTP_METHOD_NOT_ALLOWED = 405; + public const HTTP_NOT_ACCEPTABLE = 406; + public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; + public const HTTP_REQUEST_TIMEOUT = 408; + public const HTTP_CONFLICT = 409; + public const HTTP_GONE = 410; + public const HTTP_LENGTH_REQUIRED = 411; + public const HTTP_PRECONDITION_FAILED = 412; + public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413; + public const HTTP_REQUEST_URI_TOO_LONG = 414; + public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415; + public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + public const HTTP_EXPECTATION_FAILED = 417; + public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324 + public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918 + public const HTTP_LOCKED = 423; // RFC4918 + public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918 + public const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817 + public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817 + public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585 + public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585 + public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585 + public const HTTP_INTERNAL_SERVER_ERROR = 500; + public const HTTP_NOT_IMPLEMENTED = 501; + public const HTTP_BAD_GATEWAY = 502; + public const HTTP_SERVICE_UNAVAILABLE = 503; + public const HTTP_GATEWAY_TIMEOUT = 504; + public const HTTP_VERSION_NOT_SUPPORTED = 505; + public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295 + public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918 + public const HTTP_LOOP_DETECTED = 508; // RFC5842 + public const HTTP_NOT_EXTENDED = 510; // RFC2774 + public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585 + + /** + * Status codes translation table. + * + * The list of codes is complete according to the + * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry} + * (last updated 2012-02-13). + * + * Unless otherwise noted, the status code is defined in RFC2616. + * + * @var array + */ + public static $statusTexts = [ + 100 => 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', // RFC2518 + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', // RFC4918 + 208 => 'Already Reported', // RFC5842 + 226 => 'IM Used', // RFC3229 + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', // RFC7238 + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 418 => 'I\'m a teapot', // RFC2324 + 422 => 'Unprocessable Entity', // RFC4918 + 423 => 'Locked', // RFC4918 + 424 => 'Failed Dependency', // RFC4918 + 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817 + 426 => 'Upgrade Required', // RFC2817 + 428 => 'Precondition Required', // RFC6585 + 429 => 'Too Many Requests', // RFC6585 + 431 => 'Request Header Fields Too Large', // RFC6585 + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', // RFC2295 + 507 => 'Insufficient Storage', // RFC4918 + 508 => 'Loop Detected', // RFC5842 + 510 => 'Not Extended', // RFC2774 + 511 => 'Network Authentication Required', // RFC6585 + ]; + + /** + * @var string + */ + protected $content; + + /** + * @var int + */ + protected $statusCode; + + /** + * @var string + */ + protected $statusText; + + /** + * @var array + */ + public $headers; + + /** + * @var string + */ + protected $version; + + /** + * Construct the response. + * + * @param int $statusCode + * @param array $headers + */ + public function __construct($content = '', $statusCode = 200, $headers = []) + { + $this->setContent($content); + $this->setStatusCode($statusCode); + $this->headers = $headers; + $this->version = '1.1'; + } + + /** + * Set the content on the response. + * + * @return $this + */ + public function setContent($content) + { + if ($content instanceof ArrayObject || is_array($content)) { + $this->headers['Content-Type'] = ['application/json']; + + $content = json_encode($content); + } + + $this->content = $content; + } + + /** + * Returns the Response as an HTTP string. + * + * The string representation of the Response is the same as the + * one that will be sent to the client only if the prepare() method + * has been called before. + * + * @return string The Response as an HTTP string + * + * @see prepare() + */ + public function __toString() + { + return + sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". + $this->headers."\r\n". + $this->getContent(); + } + + /** + * Sets the response status code. + * + * @param int $code HTTP status code + * @param mixed $text HTTP status text + * + * If the status text is null it will be automatically populated for the known + * status codes and left empty otherwise + * + * @return Response + * + * @throws \InvalidArgumentException When the HTTP status code is not valid + * + * @api + */ + public function setStatusCode($code, $text = null) + { + $this->statusCode = $code = (int) $code; + if ($this->isInvalid()) { + throw new InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); + } + + if (null === $text) { + $this->statusText = self::$statusTexts[$code] ?? ''; + + return $this; + } + + if (false === $text) { + $this->statusText = ''; + + return $this; + } + + $this->statusText = $text; + + return $this; + } + + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + + /** + * Is response invalid? + * + * @return bool + * + * @api + */ + public function isInvalid() + { + return $this->statusCode < 100 || $this->statusCode >= 600; + } + + /** + * Set a header on the Response. + * + * @param string $key + * @param string $value + * @param bool $replace + * + * @return $this + */ + public function header($key, $value, $replace = true) + { + if (empty($this->headers[$key])) { + $this->headers[$key] = []; + } + if ($replace) { + $this->headers[$key] = [$value]; + } else { + $this->headers[$key][] = $value; + } + + return $this; + } + + /** + * Sends HTTP headers and content. + * + * @return Response + * + * @api + */ + public function send() + { + $this->sendHeaders(); + $this->sendContent(); + + if (function_exists('fastcgi_finish_request')) { + fastcgi_finish_request(); + } + + return $this; + } + + /** + * Sends content for the current web response. + * + * @return Response + */ + public function sendContent() + { + echo $this->content; + + return $this; + } + + /** + * Sends HTTP headers. + * + * @return Response + */ + public function sendHeaders() + { + // headers have already been sent by the developer + if (headers_sent()) { + return $this; + } + + // status + header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); + + // headers + foreach ($this->headers as $name => $values) { + if (is_array($values)) { + foreach ($values as $value) { + header($name.': '.$value, false, $this->statusCode); + } + } else { + header($name.': '.$values, false, $this->statusCode); + } + } + + return $this; + } +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/ftp_class.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/ftp_class.php new file mode 100755 index 0000000..e760cf7 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/ftp_class.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class ftp_class +{ + // *** Class variables + private $connectionId; + private $loginOk = false; + private $messageArray = []; + + public function __construct() + { + } + + private function logMessage($message): void + { + $this->messageArray[] = $message; + } + + public function getMessages() + { + return $this->messageArray; + } + + public function connect($server, $ftpUser, $ftpPassword, $isPassive = false) + { + // *** Set up basic connection + $this->connectionId = ftp_connect($server); + + // *** Login with username and password + $loginResult = ftp_login($this->connectionId, $ftpUser, $ftpPassword); + + // *** Sets passive mode on/off (default off) + ftp_pasv($this->connectionId, $isPassive); + + // *** Check connection + if ((!$this->connectionId) || (!$loginResult)) { + $this->logMessage('FTP connection has failed!'); + $this->logMessage('Attempted to connect to '.$server.' for user '.$ftpUser, true); + + return false; + } + $this->logMessage('Connected to '.$server.', for user '.$ftpUser); + $this->loginOk = true; + + return true; + } + + public function makeDir($directory) + { + // *** If creating a directory is successful... + if (ftp_mkdir($this->connectionId, $directory)) { + $this->logMessage('Directory "'.$directory.'" created successfully'); + + return true; + } + + // *** ...Else, FAIL. + $this->logMessage('Failed creating directory "'.$directory.'"'); + + return false; + } + + public function changeDir($directory) + { + if (ftp_chdir($this->connectionId, $directory)) { + $this->logMessage('Current directory is now: '.ftp_pwd($this->connectionId)); + + return true; + } + $this->logMessage('Couldn\'t change directory'); + + return false; + } + + public function getDirListing($directory = '.', $parameters = '-la') + { + echo shell_exec('whoami').' is who i am
'; + echo 'Current directory is now: '.ftp_pwd($this->connectionId).'
'; + + // get contents of the current directory + $contentsArray = ftp_rawlist($this->connectionId, $parameters.' '.$directory); + echo error_get_last(); + + return $contentsArray; + } +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/mime_type_lib.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/mime_type_lib.php new file mode 100755 index 0000000..d1e1984 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/mime_type_lib.php @@ -0,0 +1,323 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* REMOVE ME TO TEST +echo "magicfile: " . ini_get( 'mime_magic.magicfile' ) . "\n"; + +if ( function_exists( 'finfo_open' ) ) + echo "Found finfo_open function\n"; +else + echo "Did not find finfo_open function\n"; + +if ( function_exists( 'mime_content_type' ) ) + echo "Found mime_content_type function\n"; +else + echo "Did not find mime_content_type function\n"; +REMOVE ME TO TEST */ + +$mime_types = [ + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'asc' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'asx' => 'video/x-ms-asf', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'bcpio' => 'application/x-bcpio', + 'bin' => 'application/octet-stream', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bzip2', + 'cdf' => 'application/x-netcdf', + 'chrt' => 'application/x-kchart', + 'class' => 'application/octet-stream', + 'cpio' => 'application/x-cpio', + 'cpt' => 'application/mac-compactpro', + 'csh' => 'application/x-csh', + 'css' => 'text/css', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dvi' => 'application/x-dvi', + 'dwg' => 'image/vnd.dwg', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', + 'etx' => 'text/x-setext', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', + 'flv' => 'video/x-flv', + 'gif' => 'image/gif', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'hdf' => 'application/x-hdf', + 'hqx' => 'application/mac-binhex40', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ice' => 'x-conference/x-cooltalk', + 'ief' => 'image/ief', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'img' => 'application/octet-stream', + 'iso' => 'application/octet-stream', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jar' => 'application/x-java-archive', + 'jnlp' => 'application/x-java-jnlp-file', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'js' => 'application/x-javascript', + 'kar' => 'audio/midi', + 'kil' => 'application/x-killustrator', + 'kpr' => 'application/x-kpresenter', + 'kpt' => 'application/x-kpresenter', + 'ksp' => 'application/x-kspread', + 'kwd' => 'application/x-kword', + 'kwt' => 'application/x-kword', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'latex' => 'application/x-latex', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'm3u' => 'audio/x-mpegurl', + 'man' => 'application/x-troff-man', + 'me' => 'application/x-troff-me', + 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'ms' => 'application/x-troff-ms', + 'msh' => 'model/mesh', + 'mxu' => 'video/vnd.mpegurl', + 'nc' => 'application/x-netcdf', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ogg' => 'application/ogg', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'pbm' => 'image/x-portable-bitmap', + 'pdb' => 'chemical/x-pdb', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'php' => 'text/x-php', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'ra' => 'audio/x-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'ras' => 'image/x-cmu-raster', + 'rgb' => 'image/x-rgb', + 'rm' => 'audio/x-pn-realaudio', + 'roff' => 'application/x-troff', + 'rpm' => 'application/x-rpm', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'skd' => 'application/x-koan', + 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', + 'skt' => 'application/x-koan', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'snd' => 'audio/basic', + 'svg' => 'image/svg+xml', + 'so' => 'application/octet-stream', + 'spl' => 'application/x-futuresplash', + 'src' => 'application/x-wais-source', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'swf' => 'application/x-shockwave-flash', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'application/x-troff', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'tgz' => 'application/x-gzip', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'torrent' => 'application/x-bittorrent', + 'tr' => 'application/x-troff', + 'tsv' => 'text/tab-separated-values', + 'txt' => 'text/plain', + 'ustar' => 'application/x-ustar', + 'vcd' => 'application/x-cdlink', + 'vrml' => 'model/vrml', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wrl' => 'model/vrml', + 'wvx' => 'video/x-ms-wvx', + 'xbm' => 'image/x-xbitmap', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xml' => 'text/xml', + 'xml' => 'application/xml', + 'xpm' => 'image/x-xpixmap', + 'xsl' => 'text/xsl', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'zip' => 'application/zip', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', +]; + +if (!function_exists('get_extension_from_mime')) { + function get_extension_from_mime($mime) + { + global $mime_types; + if (strpos($mime, ';') !== false) { + $mime = substr($mime, 0, strpos($mime, ';')); + } + $mime_types_conv = array_flip($mime_types); + if (isset($mime_types_conv[$mime])) { + return $mime_types_conv[$mime]; + } + + return ''; + } +} + +if (!function_exists('get_file_mime_type')) { + function get_file_mime_type($filename, $debug = false) + { + if (function_exists('finfo_open') && function_exists('finfo_file') && function_exists('finfo_close')) { + $fileinfo = finfo_open(\FILEINFO_MIME_TYPE); + $mime_type = finfo_file($fileinfo, $filename); + finfo_close($fileinfo); + + if (!empty($mime_type)) { + if (true === $debug) { + return ['mime_type' => $mime_type, 'method' => 'fileinfo']; + } + + return $mime_type; + } + } + + if (function_exists('mime_content_type')) { + $mime_type = mime_content_type($filename); + + if (!empty($mime_type)) { + if (true === $debug) { + return ['mime_type' => $mime_type, 'method' => 'mime_content_type']; + } + + return $mime_type; + } + } + + global $mime_types; + + $tmp_array = explode('.', $filename); + $ext = strtolower(array_pop($tmp_array)); + + if (!empty($mime_types[$ext])) { + if (true === $debug) { + return ['mime_type' => $mime_types[$ext], 'method' => 'from_array']; + } + + return $mime_types[$ext]; + } + + if (true === $debug) { + return ['mime_type' => 'application/octet-stream', 'method' => 'last_resort']; + } + + return 'application/octet-stream'; + } +} + +/******************** + * The following code can be used to test the function. + * First put a plain text file named "test.txt" and a + * JPEG image file named "image.jpg" in the same folder + * as this file. + * + * Simply remove the "REMOVE ME TO TEST" lines below to have + * the code run when this file runs. + * + * Run the code with this command: + * php mime_type_lib.php + ********************/ + +/* REMOVE ME TO TEST +echo get_file_mime_type( 'test.txt' ) . "\n"; +echo print_r( get_file_mime_type( 'image.jpg', true ), true ) . "\n"; +REMOVE ME TO TEST */ diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/php_image_magician.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/php_image_magician.php new file mode 100755 index 0000000..8288e23 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/php_image_magician.php @@ -0,0 +1,3273 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// +// This work is licensed under the Creative Commons Attribution 3.0 Unported +// License. To view a copy of this license, +// visit http://creativecommons.org/licenses/by/3.0/ or send a letter to +// Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, +// 94041, USA. +// +// All rights reserved. +// +// Author: Jarrod Oberto +// Version: 1.5.1 +// Date: 10-05-11 +// Purpose: Provide tools for image manipulation using GD +// Param In: See functions. +// Param Out: Produces a resized image +// Requires : Requires PHP GD library. +// Usage Example: +// include("lib/php_image_magician.php"); +// $magicianObj = new resize('images/car.jpg'); +// $magicianObj -> resizeImage(150, 100, 0); +// $magicianObj -> saveImage('images/car_small.jpg', 100); +// +// - See end of doc for more examples - +// +// Supported file types include: jpg, png, gif, bmp, psd (read) +// +// +// +// The following functions are taken from phpThumb() [available from +// http://phpthumb.sourceforge.net], and are used with written permission +// from James Heinrich. +// - GD2BMPstring +// - GetPixelColor +// - LittleEndian2String +// +// The following functions are from Marc Hibbins and are used with written +// permission (are also under the Attribution-ShareAlike +// [http://creativecommons.org/licenses/by-sa/3.0/] license. +// - +// +// PhpPsdReader is used with written permission from Tim de Koning. +// [http://www.kingsquare.nl/phppsdreader] +// +// +// +// Modificatoin history +// Date Initials Ver Description +// 10-05-11 J.C.O 0.0 Initial build +// 01-06-11 J.C.O 0.1.1 * Added reflections +// * Added Rounded corners +// * You can now use PNG interlacing +// * Added shadow +// * Added caption box +// * Added vintage filter +// * Added dynamic image resizing (resize on the fly) +// * minor bug fixes +// 05-06-11 J.C.O 0.1.1.1 * Fixed undefined variables +// 17-06-11 J.C.O 0.1.2 * Added image_batch_class.php class +// * Minor bug fixes +// 26-07-11 J.C.O 0.1.4 * Added support for external images +// * Can now set the crop poisition +// 03-08-11 J.C.O 0.1.5 * Added reset() method to reset resource to +// original input file. +// * Added method addTextToCaptionBox() to +// simplify adding text to a caption box. +// * Added experimental writeIPTC. (not finished) +// * Added experimental readIPTC. (not finished) +// 11-08-11 J.C.O * Added initial border presets. +// 30-08-11 J.C.O * Added 'auto' crop option to crop portrait +// images near the top. +// 08-09-11 J.C.O * Added cropImage() method to allow standalone +// cropping. +// 17-09-11 J.C.O * Added setCropFromTop() set method - set the +// percentage to crop from the top when using +// crop 'auto' option. +// * Added setTransparency() set method - allows you +// to turn transparency off (like when saving +// as a jpg). +// * Added setFillColor() set method - set the +// background color to use instead of transparency. +// 05-11-11 J.C.O 0.1.5.1 * Fixed interlacing option +// 0-07-12 J.C.O 1.0 +// +// Known issues & Limitations: +// ------------------------------- +// Not so much an issue, the image is destroyed on the deconstruct rather than +// when we have finished with it. The reason for this is that we don't know +// when we're finished with it as you can both save the image and display +// it directly to the screen (imagedestroy($this->imageResized)) +// +// Opening BMP files is slow. A test with 884 bmp files processed in a loop +// takes forever - over 5 min. This test inlcuded opening the file, then +// getting and displaying its width and height. +// +// $forceStretch: +// ------------------------------- +// On by default. +// $forceStretch can be disabled by calling method setForceStretch with false +// parameter. If disabled, if an images original size is smaller than the size +// specified by the user, the original size will be used. This is useful when +// dealing with small images. +// +// If enabled, images smaller than the size specified will be stretched to +// that size. +// +// Tips: +// ------------------------------- +// * If you're resizing a transparent png and saving it as a jpg, set +// $keepTransparency to false with: $magicianObj->setTransparency(false); +// +// FEATURES: +// * EASY TO USE +// * BMP SUPPORT (read & write) +// * PSD (photoshop) support (read) +// * RESIZE IMAGES +// - Preserve transparency (png, gif) +// - Apply sharpening (jpg) (requires PHP >= 5.1.0) +// - Set image quality (jpg, png) +// - Resize modes: +// - exact size +// - resize by width (auto height) +// - resize by height (auto width) +// - auto (automatically determine the best of the above modes to use) +// - crop - resize as best as it can then crop the rest +// - Force stretching of smaller images (upscale) +// * APPLY FILTERS +// - Convert to grey scale +// - Convert to black and white +// - Convert to sepia +// - Convert to negative +// * ROTATE IMAGES +// - Rotate using predefined "left", "right", or "180"; or any custom degree amount +// * EXTRACT EXIF DATA (requires exif module) +// - make +// - model +// - date +// - exposure +// - aperture +// - f-stop +// - iso +// - focal length +// - exposure program +// - metering mode +// - flash status +// - creator +// - copyright +// * ADD WATERMARK +// - Specify exact x, y placement +// - Or, specify using one of the 9 pre-defined placements such as "tl" +// (for top left), "m" (for middle), "br" (for bottom right) +// - also specify padding from edge amount (optional). +// - Set opacity of watermark (png). +// * ADD BORDER +// * USE HEX WHEN SPECIFYING COLORS (eg: #ffffff) +// * SAVE IMAGE OR OUTPUT TO SCREEN +// +// +// ========================================================================# + +class php_image_magician +{ + private $fileName; + private $image; + protected $imageResized; + private $widthOriginal; // Always be the original width + private $heightOriginal; + private $width; // Current width (width after resize) + private $height; + private $imageSize; + private $fileExtension; + + private $debug = true; + private $errorArray = []; + + private $forceStretch = true; + private $aggresiveSharpening = false; + + private $transparentArray = ['.png', '.gif']; + private $keepTransparency = true; + private $fillColorArray = ['r' => 255, 'g' => 255, 'b' => 255]; + + private $sharpenArray = ['jpg']; + + private $psdReaderPath; + private $filterOverlayPath; + + private $isInterlace; + + private $captionBoxPositionArray = []; + + private $fontDir = 'fonts'; + + private $cropFromTopPercent = 10; + + // # -------------------------------------------------------- + + public function __construct($fileName) + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Constructor + // Param in: $fileName: File name and path. + // Param out: n/a + // Reference: + // Notes: + // + { + if (!$this->testGDInstalled()) { + if ($this->debug) { + throw new Exception('The GD Library is not installed.'); + } + + throw new Exception(); + } + + $this->initialise(); + + // *** Save the image file name. Only store this incase you want to display it + $this->fileName = $fileName; + $this->fileExtension = fix_strtolower(strrchr($fileName, '.')); + + // *** Open up the file + $this->image = $this->openImage($fileName); + + // *** Assign here so we don't modify the original + $this->imageResized = $this->image; + + // *** If file is an image + if ($this->testIsImage($this->image)) { + // *** Get width and height + $this->width = imagesx($this->image); + $this->widthOriginal = imagesx($this->image); + $this->height = imagesy($this->image); + $this->heightOriginal = imagesy($this->image); + + /* Added 15-09-08 + * Get the filesize using this build in method. + * Stores an array of size + * + * $this->imageSize[1] = width + * $this->imageSize[2] = height + * $this->imageSize[3] = width x height + * + */ + $this->imageSize = getimagesize($this->fileName); + } else { + $this->errorArray[] = 'File is not an image'; + } + } + + // # -------------------------------------------------------- + + private function initialise(): void + { + $this->psdReaderPath = __DIR__.'/classPhpPsdReader.php'; + $this->filterOverlayPath = __DIR__.'/filters'; + + // *** Set if image should be interlaced or not. + $this->isInterlace = false; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Resize +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function resizeImage($newWidth, $newHeight, $option = 0, $sharpen = false, $autoRotate = false): void + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Resizes the image + // Param in: $newWidth: + // $newHeight: + // $option: 0 / exact = defined size; + // 1 / portrait = keep aspect set height; + // 2 / landscape = keep aspect set width; + // 3 / auto = auto; + // 4 / crop= resize and crop; + // + // $option can also be an array containing options for + // cropping. E.G., array('crop', 'r') + // + // This array only applies to 'crop' and the 'r' refers to + // "crop right". Other value include; tl, t, tr, l, m (default), + // r, bl, b, br, or you can specify your own co-ords (which + // isn't recommended. + // + // $sharpen: true: sharpen (jpg only); + // false: don't sharpen + // Param out: n/a + // Reference: + // Notes: To clarify the $option input: + // 0 = The exact height and width dimensions you set. + // 1 = Whatever height is passed in will be the height that + // is set. The width will be calculated and set automatically + // to a the value that keeps the original aspect ratio. + // 2 = The same but based on the width. We try make the image the + // biggest size we can while stil fitting inside the box size + // 3 = Depending whether the image is landscape or portrait, this + // will automatically determine whether to resize via + // dimension 1,2 or 0 + // 4 = Will resize and then crop the image for best fit + // + // forceStretch can be applied to options 1,2,3 and 4 + // + { + // *** We can pass in an array of options to change the crop position + $cropPos = 'm'; + if (is_array($option) && fix_strtolower($option[0]) == 'crop') { + $cropPos = $option[1]; // get the crop option + } else { + if (strpos($option, '-') !== false) { + // *** Or pass in a hyphen seperated option + $optionPiecesArray = explode('-', $option); + $cropPos = end($optionPiecesArray); + } + } + + // *** Check the option is valid + $option = $this->prepOption($option); + + // *** Make sure the file passed in is valid + if (!$this->image) { + if ($this->debug) { + throw new Exception('file '.$this->getFileName().' is missing or invalid'); + } + + throw new Exception(); + } + + // *** Get optimal width and height - based on $option + $dimensionsArray = $this->getDimensions($newWidth, $newHeight, $option); + + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + + // *** Resample - create image canvas of x, y size + $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight); + $this->keepTransparancy($optimalWidth, $optimalHeight, $this->imageResized); + imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height); + + // *** If '4', then crop too + if ($option == 4 || $option == 'crop') { + if ($optimalWidth >= $newWidth && $optimalHeight >= $newHeight) { + $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos); + } + } + + // *** If Rotate. + if ($autoRotate) { + $exifData = $this->getExif(false); + if (count($exifData) > 0) { + switch ($exifData['orientation']) { + case 8: + $this->imageResized = imagerotate($this->imageResized, 90, 0); + break; + case 3: + $this->imageResized = imagerotate($this->imageResized, 180, 0); + break; + case 6: + $this->imageResized = imagerotate($this->imageResized, -90, 0); + break; + } + } + } + + // *** Sharpen image (if jpg and the user wishes to do so) + if ($sharpen && in_array($this->fileExtension, $this->sharpenArray)) { + // *** Sharpen + $this->sharpen(); + } + } + + // # -------------------------------------------------------- + + public function cropImage($newWidth, $newHeight, $cropPos = 'm'): void + // Author: Jarrod Oberto + // Date: 08-09-11 + // Purpose: Crops the image + // Param in: $newWidth: crop with + // $newHeight: crop height + // $cropPos: Can be any of the following: + // tl, t, tr, l, m, r, bl, b, br, auto + // Or: + // a custom position such as '30x50' + // Param out: n/a + // Reference: + // Notes: + // + { + // *** Make sure the file passed in is valid + if (!$this->image) { + if ($this->debug) { + throw new Exception('file '.$this->getFileName().' is missing or invalid'); + } + + throw new Exception(); + } + + $this->imageResized = $this->image; + $this->crop($this->width, $this->height, $newWidth, $newHeight, $cropPos); + } + + // # -------------------------------------------------------- + + private function keepTransparancy($width, $height, $im): void + // Author: Jarrod Oberto + // Date: 08-04-11 + // Purpose: Keep transparency for png and gif image + // Param in: + // Param out: n/a + // Reference: + // Notes: + // + { + // *** If PNG, perform some transparency retention actions (gif untested) + if (in_array($this->fileExtension, $this->transparentArray) && $this->keepTransparency) { + imagealphablending($im, false); + imagesavealpha($im, true); + $transparent = imagecolorallocatealpha($im, 255, 255, 255, 127); + imagefilledrectangle($im, 0, 0, $width, $height, $transparent); + } else { + $color = imagecolorallocate($im, $this->fillColorArray['r'], $this->fillColorArray['g'], $this->fillColorArray['b']); + imagefilledrectangle($im, 0, 0, $width, $height, $color); + } + } + + // # -------------------------------------------------------- + + private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos): void + // Author: Jarrod Oberto + // Date: 15-09-08 + // Purpose: Crops the image + // Param in: $newWidth: + // $newHeight: + // Param out: n/a + // Reference: + // Notes: + // + { + // *** Get cropping co-ordinates + $cropArray = $this->getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $cropPos); + $cropStartX = $cropArray['x']; + $cropStartY = $cropArray['y']; + + // *** Crop this bad boy + $crop = imagecreatetruecolor($newWidth, $newHeight); + $this->keepTransparancy($optimalWidth, $optimalHeight, $crop); + imagecopyresampled($crop, $this->imageResized, 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight, $newWidth, $newHeight); + + $this->imageResized = $crop; + + // *** Set new width and height to our variables + $this->width = $newWidth; + $this->height = $newHeight; + } + + // # -------------------------------------------------------- + + private function getCropPlacing($optimalWidth, $optimalHeight, $newWidth, $newHeight, $pos = 'm') + // + // Author: Jarrod Oberto + // Date: July 11 + // Purpose: Set the cropping area. + // Params in: + // Params out: (array) the crop x and y co-ordinates. + // Notes: When specifying the exact pixel crop position (eg 10x15), be + // very careful as it's easy to crop out of the image leaving + // black borders. + // + { + $pos = fix_strtolower($pos); + + // *** If co-ords have been entered + if (strstr($pos, 'x')) { + $pos = str_replace(' ', '', $pos); + + $xyArray = explode('x', $pos); + [$cropStartX, $cropStartY] = $xyArray; + } else { + switch ($pos) { + case 'tl': + $cropStartX = 0; + $cropStartY = 0; + break; + case 't': + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = 0; + break; + case 'tr': + $cropStartX = $optimalWidth - $newWidth; + $cropStartY = 0; + break; + case 'l': + $cropStartX = 0; + $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); + break; + case 'm': + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); + break; + case 'r': + $cropStartX = $optimalWidth - $newWidth; + $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); + break; + case 'bl': + $cropStartX = 0; + $cropStartY = $optimalHeight - $newHeight; + break; + case 'b': + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = $optimalHeight - $newHeight; + break; + case 'br': + $cropStartX = $optimalWidth - $newWidth; + $cropStartY = $optimalHeight - $newHeight; + break; + case 'auto': + // *** If image is a portrait crop from top, not center. v1.5 + if ($optimalHeight > $optimalWidth) { + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = ($this->cropFromTopPercent / 100) * $optimalHeight; + } else { + // *** Else crop from the center + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); + } + break; + default: + // *** Default to center + $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); + $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); + break; + } + } + + return ['x' => $cropStartX, 'y' => $cropStartY]; + } + + // # -------------------------------------------------------- + + private function getDimensions($newWidth, $newHeight, $option) + // Author: Jarrod Oberto + // Date: 17-11-09 + // Purpose: Get new image dimensions based on user specificaions + // Param in: $newWidth: + // $newHeight: + // Param out: Array of new width and height values + // Reference: + // Notes: If $option = 3 then this function is call recursivly + // + // To clarify the $option input: + // 0 = The exact height and width dimensions you set. + // 1 = Whatever height is passed in will be the height that + // is set. The width will be calculated and set automatically + // to a the value that keeps the original aspect ratio. + // 2 = The same but based on the width. + // 3 = Depending whether the image is landscape or portrait, this + // will automatically determine whether to resize via + // dimension 1,2 or 0. + // 4 = Resize the image as much as possible, then crop the + // remainder. + { + switch ((string) $option) { + case '0': + case 'exact': + $optimalWidth = $newWidth; + $optimalHeight = $newHeight; + break; + case '1': + case 'portrait': + $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + break; + case '2': + case 'landscape': + $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + break; + case '3': + case 'auto': + $dimensionsArray = $this->getSizeByAuto($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + break; + case '4': + case 'crop': + $dimensionsArray = $this->getOptimalCrop($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + break; + } + + return ['optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight]; + } + + // # -------------------------------------------------------- + + private function getSizeByFixedHeight($newWidth, $newHeight) + { + // *** If forcing is off... + if (!$this->forceStretch) { + // *** ...check if actual height is less than target height + if ($this->height < $newHeight) { + return ['optimalWidth' => $this->width, 'optimalHeight' => $this->height]; + } + } + + $ratio = $this->width / $this->height; + + $newWidth = $newHeight * $ratio; + + // return $newWidth; + return ['optimalWidth' => $newWidth, 'optimalHeight' => $newHeight]; + } + + // # -------------------------------------------------------- + + private function getSizeByFixedWidth($newWidth, $newHeight) + { + // *** If forcing is off... + if (!$this->forceStretch) { + // *** ...check if actual width is less than target width + if ($this->width < $newWidth) { + return ['optimalWidth' => $this->width, 'optimalHeight' => $this->height]; + } + } + + $ratio = $this->height / $this->width; + + $newHeight = $newWidth * $ratio; + + // return $newHeight; + return ['optimalWidth' => $newWidth, 'optimalHeight' => $newHeight]; + } + + // # -------------------------------------------------------- + + private function getSizeByAuto($newWidth, $newHeight) + // Author: Jarrod Oberto + // Date: 19-08-08 + // Purpose: Depending on the height, choose to resize by 0, 1, or 2 + // Param in: The new height and new width + // Notes: + // + { + // *** If forcing is off... + if (!$this->forceStretch) { + // *** ...check if actual size is less than target size + if ($this->width < $newWidth && $this->height < $newHeight) { + return ['optimalWidth' => $this->width, 'optimalHeight' => $this->height]; + } + } + + if ($this->height < $this->width) { + // *** Image to be resized is wider (landscape) + // $optimalWidth = $newWidth; + // $optimalHeight= $this->getSizeByFixedWidth($newWidth); + + $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + } elseif ($this->height > $this->width) { + // *** Image to be resized is taller (portrait) + // $optimalWidth = $this->getSizeByFixedHeight($newHeight); + // $optimalHeight= $newHeight; + + $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + } else { // *** Image to be resizerd is a square + if ($newHeight < $newWidth) { + // $optimalWidth = $newWidth; + // $optimalHeight= $this->getSizeByFixedWidth($newWidth); + $dimensionsArray = $this->getSizeByFixedWidth($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + } else { + if ($newHeight > $newWidth) { + // $optimalWidth = $this->getSizeByFixedHeight($newHeight); + // $optimalHeight= $newHeight; + $dimensionsArray = $this->getSizeByFixedHeight($newWidth, $newHeight); + $optimalWidth = $dimensionsArray['optimalWidth']; + $optimalHeight = $dimensionsArray['optimalHeight']; + } else { + // *** Sqaure being resized to a square + $optimalWidth = $newWidth; + $optimalHeight = $newHeight; + } + } + } + + return ['optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight]; + } + + // # -------------------------------------------------------- + + private function getOptimalCrop($newWidth, $newHeight) + // Author: Jarrod Oberto + // Date: 17-11-09 + // Purpose: Get optimal crop dimensions + // Param in: width and height as requested by user (fig 3) + // Param out: Array of optimal width and height (fig 2) + // Reference: + // Notes: The optimal width and height return are not the same as the + // same as the width and height passed in. For example: + // + // + // |-----------------| |------------| |-------| + // | | => |**| |**| => | | + // | | |**| |**| | | + // | | |------------| |-------| + // |-----------------| + // original optimal crop + // size size size + // Fig 1 2 3 + // + // 300 x 250 150 x 125 150 x 100 + // + // The optimal size is the smallest size (that is closest to the crop size) + // while retaining proportion/ratio. + // + // The crop size is the optimal size that has been cropped on one axis to + // make the image the exact size specified by the user. + // + // * represent cropped area + // + { + // *** If forcing is off... + if (!$this->forceStretch) { + // *** ...check if actual size is less than target size + if ($this->width < $newWidth && $this->height < $newHeight) { + return ['optimalWidth' => $this->width, 'optimalHeight' => $this->height]; + } + } + + $heightRatio = $this->height / $newHeight; + $widthRatio = $this->width / $newWidth; + + if ($heightRatio < $widthRatio) { + $optimalRatio = $heightRatio; + } else { + $optimalRatio = $widthRatio; + } + + $optimalHeight = round($this->height / $optimalRatio); + $optimalWidth = round($this->width / $optimalRatio); + + return ['optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight]; + } + + // # -------------------------------------------------------- + + private function sharpen(): void + // Author: Jarrod Oberto + // Date: 08 04 2011 + // Purpose: Sharpen image + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // Credit: Incorporates Joe Lencioni (August 6, 2008) code + { + if (version_compare(\PHP_VERSION, '5.1.0') >= 0) { + // *** + if ($this->aggresiveSharpening) { // A more aggressive sharpening solution + $sharpenMatrix = [[-1, -1, -1], + [-1, 16, -1], + [-1, -1, -1], ]; + $divisor = 8; + $offset = 0; + + imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset); + } else { // More subtle and personally more desirable + $sharpness = $this->findSharp($this->widthOriginal, $this->width); + + $sharpenMatrix = [ + [-1, -2, -1], + [-2, $sharpness + 12, -2], // Lessen the effect of a filter by increasing the value in the center cell + [-1, -2, -1], + ]; + $divisor = $sharpness; // adjusts brightness + $offset = 0; + imageconvolution($this->imageResized, $sharpenMatrix, $divisor, $offset); + } + } else { + if ($this->debug) { + throw new Exception('Sharpening required PHP 5.1.0 or greater.'); + } + } + } + + // # -------------------------------------------------------- + + private function sharpen2($level): void + { + $sharpenMatrix = [ + [$level, $level, $level], + [$level, (8 * $level) + 1, $level], // Lessen the effect of a filter by increasing the value in the center cell + [$level, $level, $level], + ]; + } + + // # -------------------------------------------------------- + + private function findSharp($orig, $final) + // Author: Ryan Rud (http://adryrun.com) + // Purpose: Find optimal sharpness + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // + { + $final = $final * (750.0 / $orig); + $a = 52; + $b = -0.27810650887573124; + $c = .00047337278106508946; + + $result = $a + $b * $final + $c * $final * $final; + + return max(round($result), 0); + } + + // # -------------------------------------------------------- + + private function prepOption($option) + // Author: Jarrod Oberto + // Purpose: Prep option like change the passed in option to lowercase + // Param in: (str/int) $option: eg. 'exact', 'crop'. 0, 4 + // Param out: lowercase string + // Reference: + // Notes: + // + { + if (is_array($option)) { + if (fix_strtolower($option[0]) == 'crop' && count($option) == 2) { + return 'crop'; + } + + throw new Exception('Crop resize option array is badly formatted.'); + } else { + if (strpos($option, 'crop') !== false) { + return 'crop'; + } + } + + if (is_string($option)) { + return fix_strtolower($option); + } + + return $option; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Presets +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + +// + // Preset are pre-defined templates you can apply to your image. +// + // These are inteded to be applied to thumbnail images. +// + + public function borderPreset($preset): void + { + switch ($preset) { + case 'simple': + $this->addBorder(7, '#fff'); + $this->addBorder(6, '#f2f1f0'); + $this->addBorder(2, '#fff'); + $this->addBorder(1, '#ccc'); + break; + default: + break; + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Draw border +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addBorder($thickness = 1, $rgbArray = [255, 255, 255]): void + // Author: Jarrod Oberto + // Date: 05-05-11 + // Purpose: Add a border to the image + // Param in: + // Param out: + // Reference: + // Notes: This border is added to the INSIDE of the image + // + { + if ($this->imageResized) { + $rgbArray = $this->formatColor($rgbArray); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + + $x1 = 0; + $y1 = 0; + $x2 = imagesx($this->imageResized) - 1; + $y2 = imagesy($this->imageResized) - 1; + + $rgbArray = imagecolorallocate($this->imageResized, $r, $g, $b); + + for ($i = 0; $i < $thickness; ++$i) { + imagerectangle($this->imageResized, $x1++, $y1++, $x2--, $y2--, $rgbArray); + } + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Gray Scale +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function greyScale(): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Make image greyscale + // Param in: n/a + // Param out: + // Reference: + // Notes: + // + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_GRAYSCALE); + } + } + + // # -------------------------------------------------------- + + public function greyScaleEnhanced(): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Make image greyscale + // Param in: n/a + // Param out: + // Reference: + // Notes: + // + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_GRAYSCALE); + imagefilter($this->imageResized, \IMG_FILTER_CONTRAST, -15); + imagefilter($this->imageResized, \IMG_FILTER_BRIGHTNESS, 2); + $this->sharpen($this->width); + } + } + + // # -------------------------------------------------------- + + public function greyScaleDramatic(): void + // Alias of gd_filter_monopin + { + $this->gd_filter_monopin(); + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Black 'n White +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function blackAndWhite(): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Make image black and white + // Param in: n/a + // Param out: + // Reference: + // Notes: + // + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_GRAYSCALE); + imagefilter($this->imageResized, \IMG_FILTER_CONTRAST, -1000); + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Negative +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function negative(): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Make image negative + // Param in: n/a + // Param out: + // Reference: + // Notes: + // + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_NEGATE); + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Sepia +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function sepia(): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Make image sepia + // Param in: n/a + // Param out: + // Reference: + // Notes: + // + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_GRAYSCALE); + imagefilter($this->imageResized, \IMG_FILTER_BRIGHTNESS, -10); + imagefilter($this->imageResized, \IMG_FILTER_CONTRAST, -20); + imagefilter($this->imageResized, \IMG_FILTER_COLORIZE, 60, 30, -15); + } + } + + // # -------------------------------------------------------- + + public function sepia2(): void + { + if ($this->imageResized) { + $total = imagecolorstotal($this->imageResized); + for ($i = 0; $i < $total; ++$i) { + $index = imagecolorsforindex($this->imageResized, $i); + $red = ($index['red'] * 0.393 + $index['green'] * 0.769 + $index['blue'] * 0.189) / 1.351; + $green = ($index['red'] * 0.349 + $index['green'] * 0.686 + $index['blue'] * 0.168) / 1.203; + $blue = ($index['red'] * 0.272 + $index['green'] * 0.534 + $index['blue'] * 0.131) / 2.140; + imagecolorset($this->imageResized, $i, $red, $green, $blue); + } + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Vintage +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function vintage(): void + // Alias of gd_filter_monopin + { + $this->gd_filter_vintage(); + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Presets By Marc Hibbins +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + /** Apply 'Monopin' preset */ + public function gd_filter_monopin(): void + { + if ($this->imageResized) { + imagefilter($this->imageResized, \IMG_FILTER_GRAYSCALE); + imagefilter($this->imageResized, \IMG_FILTER_BRIGHTNESS, -15); + imagefilter($this->imageResized, \IMG_FILTER_CONTRAST, -15); + $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 100); + } + } + + // # -------------------------------------------------------- + + public function gd_filter_vintage(): void + { + if ($this->imageResized) { + $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'vignette', 45); + imagefilter($this->imageResized, \IMG_FILTER_BRIGHTNESS, 20); + imagefilter($this->imageResized, \IMG_FILTER_CONTRAST, -35); + imagefilter($this->imageResized, \IMG_FILTER_COLORIZE, 60, -10, 35); + imagefilter($this->imageResized, \IMG_FILTER_SMOOTH, 7); + $this->imageResized = $this->gd_apply_overlay($this->imageResized, 'scratch', 10); + } + } + + // # -------------------------------------------------------- + + /** Apply a PNG overlay */ + private function gd_apply_overlay($im, $type, $amount) + // + // Original Author: Marc Hibbins + // License: Attribution-ShareAlike 3.0 + // Purpose: + // Params in: + // Params out: + // Notes: + // + { + $width = imagesx($im); + $height = imagesy($im); + $filter = imagecreatetruecolor($width, $height); + + imagealphablending($filter, false); + imagesavealpha($filter, true); + + $transparent = imagecolorallocatealpha($filter, 255, 255, 255, 127); + imagefilledrectangle($filter, 0, 0, $width, $height, $transparent); + + // *** Resize overlay + $overlay = $this->filterOverlayPath.'/'.$type.'.png'; + $png = imagecreatefrompng($overlay); + imagecopyresampled($filter, $png, 0, 0, 0, 0, $width, $height, imagesx($png), imagesy($png)); + + $comp = imagecreatetruecolor($width, $height); + imagecopy($comp, $im, 0, 0, 0, 0, $width, $height); + imagecopy($comp, $filter, 0, 0, 0, 0, $width, $height); + imagecopymerge($im, $comp, 0, 0, 0, 0, $width, $height, $amount); + + imagedestroy($comp); + + return $im; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Colorise +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function image_colorize($rgb) + { + imagetruecolortopalette($this->imageResized, true, 256); + $numColors = imagecolorstotal($this->imageResized); + + for ($x = 0; $x < $numColors; ++$x) { + [$r, $g, $b] = array_values(imagecolorsforindex($this->imageResized, $x)); + + // calculate grayscale in percent + $grayscale = ($r + $g + $b) / 3 / 0xFF; + + imagecolorset($this->imageResized, $x, + $grayscale * $rgb[0], + $grayscale * $rgb[1], + $grayscale * $rgb[2] + ); + } + + return true; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Reflection +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addReflection($reflectionHeight = 50, $startingTransparency = 30, $inside = false, $bgColor = '#fff', $stretch = false, $divider = 0): void + { + // *** Convert color + $rgbArray = $this->formatColor($bgColor); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + + $im = $this->imageResized; + $li = imagecreatetruecolor($this->width, 1); + + $bgc = imagecolorallocate($li, $r, $g, $b); + imagefilledrectangle($li, 0, 0, $this->width, 1, $bgc); + + $bg = imagecreatetruecolor($this->width, $reflectionHeight); + $wh = imagecolorallocate($im, 255, 255, 255); + + $im = imagerotate($im, -180, $wh); + imagecopyresampled($bg, $im, 0, 0, 0, 0, $this->width, $this->height, $this->width, $this->height); + + $im = $bg; + + $bg = imagecreatetruecolor($this->width, $reflectionHeight); + + for ($x = 0; $x < $this->width; ++$x) { + imagecopy($bg, $im, $x, 0, $this->width - $x - 1, 0, 1, $reflectionHeight); + } + $im = $bg; + + $transaprencyAmount = $this->invertTransparency($startingTransparency, 100); + + // *** Fade + if ($stretch) { + $step = 100 / ($reflectionHeight + $startingTransparency); + } else { + $step = 100 / $reflectionHeight; + } + for ($i = 0; $i <= $reflectionHeight; ++$i) { + if ($startingTransparency > 100) { + $startingTransparency = 100; + } + if ($startingTransparency < 1) { + $startingTransparency = 1; + } + imagecopymerge($bg, $li, 0, $i, 0, 0, $this->width, 1, $startingTransparency); + $startingTransparency += $step; + } + + // *** Apply fade + imagecopymerge($im, $li, 0, 0, 0, 0, $this->width, $divider, 100); // Divider + + // *** width, height of reflection. + $x = imagesx($im); + $y = imagesy($im); + + // *** Determines if the reflection should be displayed inside or outside the image + if ($inside) { + // Create new blank image with sizes. + $final = imagecreatetruecolor($this->width, $this->height); + + imagecopymerge($final, $this->imageResized, 0, 0, 0, $reflectionHeight, $this->width, $this->height - $reflectionHeight, 100); + imagecopymerge($final, $im, 0, $this->height - $reflectionHeight, 0, 0, $x, $y, 100); + } else { + // Create new blank image with sizes. + $final = imagecreatetruecolor($this->width, $this->height + $y); + + imagecopymerge($final, $this->imageResized, 0, 0, 0, 0, $this->width, $this->height, 100); + imagecopymerge($final, $im, 0, $this->height, 0, 0, $x, $y, 100); + } + + $this->imageResized = $final; + + imagedestroy($li); + imagedestroy($im); + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Rotate +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function rotate($value = 90, $bgColor = 'transparent'): void + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Rotate image + // Param in: (mixed) $degrees: (int) number of degress to rotate image + // (str) param "left": rotate left + // (str) param "right": rotate right + // (str) param "upside": upside-down image + // Param out: + // Reference: + // Notes: The default direction of imageRotate() is counter clockwise. + // + { + if ($this->imageResized) { + if (is_int($value)) { + $degrees = $value; + } + + // *** Convert color + $rgbArray = $this->formatColor($bgColor); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + if (isset($rgbArray['a'])) { + $a = $rgbArray['a']; + } + + if (is_string($value)) { + $value = fix_strtolower($value); + + switch ($value) { + case 'left': + $degrees = 90; + break; + case 'right': + $degrees = 270; + break; + case 'upside': + $degrees = 180; + break; + default: + break; + } + } + + // *** The default direction of imageRotate() is counter clockwise + // * This makes it clockwise + $degrees = 360 - $degrees; + + // *** Create background color + $bg = imagecolorallocatealpha($this->imageResized, $r, $g, $b, $a); + + // *** Fill with background + imagefill($this->imageResized, 0, 0, $bg); + + // *** Rotate + $this->imageResized = imagerotate($this->imageResized, $degrees, $bg); // Rotate 45 degrees and allocated the transparent colour as the one to make transparent (obviously) + + // Ensure alpha transparency + imagesavealpha($this->imageResized, true); + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Round corners +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function roundCorners($radius = 5, $bgColor = 'transparent'): void + // Author: Jarrod Oberto + // Date: 19-05-2011 + // Purpose: Create rounded corners on your image + // Param in: (int) radius = the amount of curvature + // (mixed) $bgColor = the corner background color + // Param out: n/a + // Reference: + // Notes: + // + { + // *** Check if the user wants transparency + $isTransparent = false; + if (!is_array($bgColor)) { + if (fix_strtolower($bgColor) == 'transparent') { + $isTransparent = true; + } + } + + // *** If we use transparency, we need to color our curved mask with a unique color + if ($isTransparent) { + $bgColor = $this->findUnusedGreen(); + } + + // *** Convert color + $rgbArray = $this->formatColor($bgColor); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + if (isset($rgbArray['a'])) { + $a = $rgbArray['a']; + } + + // *** Create top-left corner mask (square) + $cornerImg = imagecreatetruecolor($radius, $radius); + // $cornerImg = imagecreate($radius, $radius); + + // imagealphablending($cornerImg, true); + // imagesavealpha($cornerImg, true); + + // imagealphablending($this->imageResized, false); + // imagesavealpha($this->imageResized, true); + + // *** Give it a color + $maskColor = imagecolorallocate($cornerImg, 0, 0, 0); + + // *** Replace the mask color (black) to transparent + imagecolortransparent($cornerImg, $maskColor); + + // *** Create the image background color + $imagebgColor = imagecolorallocate($cornerImg, $r, $g, $b); + + // *** Fill the corner area to the user defined color + imagefill($cornerImg, 0, 0, $imagebgColor); + + imagefilledellipse($cornerImg, $radius, $radius, $radius * 2, $radius * 2, $maskColor); + + // *** Map to top left corner + imagecopymerge($this->imageResized, $cornerImg, 0, 0, 0, 0, $radius, $radius, 100); // tl + + // *** Map rounded corner to other corners by rotating and applying the mask + $cornerImg = imagerotate($cornerImg, 90, 0); + imagecopymerge($this->imageResized, $cornerImg, 0, $this->height - $radius, 0, 0, $radius, $radius, 100); // bl + + $cornerImg = imagerotate($cornerImg, 90, 0); + imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, $this->height - $radius, 0, 0, $radius, $radius, 100); // br + + $cornerImg = imagerotate($cornerImg, 90, 0); + imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, 0, 0, 0, $radius, $radius, 100); // tr + + // *** If corners are to be transparent, we fill our chromakey color as transparent. + if ($isTransparent) { + // imagecolortransparent($this->imageResized, $imagebgColor); + $this->imageResized = $this->transparentImage($this->imageResized); + imagesavealpha($this->imageResized, true); + } + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Shadow +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addShadow($shadowAngle = 45, $blur = 15, $bgColor = 'transparent'): void + // + // Author: Jarrod Oberto (Adapted from Pascal Naidon) + // Ref: http://www.les-stooges.org/pascal/webdesign/vignettes/index.php?la=en + // Purpose: Add a drop shadow to your image + // Params in: (int) $angle: the angle of the shadow + // (int) $blur: the blur distance + // (mixed) $bgColor: the color of the background + // Params out: + // Notes: + // + { + // *** A higher number results in a smoother shadow + define('STEPS', $blur * 2); + + // *** Set the shadow distance + $shadowDistance = $blur * 0.25; + + // *** Set blur width and height + $blurWidth = $blurHeight = $blur; + + if ($shadowAngle == 0) { + $distWidth = 0; + $distHeight = 0; + } else { + $distWidth = $shadowDistance * cos(deg2rad($shadowAngle)); + $distHeight = $shadowDistance * sin(deg2rad($shadowAngle)); + } + + // *** Convert color + if (fix_strtolower($bgColor) != 'transparent') { + $rgbArray = $this->formatColor($bgColor); + $r0 = $rgbArray['r']; + $g0 = $rgbArray['g']; + $b0 = $rgbArray['b']; + } + + $image = $this->imageResized; + $width = $this->width; + $height = $this->height; + + $newImage = imagecreatetruecolor($width, $height); + imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width, $height); + + // *** RGB + $rgb = imagecreatetruecolor($width + $blurWidth, $height + $blurHeight); + $colour = imagecolorallocate($rgb, 0, 0, 0); + imagefilledrectangle($rgb, 0, 0, $width + $blurWidth, $height + $blurHeight, $colour); + $colour = imagecolorallocate($rgb, 255, 255, 255); + // imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour); + imagefilledrectangle($rgb, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, $width + $blurWidth * 0.5 - $distWidth, $height + $blurWidth * 0.5 - $distHeight, $colour); + // imagecopymerge($rgb, $newImage, 1+$blurWidth*0.5-$distWidth, 1+$blurHeight*0.5-$distHeight, 0,0, $width, $height, 100); + imagecopymerge($rgb, $newImage, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, 0, 0, $width + $blurWidth, $height + $blurHeight, 100); + + // *** Shadow (alpha) + $shadow = imagecreatetruecolor($width + $blurWidth, $height + $blurHeight); + imagealphablending($shadow, false); + $colour = imagecolorallocate($shadow, 0, 0, 0); + imagefilledrectangle($shadow, 0, 0, $width + $blurWidth, $height + $blurHeight, $colour); + + for ($i = 0; $i <= STEPS; ++$i) { + $t = ((1.0 * $i) / STEPS); + $intensity = 255 * $t * $t; + + $colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity); + $points = [ + $blurWidth * $t, $blurHeight, // Point 1 (x, y) + $blurWidth, $blurHeight * $t, // Point 2 (x, y) + $width, $blurHeight * $t, // Point 3 (x, y) + $width + $blurWidth * (1 - $t), $blurHeight, // Point 4 (x, y) + $width + $blurWidth * (1 - $t), $height, // Point 5 (x, y) + $width, $height + $blurHeight * (1 - $t), // Point 6 (x, y) + $blurWidth, $height + $blurHeight * (1 - $t), // Point 7 (x, y) + $blurWidth * $t, $height, // Point 8 (x, y) + ]; + imagepolygon($shadow, $points, 8, $colour); + } + + for ($i = 0; $i <= STEPS; ++$i) { + $t = ((1.0 * $i) / STEPS); + $intensity = 255 * $t * $t; + + $colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity); + imagefilledarc($shadow, $blurWidth - 1, $blurHeight - 1, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 180, 268, $colour, \IMG_ARC_PIE); + imagefilledarc($shadow, $width, $blurHeight - 1, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 270, 358, $colour, \IMG_ARC_PIE); + imagefilledarc($shadow, $width, $height, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 0, 90, $colour, \IMG_ARC_PIE); + imagefilledarc($shadow, $blurWidth - 1, $height, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 90, 180, $colour, \IMG_ARC_PIE); + } + + $colour = imagecolorallocate($shadow, 255, 255, 255); + imagefilledrectangle($shadow, $blurWidth, $blurHeight, $width, $height, $colour); + imagefilledrectangle($shadow, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, $width + $blurWidth * 0.5 - 1 - $distWidth, $height + $blurHeight * 0.5 - 1 - $distHeight, $colour); + + // *** The magic + imagealphablending($rgb, false); + + for ($theX = 0; $theX < imagesx($rgb); ++$theX) { + for ($theY = 0; $theY < imagesy($rgb); ++$theY) { + // *** Get the RGB values for every pixel of the RGB image + $colArray = imagecolorat($rgb, $theX, $theY); + $r = ($colArray >> 16) & 0xFF; + $g = ($colArray >> 8) & 0xFF; + $b = $colArray & 0xFF; + + // *** Get the alpha value for every pixel of the shadow image + $colArray = imagecolorat($shadow, $theX, $theY); + $a = $colArray & 0xFF; + $a = 127 - floor($a / 2); + $t = $a / 128.0; + + // *** Create color + if (fix_strtolower($bgColor) == 'transparent') { + $myColour = imagecolorallocatealpha($rgb, $r, $g, $b, $a); + } else { + $myColour = imagecolorallocate($rgb, $r * (1.0 - $t) + $r0 * $t, $g * (1.0 - $t) + $g0 * $t, $b * (1.0 - $t) + $b0 * $t); + } + + // *** Add color to new rgb image + imagesetpixel($rgb, $theX, $theY, $myColour); + } + } + + imagealphablending($rgb, true); + imagesavealpha($rgb, true); + + $this->imageResized = $rgb; + + imagedestroy($image); + imagedestroy($newImage); + imagedestroy($shadow); + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Add Caption Box +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addCaptionBox($side = 'b', $thickness = 50, $padding = 0, $bgColor = '#000', $transaprencyAmount = 30): void + // + // Author: Jarrod Oberto + // Date: 26 May 2011 + // Purpose: Add a caption box + // Params in: (str) $side: the side to add the caption box (t, r, b, or l). + // (int) $thickness: how thick you want the caption box to be. + // (mixed) $bgColor: The color of the caption box. + // (int) $transaprencyAmount: The amount of transparency to be + // applied. + // Params out: n/a + // Notes: + // + { + $side = fix_strtolower($side); + + // *** Convert color + $rgbArray = $this->formatColor($bgColor); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + + $positionArray = $this->calculateCaptionBoxPosition($side, $thickness, $padding); + + // *** Store incase we want to use method addTextToCaptionBox() + $this->captionBoxPositionArray = $positionArray; + + $transaprencyAmount = $this->invertTransparency($transaprencyAmount, 127, false); + $transparent = imagecolorallocatealpha($this->imageResized, $r, $g, $b, $transaprencyAmount); + imagefilledrectangle($this->imageResized, $positionArray['x1'], $positionArray['y1'], $positionArray['x2'], $positionArray['y2'], $transparent); + } + + // # -------------------------------------------------------- + + public function addTextToCaptionBox($text, $fontColor = '#fff', $fontSize = 12, $angle = 0, $font = null) + // + // Author: Jarrod Oberto + // Date: 03 Aug 11 + // Purpose: Simplify adding text to a caption box by automatically + // locating the center of the caption box + // Params in: The usually text paams (less a couple) + // Params out: n/a + // Notes: + // + { + // *** Get the caption box measurements + if (count($this->captionBoxPositionArray) == 4) { + $x1 = $this->captionBoxPositionArray['x1']; + $x2 = $this->captionBoxPositionArray['x2']; + $y1 = $this->captionBoxPositionArray['y1']; + $y2 = $this->captionBoxPositionArray['y2']; + } else { + if ($this->debug) { + throw new Exception('No caption box found.'); + } + + return false; + } + + // *** Get text font + $font = $this->getTextFont($font); + + // *** Get text size + $textSizeArray = $this->getTextSize($fontSize, $angle, $font, $text); + $textWidth = $textSizeArray['width']; + $textHeight = $textSizeArray['height']; + + // *** Find the width/height middle points + $boxXMiddle = (($x2 - $x1) / 2); + $boxYMiddle = (($y2 - $y1) / 2); + + // *** Box middle - half the text width/height + $xPos = ($x1 + $boxXMiddle) - ($textWidth / 2); + $yPos = ($y1 + $boxYMiddle) - ($textHeight / 2); + + $pos = $xPos.'x'.$yPos; + + $this->addText($text, $pos, $padding = 0, $fontColor, $fontSize, $angle, $font); + } + + // # -------------------------------------------------------- + + private function calculateCaptionBoxPosition($side, $thickness, $padding) + { + $positionArray = []; + + switch ($side) { + case 't': + $positionArray['x1'] = 0; + $positionArray['y1'] = $padding; + $positionArray['x2'] = $this->width; + $positionArray['y2'] = $thickness + $padding; + break; + case 'r': + $positionArray['x1'] = $this->width - $thickness - $padding; + $positionArray['y1'] = 0; + $positionArray['x2'] = $this->width - $padding; + $positionArray['y2'] = $this->height; + break; + case 'b': + $positionArray['x1'] = 0; + $positionArray['y1'] = $this->height - $thickness - $padding; + $positionArray['x2'] = $this->width; + $positionArray['y2'] = $this->height - $padding; + break; + case 'l': + $positionArray['x1'] = $padding; + $positionArray['y1'] = 0; + $positionArray['x2'] = $thickness + $padding; + $positionArray['y2'] = $this->height; + break; + default: + break; + } + + return $positionArray; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Get EXIF Data +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function getExif($debug = false) + // Author: Jarrod Oberto + // Date: 07-05-2011 + // Purpose: Get image EXIF data + // Param in: n/a + // Param out: An associate array of EXIF data + // Reference: + // Notes: + // 23 May 13 : added orientation flag -jco + // + { + if (!$this->debug || !$debug) { + $debug = false; + } + + // *** Check all is good - check the EXIF library exists and the file exists, too. + if (!$this->testEXIFInstalled()) { + if ($debug) { + throw new Exception('The EXIF Library is not installed.'); + } + + return []; + } + if (!file_exists($this->fileName)) { + if ($debug) { + throw new Exception('Image not found.'); + } + + return []; + } + if ($this->fileExtension != '.jpg') { + if ($debug) { + throw new Exception('Metadata not supported for this image type.'); + } + + return []; + } + $exifData = exif_read_data($this->fileName, 'IFD0'); + + // *** Format the apperture value + $ev = $exifData['ApertureValue']; + $apPeicesArray = explode('/', $ev); + if (count($apPeicesArray) == 2) { + $apertureValue = round($apPeicesArray[0] / $apPeicesArray[1], 2, \PHP_ROUND_HALF_DOWN).' EV'; + } else { + $apertureValue = ''; + } + + // *** Format the focal length + $focalLength = $exifData['FocalLength']; + $flPeicesArray = explode('/', $focalLength); + if (count($flPeicesArray) == 2) { + $focalLength = $flPeicesArray[0] / $flPeicesArray[1].'.0 mm'; + } else { + $focalLength = ''; + } + + // *** Format fNumber + $fNumber = $exifData['FNumber']; + $fnPeicesArray = explode('/', $fNumber); + if (count($fnPeicesArray) == 2) { + $fNumber = $fnPeicesArray[0] / $fnPeicesArray[1]; + } else { + $fNumber = ''; + } + + // *** Resolve ExposureProgram + if (isset($exifData['ExposureProgram'])) { + $ep = $exifData['ExposureProgram']; + } + if (isset($ep)) { + $ep = $this->resolveExposureProgram($ep); + } + + // *** Resolve MeteringMode + $mm = $exifData['MeteringMode']; + $mm = $this->resolveMeteringMode($mm); + + // *** Resolve Flash + $flash = $exifData['Flash']; + $flash = $this->resolveFlash($flash); + + if (isset($exifData['Make'])) { + $exifDataArray['make'] = $exifData['Make']; + } else { + $exifDataArray['make'] = ''; + } + + if (isset($exifData['Model'])) { + $exifDataArray['model'] = $exifData['Model']; + } else { + $exifDataArray['model'] = ''; + } + + if (isset($exifData['DateTime'])) { + $exifDataArray['date'] = $exifData['DateTime']; + } else { + $exifDataArray['date'] = ''; + } + + if (isset($exifData['ExposureTime'])) { + $exifDataArray['exposure time'] = $exifData['ExposureTime'].' sec.'; + } else { + $exifDataArray['exposure time'] = ''; + } + + if ($apertureValue != '') { + $exifDataArray['aperture value'] = $apertureValue; + } else { + $exifDataArray['aperture value'] = ''; + } + + if (isset($exifData['COMPUTED']['ApertureFNumber'])) { + $exifDataArray['f-stop'] = $exifData['COMPUTED']['ApertureFNumber']; + } else { + $exifDataArray['f-stop'] = ''; + } + + if (isset($exifData['FNumber'])) { + $exifDataArray['fnumber'] = $exifData['FNumber']; + } else { + $exifDataArray['fnumber'] = ''; + } + + if ($fNumber != '') { + $exifDataArray['fnumber value'] = $fNumber; + } else { + $exifDataArray['fnumber value'] = ''; + } + + if (isset($exifData['ISOSpeedRatings'])) { + $exifDataArray['iso'] = $exifData['ISOSpeedRatings']; + } else { + $exifDataArray['iso'] = ''; + } + + if ($focalLength != '') { + $exifDataArray['focal length'] = $focalLength; + } else { + $exifDataArray['focal length'] = ''; + } + + if (isset($ep)) { + $exifDataArray['exposure program'] = $ep; + } else { + $exifDataArray['exposure program'] = ''; + } + + if ($mm != '') { + $exifDataArray['metering mode'] = $mm; + } else { + $exifDataArray['metering mode'] = ''; + } + + if ($flash != '') { + $exifDataArray['flash status'] = $flash; + } else { + $exifDataArray['flash status'] = ''; + } + + if (isset($exifData['Artist'])) { + $exifDataArray['creator'] = $exifData['Artist']; + } else { + $exifDataArray['creator'] = ''; + } + + if (isset($exifData['Copyright'])) { + $exifDataArray['copyright'] = $exifData['Copyright']; + } else { + $exifDataArray['copyright'] = ''; + } + + // *** Orientation + if (isset($exifData['Orientation'])) { + $exifDataArray['orientation'] = $exifData['Orientation']; + } else { + $exifDataArray['orientation'] = ''; + } + + return $exifDataArray; + } + + // # -------------------------------------------------------- + + private function resolveExposureProgram($ep) + { + switch ($ep) { + case 0: + $ep = ''; + break; + case 1: + $ep = 'manual'; + break; + case 2: + $ep = 'normal program'; + break; + case 3: + $ep = 'aperture priority'; + break; + case 4: + $ep = 'shutter priority'; + break; + case 5: + $ep = 'creative program'; + break; + case 6: + $ep = 'action program'; + break; + case 7: + $ep = 'portrait mode'; + break; + case 8: + $ep = 'landscape mode'; + break; + default: + break; + } + + return $ep; + } + + // # -------------------------------------------------------- + + private function resolveMeteringMode($mm) + { + switch ($mm) { + case 0: + $mm = 'unknown'; + break; + case 1: + $mm = 'average'; + break; + case 2: + $mm = 'center weighted average'; + break; + case 3: + $mm = 'spot'; + break; + case 4: + $mm = 'multi spot'; + break; + case 5: + $mm = 'pattern'; + break; + case 6: + $mm = 'partial'; + break; + case 255: + $mm = 'other'; + break; + default: + break; + } + + return $mm; + } + + // # -------------------------------------------------------- + + private function resolveFlash($flash) + { + switch ($flash) { + case 0: + $flash = 'flash did not fire'; + break; + case 1: + $flash = 'flash fired'; + break; + case 5: + $flash = 'strobe return light not detected'; + break; + case 7: + $flash = 'strobe return light detected'; + break; + case 9: + $flash = 'flash fired, compulsory flash mode'; + break; + case 13: + $flash = 'flash fired, compulsory flash mode, return light not detected'; + break; + case 15: + $flash = 'flash fired, compulsory flash mode, return light detected'; + break; + case 16: + $flash = 'flash did not fire, compulsory flash mode'; + break; + case 24: + $flash = 'flash did not fire, auto mode'; + break; + case 25: + $flash = 'flash fired, auto mode'; + break; + case 29: + $flash = 'flash fired, auto mode, return light not detected'; + break; + case 31: + $flash = 'flash fired, auto mode, return light detected'; + break; + case 32: + $flash = 'no flash function'; + break; + case 65: + $flash = 'flash fired, red-eye reduction mode'; + break; + case 69: + $flash = 'flash fired, red-eye reduction mode, return light not detected'; + break; + case 71: + $flash = 'flash fired, red-eye reduction mode, return light detected'; + break; + case 73: + $flash = 'flash fired, compulsory flash mode, red-eye reduction mode'; + break; + case 77: + $flash = 'flash fired, compulsory flash mode, red-eye reduction mode, return light not detected'; + break; + case 79: + $flash = 'flash fired, compulsory flash mode, red-eye reduction mode, return light detected'; + break; + case 89: + $flash = 'flash fired, auto mode, red-eye reduction mode'; + break; + case 93: + $flash = 'flash fired, auto mode, return light not detected, red-eye reduction mode'; + break; + case 95: + $flash = 'flash fired, auto mode, return light detected, red-eye reduction mode'; + break; + default: + break; + } + + return $flash; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Get IPTC Data +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Write IPTC Data +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function writeIPTCcaption($value): void + // Caption + { + $this->writeIPTC(120, $value); + } + + // # -------------------------------------------------------- + + public function writeIPTCwriter($value): void + { + // $this->writeIPTC(65, $value); + } + + // # -------------------------------------------------------- + + private function writeIPTC($dat, $value): void + { + // LIMIT TO JPG + + $caption_block = $this->iptc_maketag(2, $dat, $value); + $image_string = iptcembed($caption_block, $this->fileName); + file_put_contents('iptc.jpg', $image_string); + } + + // # -------------------------------------------------------- + + private function iptc_maketag($rec, $dat, $val) + // Author: Thies C. Arntzen + // Purpose: Function to format the new IPTC text + // Param in: $rec: Application record. (We’re working with #2) + // $dat: Index. (120 for caption, 118 for contact. See the IPTC IIM + // specification: + // http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf + // $val: Value/data/text. Make sure this is within the length + // constraints of the IPTC IIM specification + // Ref: http://blog.peterhaza.no/working-with-image-meta-data-in-exif-and-iptc-headers-from-php/ + // http://php.net/manual/en/function.iptcembed.php + // + { + $len = strlen($val); + if ($len < 0x8000) { + return chr(0x1C).chr($rec).chr($dat). + chr($len >> 8). + chr($len & 0xFF). + $val; + } + + return chr(0x1C).chr($rec).chr($dat). + chr(0x80).chr(0x04). + chr(($len >> 24) & 0xFF). + chr(($len >> 16) & 0xFF). + chr(($len >> 8) & 0xFF). + chr($len & 0xFF). + $val; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Write XMP Data +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + // http://xmpphptoolkit.sourceforge.net/ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Add Text +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addText($text, $pos = '20x20', $padding = 0, $fontColor = '#fff', $fontSize = 12, $angle = 0, $font = null): void + // Author: Jarrod Oberto + // Date: 18-11-09 + // Purpose: Add text to an image + // Param in: + // Param out: + // Reference: http://php.net/manual/en/function.imagettftext.php + // Notes: Make sure you supply the font. + // + { + // *** Convert color + $rgbArray = $this->formatColor($fontColor); + $r = $rgbArray['r']; + $g = $rgbArray['g']; + $b = $rgbArray['b']; + + // *** Get text font + $font = $this->getTextFont($font); + + // *** Get text size + $textSizeArray = $this->getTextSize($fontSize, $angle, $font, $text); + $textWidth = $textSizeArray['width']; + $textHeight = $textSizeArray['height']; + + // *** Find co-ords to place text + $posArray = $this->calculatePosition($pos, $padding, $textWidth, $textHeight, false); + $x = $posArray['width']; + $y = $posArray['height']; + + $fontColor = imagecolorallocate($this->imageResized, $r, $g, $b); + + // *** Add text + imagettftext($this->imageResized, $fontSize, $angle, $x, $y, $fontColor, $font, $text); + } + + // # -------------------------------------------------------- + + private function getTextFont($font) + { + // *** Font path (shou + $fontPath = __DIR__.'/'.$this->fontDir; + + // *** The below is/may be needed depending on your version (see ref) + putenv('GDFONTPATH='.realpath('.')); + + // *** Check if the passed in font exsits... + if ($font == null || !file_exists($font)) { + // *** ...If not, default to this font. + $font = $fontPath.'/arimo.ttf'; + + // *** Check our default font exists... + if (!file_exists($font)) { + // *** If not, return false + if ($this->debug) { + throw new Exception('Font not found'); + } + + return false; + } + } + + return $font; + } + + // # -------------------------------------------------------- + + private function getTextSize($fontSize, $angle, $font, $text) + { + // *** Define box (so we can get the width) + $box = @imagettfbbox($fontSize, $angle, $font, $text); + + // *** Get width of text from dimensions + $textWidth = abs($box[4] - $box[0]); + + // *** Get height of text from dimensions (should also be same as $fontSize) + $textHeight = abs($box[5] - $box[1]); + + return ['height' => $textHeight, 'width' => $textWidth]; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + Add Watermark +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + public function addWatermark($watermarkImage, $pos, $padding = 0, $opacity = 0): void + // Author: Jarrod Oberto + // Date: 18-11-09 + // Purpose: Add watermark image + // Param in: (str) $watermark: The watermark image + // (str) $pos: Could be a pre-determined position such as: + // tl = top left, + // t = top (middle), + // tr = top right, + // l = left, + // m = middle, + // r = right, + // bl = bottom left, + // b = bottom (middle), + // br = bottom right + // Or, it could be a co-ordinate position such as: 50x100 + // + // (int) $padding: If using a pre-determined position you can + // adjust the padding from the edges by passing an amount + // in pixels. If using co-ordinates, this value is ignored. + // Param out: + // Reference: http://www.php.net/manual/en/image.examples-watermark.php + // Notes: Based on example in reference. + // + // + { + // Load the stamp and the photo to apply the watermark to + $stamp = $this->openImage($watermarkImage); // stamp + $im = $this->imageResized; // photo + + // *** Get stamps width and height + $sx = imagesx($stamp); + $sy = imagesy($stamp); + + // *** Find co-ords to place image + $posArray = $this->calculatePosition($pos, $padding, $sx, $sy); + $x = $posArray['width']; + $y = $posArray['height']; + + // *** Set watermark opacity + if (fix_strtolower(strrchr($watermarkImage, '.')) == '.png') { + $opacity = $this->invertTransparency($opacity, 100); + $this->filterOpacity($stamp, $opacity); + } + + // Copy the watermark image onto our photo + imagecopy($im, $stamp, $x, $y, 0, 0, imagesx($stamp), imagesy($stamp)); + } + + // # -------------------------------------------------------- + + private function calculatePosition($pos, $padding, $assetWidth, $assetHeight, $upperLeft = true) + // + // Author: Jarrod Oberto + // Date: 08-05-11 + // Purpose: Calculate the x, y pixel cordinates of the asset to place + // Params in: (str) $pos: Either something like: "tl", "l", "br" or an + // exact position like: "100x50" + // (int) $padding: The amount of padding from the edge. Only + // used for the predefined $pos. + // (int) $assetWidth: The width of the asset to add to the image + // (int) $assetHeight: The height of the asset to add to the image + // (bol) $upperLeft: if true, the asset will be positioned based + // on the upper left x, y coords. If false, it means you're + // using the lower left as the basepoint and this will + // convert it to the upper left position + // Params out: + // NOTE: this is done from the UPPER left corner!! But will convert lower + // left basepoints to upper left if $upperleft is set to false + // + // + { + $pos = fix_strtolower($pos); + + // *** If co-ords have been entered + if (strstr($pos, 'x')) { + $pos = str_replace(' ', '', $pos); + + $xyArray = explode('x', $pos); + [$width, $height] = $xyArray; + } else { + switch ($pos) { + case 'tl': + $width = 0 + $padding; + $height = 0 + $padding; + break; + case 't': + $width = ($this->width / 2) - ($assetWidth / 2); + $height = 0 + $padding; + break; + case 'tr': + $width = $this->width - $assetWidth - $padding; + $height = 0 + $padding; + break; + case 'l': + $width = 0 + $padding; + $height = ($this->height / 2) - ($assetHeight / 2); + break; + case 'm': + $width = ($this->width / 2) - ($assetWidth / 2); + $height = ($this->height / 2) - ($assetHeight / 2); + break; + case 'r': + $width = $this->width - $assetWidth - $padding; + $height = ($this->height / 2) - ($assetHeight / 2); + break; + case 'bl': + $width = 0 + $padding; + $height = $this->height - $assetHeight - $padding; + break; + case 'b': + $width = ($this->width / 2) - ($assetWidth / 2); + $height = $this->height - $assetHeight - $padding; + break; + case 'br': + $width = $this->width - $assetWidth - $padding; + $height = $this->height - $assetHeight - $padding; + break; + default: + $width = 0; + $height = 0; + break; + } + } + + if (!$upperLeft) { + $height = $height + $assetHeight; + } + + return ['width' => $width, 'height' => $height]; + } + + // # -------------------------------------------------------- + + private function filterOpacity(&$img, $opacity = 75) + // + // Author: aiden dot mail at freemail dot hu + // Author date: 29-03-08 08:16 + // Date added: 08-05-11 + // Purpose: Change opacity of image + // Params in: $img: Image resource id + // (int) $opacity: the opacity amount: 0-100, 100 being not opaque. + // Params out: (bool) true on success, else false + // Ref: http://www.php.net/manual/en/function.imagefilter.php#82162 + // Notes: png only + // + { + if (!isset($opacity)) { + return false; + } + + if ($opacity == 100) { + return true; + } + + $opacity /= 100; + + // get image width and height + $w = imagesx($img); + $h = imagesy($img); + + // turn alpha blending off + imagealphablending($img, false); + + // find the most opaque pixel in the image (the one with the smallest alpha value) + $minalpha = 127; + for ($x = 0; $x < $w; ++$x) { + for ($y = 0; $y < $h; ++$y) { + $alpha = (imagecolorat($img, $x, $y) >> 24) & 0xFF; + if ($alpha < $minalpha) { + $minalpha = $alpha; + } + } + } + + // loop through image pixels and modify alpha for each + for ($x = 0; $x < $w; ++$x) { + for ($y = 0; $y < $h; ++$y) { + // get current alpha value (represents the TANSPARENCY!) + $colorxy = imagecolorat($img, $x, $y); + $alpha = ($colorxy >> 24) & 0xFF; + // calculate new alpha + if ($minalpha !== 127) { + $alpha = 127 + 127 * $opacity * ($alpha - 127) / (127 - $minalpha); + } else { + $alpha += 127 * $opacity; + } + // get the color index with new alpha + $alphacolorxy = imagecolorallocatealpha($img, ($colorxy >> 16) & 0xFF, ($colorxy >> 8) & 0xFF, $colorxy & 0xFF, $alpha); + // set pixel with the new color + opacity + if (!imagesetpixel($img, $x, $y, $alphacolorxy)) { + return false; + } + } + } + + return true; + } + + // # -------------------------------------------------------- + + private function openImage($file) + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: + // Param in: + // Param out: n/a + // Reference: + // Notes: + // + { + if (!file_exists($file) && !$this->checkStringStartsWith('http://', $file) && !$this->checkStringStartsWith('https://', $file)) { + if ($this->debug) { + throw new Exception('Image not found.'); + } + + throw new Exception(); + } + + // *** Get extension + $extension = strrchr($file, '.'); + $extension = fix_strtolower($extension); + switch ($extension) { + case '.jpg': + case '.jpeg': + $img = @imagecreatefromjpeg($file); + break; + case '.gif': + $img = @imagecreatefromgif($file); + break; + case '.png': + $img = @imagecreatefrompng($file); + break; + case '.bmp': + $img = @$this->imagecreatefrombmp($file); + break; + case '.psd': + $img = @$this->imagecreatefrompsd($file); + break; + // ... etc + + default: + $img = false; + break; + } + + return $img; + } + + // # -------------------------------------------------------- + + public function reset(): void + // + // Author: Jarrod Oberto + // Date: 30-08-11 + // Purpose: Reset the resource (allow further editing) + // Params in: + // Params out: + // Notes: + // + { + $this->__construct($this->fileName); + } + + // # -------------------------------------------------------- + + public function saveImage($savePath, $imageQuality = '100'): void + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Saves the image + // Param in: $savePath: Where to save the image including filename: + // $imageQuality: image quality you want the image saved at 0-100 + // Param out: n/a + // Reference: + // Notes: * gif doesn't have a quality parameter + // * jpg has a quality setting 0-100 (100 being the best) + // * png has a quality setting 0-9 (0 being the best) + // + // * bmp files have no native support for bmp files. We use a + // third party class to save as bmp. + { + // *** Perform a check or two. + if (!is_resource($this->imageResized) && !$this->imageResized instanceof GdImage) { + if ($this->debug) { + throw new Exception('saveImage: This is not a resource.'); + } + + throw new Exception(); + } + $fileInfoArray = pathinfo($savePath); + clearstatcache(); + if (!is_writable($fileInfoArray['dirname'])) { + if ($this->debug) { + throw new Exception('The path is not writable. Please check your permissions.'); + } + + throw new Exception(); + } + + // *** Get extension + $extension = strrchr($savePath, '.'); + $extension = fix_strtolower($extension); + + $error = ''; + + switch ($extension) { + case '.jpg': + case '.jpeg': + $this->checkInterlaceImage($this->isInterlace); + if (imagetypes() & \IMG_JPG) { + imagejpeg($this->imageResized, $savePath, $imageQuality); + } else { + $error = 'jpg'; + } + break; + case '.gif': + $this->checkInterlaceImage($this->isInterlace); + if (imagetypes() & \IMG_GIF) { + imagegif($this->imageResized, $savePath); + } else { + $error = 'gif'; + } + break; + case '.png': + // *** Scale quality from 0-100 to 0-9 + $scaleQuality = round(($imageQuality / 100) * 9); + + // *** Invert qualit setting as 0 is best, not 9 + $invertScaleQuality = 9 - $scaleQuality; + + $this->checkInterlaceImage($this->isInterlace); + if (imagetypes() & \IMG_PNG) { + imagepng($this->imageResized, $savePath, $invertScaleQuality); + } else { + $error = 'png'; + } + break; + case '.bmp': + file_put_contents($savePath, $this->GD2BMPstring($this->imageResized)); + break; + // ... etc + + default: + // *** No extension - No save. + $this->errorArray[] = 'This file type ('.$extension.') is not supported. File not saved.'; + break; + } + + // imagedestroy($this->imageResized); + + // *** Display error if a file type is not supported. + if ($error != '') { + $this->errorArray[] = $error.' support is NOT enabled. File not saved.'; + } + } + + // # -------------------------------------------------------- + + public function displayImage($fileType = 'jpg', $imageQuality = '100'): void + // Author: Jarrod Oberto + // Date: 18-11-09 + // Purpose: Display images directly to the browser + // Param in: The image type you want to display + // Param out: + // Reference: + // Notes: + // + { + if (!is_resource($this->imageResized)) { + if ($this->debug) { + throw new Exception('saveImage: This is not a resource.'); + } + + throw new Exception(); + } + + switch ($fileType) { + case 'jpg': + case 'jpeg': + header('Content-type: image/jpeg'); + imagejpeg($this->imageResized, '', $imageQuality); + break; + case 'gif': + header('Content-type: image/gif'); + imagegif($this->imageResized); + break; + case 'png': + header('Content-type: image/png'); + + // *** Scale quality from 0-100 to 0-9 + $scaleQuality = round(($imageQuality / 100) * 9); + + // *** Invert qualit setting as 0 is best, not 9 + $invertScaleQuality = 9 - $scaleQuality; + + imagepng($this->imageResized, '', $invertScaleQuality); + break; + case 'bmp': + echo 'bmp file format is not supported.'; + break; + // ... etc + + default: + // *** No extension - No save. + break; + } + + // imagedestroy($this->imageResized); + } + + // # -------------------------------------------------------- + + public function setTransparency($bool): void + // Sep 2011 + { + $this->keepTransparency = $bool; + } + + // # -------------------------------------------------------- + + public function setFillColor($value): void + // Sep 2011 + // Param in: (mixed) $value: (array) Could be an array of RGB + // (str) Could be hex #ffffff or #fff, fff, ffffff + // + // If the keepTransparency is set to false, then no transparency is to be used. + // This is ideal when you want to save as jpg. + // + // this method allows you to set the background color to use instead of + // transparency. + // + { + $colorArray = $this->formatColor($value); + $this->fillColorArray = $colorArray; + } + + // # -------------------------------------------------------- + + public function setCropFromTop($value): void + // Sep 2011 + { + $this->cropFromTopPercent = $value; + } + + // # -------------------------------------------------------- + + public function testGDInstalled() + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Test to see if GD is installed + // Param in: n/a + // Param out: (bool) True is gd extension loaded otherwise false + // Reference: + // Notes: + // + { + if (extension_loaded('gd') && function_exists('gd_info')) { + $gdInstalled = true; + } else { + $gdInstalled = false; + } + + return $gdInstalled; + } + + // # -------------------------------------------------------- + + public function testEXIFInstalled() + // Author: Jarrod Oberto + // Date: 08-05-11 + // Purpose: Test to see if EXIF is installed + // Param in: n/a + // Param out: (bool) True is exif extension loaded otherwise false + // Reference: + // Notes: + // + { + if (extension_loaded('exif')) { + $exifInstalled = true; + } else { + $exifInstalled = false; + } + + return $exifInstalled; + } + + // # -------------------------------------------------------- + + public function testIsImage($image) + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Test if file is an image + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // + { + if ($image) { + $fileIsImage = true; + } else { + $fileIsImage = false; + } + + return $fileIsImage; + } + + // # -------------------------------------------------------- + + public function testFunct(): void + // Author: Jarrod Oberto + // Date: 27-02-08 + // Purpose: Test Function + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // + { + echo $this->height; + } + + // # -------------------------------------------------------- + + public function setForceStretch($value): void + // Author: Jarrod Oberto + // Date: 23-12-10 + // Purpose: + // Param in: (bool) $value + // Param out: n/a + // Reference: + // Notes: + // + { + $this->forceStretch = $value; + } + + // # -------------------------------------------------------- + + public function setFile($fileName): void + // Author: Jarrod Oberto + // Date: 28-02-08 + // Purpose: + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // + { + self::__construct($fileName); + } + + // # -------------------------------------------------------- + + public function getFileName() + // Author: Jarrod Oberto + // Date: 10-09-08 + // Purpose: + // Param in: n/a + // Param out: n/a + // Reference: + // Notes: + // + { + return $this->fileName; + } + + // # -------------------------------------------------------- + + public function getHeight() + { + return $this->height; + } + + // # -------------------------------------------------------- + + public function getWidth() + { + return $this->width; + } + + // # -------------------------------------------------------- + + public function getOriginalHeight() + { + return $this->heightOriginal; + } + + // # -------------------------------------------------------- + + public function getOriginalWidth() + { + return $this->widthOriginal; + } + + // # -------------------------------------------------------- + + public function getErrors() + // Author: Jarrod Oberto + // Date: 19-11-09 + // Purpose: Returns the error array + // Param in: n/a + // Param out: Array of errors + // Reference: + // Notes: + // + { + return $this->errorArray; + } + + // # -------------------------------------------------------- + + private function checkInterlaceImage($isEnabled): void + // jpg will use progressive (they don't use interace) + { + if ($isEnabled) { + imageinterlace($this->imageResized, $isEnabled); + } + } + + // # -------------------------------------------------------- + + protected function formatColor($value) + // Author: Jarrod Oberto + // Date: 09-05-11 + // Purpose: Determine color method passed in and return color as RGB + // Param in: (mixed) $value: (array) Could be an array of RGB + // (str) Could be hex #ffffff or #fff, fff, ffffff + // Param out: + // Reference: + // Notes: + // + { + $rgbArray = []; + + // *** If it's an array it should be R, G, B + if (is_array($value)) { + if (key($value) == 0 && count($value) == 3) { + $rgbArray['r'] = $value[0]; + $rgbArray['g'] = $value[1]; + $rgbArray['b'] = $value[2]; + } else { + $rgbArray = $value; + } + } else { + if (fix_strtolower($value) == 'transparent') { + $rgbArray = [ + 'r' => 255, + 'g' => 255, + 'b' => 255, + 'a' => 127, + ]; + } else { + // *** ...Else it should be hex. Let's make it RGB + $rgbArray = $this->hex2dec($value); + } + } + + return $rgbArray; + } + + // # -------------------------------------------------------- + + public function hex2dec($hex) + // Purpose: Convert #hex color to RGB + { + $color = str_replace('#', '', $hex); + + if (strlen($color) == 3) { + $color = $color.$color; + } + + $rgb = [ + 'r' => hexdec(substr($color, 0, 2)), + 'g' => hexdec(substr($color, 2, 2)), + 'b' => hexdec(substr($color, 4, 2)), + 'a' => 0, + ]; + + return $rgb; + } + + // # -------------------------------------------------------- + + private function createImageColor($colorArray) + { + $r = $colorArray['r']; + $g = $colorArray['g']; + $b = $colorArray['b']; + + return imagecolorallocate($this->imageResized, $r, $g, $b); + } + + // # -------------------------------------------------------- + + private function testColorExists($colorArray) + { + $r = $colorArray['r']; + $g = $colorArray['g']; + $b = $colorArray['b']; + + if (imagecolorexact($this->imageResized, $r, $g, $b) == -1) { + return false; + } + + return true; + } + + // # -------------------------------------------------------- + + private function findUnusedGreen() + // Purpose: We find a green color suitable to use like green-screen effect. + // Therefore, the color must not exist in the image. + { + $green = 255; + + do { + $greenChroma = [0, $green, 0]; + $colorArray = $this->formatColor($greenChroma); + $match = $this->testColorExists($colorArray); + --$green; + } while ($match == false && $green > 0); + + // *** If no match, just bite the bullet and use green value of 255 + if (!$match) { + $greenChroma = [0, $green, 0]; + } + + return $greenChroma; + } + + // # -------------------------------------------------------- + + private function findUnusedBlue() + // Purpose: We find a green color suitable to use like green-screen effect. + // Therefore, the color must not exist in the image. + { + $blue = 255; + + do { + $blueChroma = [0, 0, $blue]; + $colorArray = $this->formatColor($blueChroma); + $match = $this->testColorExists($colorArray); + --$blue; + } while ($match == false && $blue > 0); + + // *** If no match, just bite the bullet and use blue value of 255 + if (!$match) { + $blueChroma = [0, 0, $blue]; + } + + return $blueChroma; + } + + // # -------------------------------------------------------- + + private function invertTransparency($value, $originalMax, $invert = true) + // Purpose: This does two things: + // 1) Convert the range from 0-127 to 0-100 + // 2) Inverts value to 100 is not transparent while 0 is fully + // transparent (like Photoshop) + { + // *** Test max range + if ($value > $originalMax) { + $value = $originalMax; + } + + // *** Test min range + if ($value < 0) { + $value = 0; + } + + if ($invert) { + return $originalMax - (($value / 100) * $originalMax); + } + + return ($value / 100) * $originalMax; + } + + // # -------------------------------------------------------- + + private function transparentImage($src) + { + // *** making images with white bg transparent + $r1 = 0; + $g1 = 255; + $b1 = 0; + for ($x = 0; $x < imagesx($src); ++$x) { + for ($y = 0; $y < imagesy($src); ++$y) { + $color = imagecolorat($src, $x, $y); + $r = ($color >> 16) & 0xFF; + $g = ($color >> 8) & 0xFF; + $b = $color & 0xFF; + for ($i = 0; $i < 270; ++$i) { + // if ($r . $g . $b == ($r1 + $i) . ($g1 + $i) . ($b1 + $i)) { + if ($r == 0 && $g == 255 && $b == 0) { + // if ($g == 255) { + $trans_colour = imagecolorallocatealpha($src, 0, 0, 0, 127); + imagefill($src, $x, $y, $trans_colour); + } + } + } + } + + return $src; + } + + // # -------------------------------------------------------- + + public function checkStringStartsWith($needle, $haystack) + // Check if a string starts with a specific pattern + { + return substr($haystack, 0, strlen($needle)) == $needle; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + BMP SUPPORT (SAVING) - James Heinrich +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + private function GD2BMPstring(&$gd_image) + // Author: James Heinrich + // Purpose: Save file as type bmp + // Param in: The image canvas (passed as ref) + // Param out: + // Reference: + // Notes: This code was stripped out of two external files + // (phpthumb.bmp.php,phpthumb.functions.php) and added below to + // avoid dependancies. + // + { + $imageX = imagesx($gd_image); + $imageY = imagesy($gd_image); + + $BMP = ''; + for ($y = ($imageY - 1); $y >= 0; --$y) { + $thisline = ''; + for ($x = 0; $x < $imageX; ++$x) { + $argb = $this->GetPixelColor($gd_image, $x, $y); + $thisline .= chr($argb['blue']).chr($argb['green']).chr($argb['red']); + } + while (strlen($thisline) % 4) { + $thisline .= "\x00"; + } + $BMP .= $thisline; + } + + $bmpSize = strlen($BMP) + 14 + 40; + // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp + $BITMAPFILEHEADER = 'BM'; // WORD bfType; + $BITMAPFILEHEADER .= $this->LittleEndian2String($bmpSize, 4); // DWORD bfSize; + $BITMAPFILEHEADER .= $this->LittleEndian2String(0, 2); // WORD bfReserved1; + $BITMAPFILEHEADER .= $this->LittleEndian2String(0, 2); // WORD bfReserved2; + $BITMAPFILEHEADER .= $this->LittleEndian2String(54, 4); // DWORD bfOffBits; + + // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp + $BITMAPINFOHEADER = $this->LittleEndian2String(40, 4); // DWORD biSize; + $BITMAPINFOHEADER .= $this->LittleEndian2String($imageX, 4); // LONG biWidth; + $BITMAPINFOHEADER .= $this->LittleEndian2String($imageY, 4); // LONG biHeight; + $BITMAPINFOHEADER .= $this->LittleEndian2String(1, 2); // WORD biPlanes; + $BITMAPINFOHEADER .= $this->LittleEndian2String(24, 2); // WORD biBitCount; + $BITMAPINFOHEADER .= $this->LittleEndian2String(0, 4); // DWORD biCompression; + $BITMAPINFOHEADER .= $this->LittleEndian2String(0, 4); // DWORD biSizeImage; + $BITMAPINFOHEADER .= $this->LittleEndian2String(2835, 4); // LONG biXPelsPerMeter; + $BITMAPINFOHEADER .= $this->LittleEndian2String(2835, 4); // LONG biYPelsPerMeter; + $BITMAPINFOHEADER .= $this->LittleEndian2String(0, 4); // DWORD biClrUsed; + $BITMAPINFOHEADER .= $this->LittleEndian2String(0, 4); // DWORD biClrImportant; + + return $BITMAPFILEHEADER.$BITMAPINFOHEADER.$BMP; + } + + // # -------------------------------------------------------- + + private function GetPixelColor(&$img, $x, $y) + // Author: James Heinrich + // Purpose: + // Param in: + // Param out: + // Reference: + // Notes: + // + { + if (!is_resource($img)) { + return false; + } + + return @imagecolorsforindex($img, @imagecolorat($img, $x, $y)); + } + + // # -------------------------------------------------------- + + private function LittleEndian2String($number, $minbytes = 1) + // Author: James Heinrich + // Purpose: BMP SUPPORT (SAVING) + // Param in: + // Param out: + // Reference: + // Notes: + // + { + $intstring = ''; + while ($number > 0) { + $intstring = $intstring.chr($number & 255); + $number >>= 8; + } + + return str_pad($intstring, $minbytes, "\x00", \STR_PAD_RIGHT); + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + BMP SUPPORT (READING) +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + private function ImageCreateFromBMP($filename) + // Author: DHKold + // Date: The 15th of June 2005 + // Version: 2.0B + // Purpose: To create an image from a BMP file. + // Param in: BMP file to open. + // Param out: Return a resource like the other ImageCreateFrom functions + // Reference: http://us3.php.net/manual/en/function.imagecreate.php#53879 + // Bug fix: Author: domelca at terra dot es + // Date: 06 March 2008 + // Fix: Correct 16bit BMP support + // Notes: + // + { + // Ouverture du fichier en mode binaire + if (!$f1 = fopen($filename, 'r')) { + return false; + } + + // 1 : Chargement des ent�tes FICHIER + $FILE = unpack('vfile_type/Vfile_size/Vreserved/Vbitmap_offset', fread($f1, 14)); + if ($FILE['file_type'] != 19778) { + return false; + } + + // 2 : Chargement des ent�tes BMP + $BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'. + '/Vcompression/Vsize_bitmap/Vhoriz_resolution'. + '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1, 40)); + $BMP['colors'] = 2 ** $BMP['bits_per_pixel']; + + if ($BMP['size_bitmap'] == 0) { + $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset']; + } + + $BMP['bytes_per_pixel'] = $BMP['bits_per_pixel'] / 8; + $BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']); + $BMP['decal'] = ($BMP['width'] * $BMP['bytes_per_pixel'] / 4); + $BMP['decal'] -= floor($BMP['width'] * $BMP['bytes_per_pixel'] / 4); + $BMP['decal'] = 4 - (4 * $BMP['decal']); + + if ($BMP['decal'] == 4) { + $BMP['decal'] = 0; + } + + // 3 : Chargement des couleurs de la palette + $PALETTE = []; + if ($BMP['colors'] < 16777216) { + $PALETTE = unpack('V'.$BMP['colors'], fread($f1, $BMP['colors'] * 4)); + } + + // 4 : Cr�ation de l'image + $IMG = fread($f1, $BMP['size_bitmap']); + $VIDE = chr(0); + + $res = imagecreatetruecolor($BMP['width'], $BMP['height']); + $P = 0; + $Y = $BMP['height'] - 1; + while ($Y >= 0) { + $X = 0; + while ($X < $BMP['width']) { + if ($BMP['bits_per_pixel'] == 24) { + $COLOR = unpack('V', substr($IMG, $P, 3).$VIDE); + } elseif ($BMP['bits_per_pixel'] == 16) { + /* + * BMP 16bit fix + * ================= + * + * Ref: http://us3.php.net/manual/en/function.imagecreate.php#81604 + * + * Notes: + * "don't work with bmp 16 bits_per_pixel. change pixel + * generator for this." + * + */ + + // *** Original code (don't work) + // $COLOR = unpack("n",substr($IMG,$P,2)); + // $COLOR[1] = $PALETTE[$COLOR[1]+1]; + + $COLOR = unpack('v', substr($IMG, $P, 2)); + $blue = ($COLOR[1] & 0x001F) << 3; + $green = ($COLOR[1] & 0x07E0) >> 3; + $red = ($COLOR[1] & 0xF800) >> 8; + $COLOR[1] = $red * 65536 + $green * 256 + $blue; + } elseif ($BMP['bits_per_pixel'] == 8) { + $COLOR = unpack('n', $VIDE.substr($IMG, $P, 1)); + $COLOR[1] = $PALETTE[$COLOR[1] + 1]; + } elseif ($BMP['bits_per_pixel'] == 4) { + $COLOR = unpack('n', $VIDE.substr($IMG, floor($P), 1)); + if (($P * 2) % 2 == 0) { + $COLOR[1] = ($COLOR[1] >> 4); + } else { + $COLOR[1] = ($COLOR[1] & 0x0F); + } + $COLOR[1] = $PALETTE[$COLOR[1] + 1]; + } elseif ($BMP['bits_per_pixel'] == 1) { + $COLOR = unpack('n', $VIDE.substr($IMG, floor($P), 1)); + if (($P * 8) % 8 == 0) { + $COLOR[1] = $COLOR[1] >> 7; + } elseif (($P * 8) % 8 == 1) { + $COLOR[1] = ($COLOR[1] & 0x40) >> 6; + } elseif (($P * 8) % 8 == 2) { + $COLOR[1] = ($COLOR[1] & 0x20) >> 5; + } elseif (($P * 8) % 8 == 3) { + $COLOR[1] = ($COLOR[1] & 0x10) >> 4; + } elseif (($P * 8) % 8 == 4) { + $COLOR[1] = ($COLOR[1] & 0x8) >> 3; + } elseif (($P * 8) % 8 == 5) { + $COLOR[1] = ($COLOR[1] & 0x4) >> 2; + } elseif (($P * 8) % 8 == 6) { + $COLOR[1] = ($COLOR[1] & 0x2) >> 1; + } elseif (($P * 8) % 8 == 7) { + $COLOR[1] = ($COLOR[1] & 0x1); + } + $COLOR[1] = $PALETTE[$COLOR[1] + 1]; + } else { + return false; + } + + imagesetpixel($res, $X, $Y, $COLOR[1]); + ++$X; + $P += $BMP['bytes_per_pixel']; + } + + --$Y; + $P += $BMP['decal']; + } + // Fermeture du fichier + fclose($f1); + + return $res; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*- + PSD SUPPORT (READING) +*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + private function imagecreatefrompsd($fileName) + // Author: Tim de Koning + // Version: 1.3 + // Purpose: To create an image from a PSD file. + // Param in: PSD file to open. + // Param out: Return a resource like the other ImageCreateFrom functions + // Reference: http://www.kingsquare.nl/phppsdreader + // Notes: + // + { + if (file_exists($this->psdReaderPath)) { + include_once $this->psdReaderPath; + + $psdReader = new PhpPsdReader($fileName); + + if (isset($psdReader->infoArray['error'])) { + return ''; + } + + return $psdReader->getImage(); + } + + return false; + } + + // # -------------------------------------------------------- + + public function __destruct() + { + if (is_resource($this->imageResized)) { + imagedestroy($this->imageResized); + } + } + + // # -------------------------------------------------------- +} + +/* + * Example with some API calls (outdated): + * + * + * =============================== + * Compulsary + * =============================== + * + * include("classes/resize_class.php"); + * + * // *** Initialise object + * $magicianObj = new resize('images/cars/large/a.jpg'); + * + * // *** Turn off stretching (optional) + * $magicianObj -> setForceStretch(false); + * + * // *** Resize object + * $magicianObj -> resizeImage(150, 100, 0); + * + * =============================== + * Image options - can run none, one, or all. + * =============================== + * + * // *** Add watermark + * $magicianObj -> addWatermark('stamp.png'); + * + * // *** Add text + * $magicianObj -> addText('testing...'); + * + * =============================== + * Output options - can run one, or the other, or both. + * =============================== + * + * // *** Save image to disk + * $magicianObj -> saveImage('images/cars/large/b.jpg', 100); + * + * // *** Or output to screen (params in can be jpg, gif, png) + * $magicianObj -> displayImage('png'); + * + * =============================== + * Return options - return errors. nice for debuggin. + * =============================== + * + * // *** Return error array + * $errorArray = $magicianObj -> getErrors(); + * + * + * =============================== + * Cleanup options - not really neccessary, but good practice + * =============================== + * + * // *** Free used memory + * $magicianObj -> __destruct(); + */ diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/utils.php b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/utils.php new file mode 100755 index 0000000..7fbb4f2 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/include/utils.php @@ -0,0 +1,1038 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if ($_SESSION['RF']['verify'] != 'RESPONSIVEfilemanager') { + exit('forbiden'); +} +require __DIR__.'/Response.php'; + +if (!function_exists('response')) { + /** + * Response construction helper. + * + * @param string $content + * @param int $statusCode + * @param array $headers + * + * @return \Response|\Illuminate\Http\Response + */ + function response($content = '', $statusCode = 200, $headers = []) + { + $responseClass = class_exists('Illuminate\Http\Response') ? '\Illuminate\Http\Response' : 'Response'; + + return new $responseClass($content, $statusCode, $headers); + } +} + +if (!function_exists('trans')) { + // language + if (!isset($_SESSION['RF']['language']) + || file_exists('lang/'.basename($_SESSION['RF']['language']).'.php') === false + || !is_readable('lang/'.basename($_SESSION['RF']['language']).'.php') + ) { + $lang = $default_language; + + if (isset($_GET['lang']) && $_GET['lang'] != 'undefined' && $_GET['lang'] != '') { + $lang = fix_get_params($_GET['lang']); + $lang = trim($lang); + } + + if ($lang != $default_language) { + $path_parts = pathinfo($lang); + $lang = $path_parts['basename']; + $languages = include 'lang/languages.php'; + } + + // add lang file to session for easy include + $_SESSION['RF']['language'] = $lang; + } else { + if (file_exists('lang/languages.php')) { + $languages = include 'lang/languages.php'; + } else { + $languages = include '../lang/languages.php'; + } + + if (array_key_exists($_SESSION['RF']['language'], $languages)) { + $lang = $_SESSION['RF']['language']; + } else { + response(trans('Lang_Not_Found').AddErrorLocation())->send(); + exit; + } + } + if (file_exists('lang/'.$lang.'.php')) { + $lang_vars = include 'lang/'.$lang.'.php'; + } else { + $lang_vars = include '../lang/'.$lang.'.php'; + } + + if (!is_array($lang_vars)) { + $lang_vars = []; + } + /** + * Translate language variable. + * + * @param $var string name + * + * @return string translated variable + */ + function trans($var) + { + global $lang_vars; + + return (array_key_exists($var, $lang_vars)) ? $lang_vars[$var] : $var; + } +} + +/** + * Delete directory. + * + * @param string $dir + * + * @return bool + */ +function deleteDir($dir, $ftp = null, $config = null) +{ + if ($ftp) { + try { + $ftp->rmdir($dir); + + return true; + } catch (FtpClient\FtpException $e) { + return null; + } + } else { + if (!file_exists($dir)) { + return false; + } + if (!is_dir($dir)) { + return unlink($dir); + } + foreach (scandir($dir) as $item) { + if ($item == '.' || $item == '..') { + continue; + } + if (!deleteDir($dir.\DIRECTORY_SEPARATOR.$item)) { + return false; + } + } + } + + return rmdir($dir); +} + +/** + * Make a file copy. + * + * @param string $old_path + * @param string $name New file name without extension + * + * @return bool + */ +function duplicate_file($old_path, $name, $ftp = null, $config = null) +{ + $info = pathinfo($old_path); + $new_path = $info['dirname'].'/'.$name.'.'.$info['extension']; + if ($ftp) { + try { + $tmp = time().$name.'.'.$info['extension']; + $ftp->get($tmp, '/'.$old_path, \FTP_BINARY); + $ftp->put('/'.$new_path, $tmp, \FTP_BINARY); + unlink($tmp); + + return true; + } catch (FtpClient\FtpException $e) { + return null; + } + } else { + if (file_exists($old_path)) { + if (file_exists($new_path) && $old_path == $new_path) { + return false; + } + + return copy($old_path, $new_path); + } + } +} + +/** + * Rename file. + * + * @param string $old_path File to rename + * @param string $name New file name without extension + * + * @return bool + */ +function rename_file($old_path, $name, $ftp = null, $config = null) +{ + $name = fix_filename($name, $config); + $info = pathinfo($old_path); + $new_path = $info['dirname'].'/'.$name.'.'.$info['extension']; + if ($ftp) { + try { + return $ftp->rename('/'.$old_path, '/'.$new_path); + } catch (FtpClient\FtpException $e) { + return false; + } + } else { + if (file_exists($old_path)) { + $new_path = $info['dirname'].'/'.$name.'.'.$info['extension']; + if (file_exists($new_path) && $old_path == $new_path) { + return false; + } + + return rename($old_path, $new_path); + } + } +} + +function url_exists($url) +{ + if (!$fp = curl_init($url)) { + return false; + } + + return true; +} + +function tempdir() +{ + $tempfile = tempnam(sys_get_temp_dir(), ''); + if (file_exists($tempfile)) { + unlink($tempfile); + } + mkdir($tempfile); + if (is_dir($tempfile)) { + return $tempfile; + } +} + +/** + * Rename directory. + * + * @param string $old_path Directory to rename + * @param string $name New directory name + * + * @return bool + */ +function rename_folder($old_path, $name, $ftp = null, $config = null) +{ + $name = fix_filename($name, $config, true); + $new_path = fix_dirname($old_path).'/'.$name; + if ($ftp) { + if ($ftp->chdir('/'.$old_path)) { + if (@$ftp->chdir($new_path)) { + return false; + } + + return $ftp->rename('/'.$old_path, '/'.$new_path); + } + } else { + if (file_exists($old_path)) { + if (file_exists($new_path) && $old_path == $new_path) { + return false; + } + + return rename($old_path, $new_path); + } + } +} + +function ftp_con($config) +{ + if (isset($config['ftp_host']) && $config['ftp_host']) { + // *** Include the class + include 'include/FtpClient.php'; + include 'include/FtpException.php'; + include 'include/FtpWrapper.php'; + + $ftp = new \FtpClient\FtpClient(); + try { + $ftp->connect($config['ftp_host'], $config['ftp_ssl'], $config['ftp_port']); + $ftp->login($config['ftp_user'], $config['ftp_pass']); + $ftp->pasv(true); + + return $ftp; + } catch (FtpClient\FtpException $e) { + echo 'Error: '; + echo $e->getMessage(); + echo ' to server '; + $tmp = $e->getTrace(); + echo $tmp[0]['args'][0]; + echo '
Please check configurations'; + exit; + } + } else { + return false; + } +} + +/** + * Create new image from existing file. + * + * @param string $imgfile Source image file name + * @param string $imgthumb Thumbnail file name + * @param int $newwidth Thumbnail width + * @param int $newheight Optional thumbnail height + * @param string $option Type of resize + * + * @return bool + * + * @throws \Exception + */ +function create_img($imgfile, $imgthumb, $newwidth, $newheight = null, $option = 'crop', $ftp = false, $config = []) +{ + $result = false; + if ($ftp) { + if (url_exists($imgfile)) { + $temp = tempnam('/tmp', 'RF'); + unlink($temp); + $temp .= '.'.substr(strrchr($imgfile, '.'), 1); + $handle = fopen($temp, 'w'); + fwrite($handle, file_get_contents($imgfile)); + fclose($handle); + $imgfile = $temp; + $save_ftp = $imgthumb; + $imgthumb = $temp; + } + } + if (file_exists($imgfile) || strpos($imgfile, 'http') === 0) { + if (strpos($imgfile, 'http') === 0 || image_check_memory_usage($imgfile, $newwidth, $newheight)) { + require_once 'php_image_magician.php'; + $magicianObj = new php_image_magician($imgfile); + $magicianObj->resizeImage($newwidth, $newheight, $option); + $magicianObj->saveImage($imgthumb, 80); + $result = true; + } + } + if ($result && $ftp) { + $ftp->put($save_ftp, $imgthumb, \FTP_BINARY); + unlink($imgthumb); + } + + return $result; +} + +/** + * Convert convert size in bytes to human readable. + * + * @param int $size + * + * @return string + */ +function makeSize($size) +{ + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $u = 0; + while ((round($size / 1024) > 0) && ($u < 4)) { + $size = $size / 1024; + ++$u; + } + + return number_format($size, 0).' '.trans($units[$u]); +} + +/** + * Determine directory size. + * + * @param string $path + * + * @return int + */ +function folder_info($path, $count_hidden = true) +{ + global $hidden_folders,$hidden_files; + $total_size = 0; + $files = scandir($path); + $cleanPath = rtrim($path, '/').'/'; + $files_count = 0; + $folders_count = 0; + foreach ($files as $t) { + if ($t != '.' && $t != '..') { + if ($count_hidden || !(in_array($t, $hidden_folders) || in_array($t, $hidden_files))) { + $currentFile = $cleanPath.$t; + if (is_dir($currentFile)) { + [$size,$tmp,$tmp1] = folder_info($currentFile); + $total_size += $size; + ++$folders_count; + } else { + $size = filesize($currentFile); + $total_size += $size; + ++$files_count; + } + } + } + } + + return [$total_size, $files_count, $folders_count]; +} +/** + * Get number of files in a directory. + * + * @param string $path + * + * @return int + */ +function filescount($path, $count_hidden = true) +{ + global $hidden_folders,$hidden_files; + $total_count = 0; + $files = scandir($path); + $cleanPath = rtrim($path, '/').'/'; + + foreach ($files as $t) { + if ($t != '.' && $t != '..') { + if ($count_hidden || !(in_array($t, $hidden_folders) || in_array($t, $hidden_files))) { + $currentFile = $cleanPath.$t; + if (is_dir($currentFile)) { + $size = filescount($currentFile); + $total_count += $size; + } else { + ++$total_count; + } + } + } + } + + return $total_count; +} +/** + * check if the current folder size plus the added size is over the overall size limite. + * + * @param int $sizeAdded + * + * @return bool + */ +function checkresultingsize($sizeAdded) +{ + global $MaxSizeTotal,$current_path; + if ($MaxSizeTotal !== false && is_int($MaxSizeTotal)) { + [$sizeCurrentFolder,$fileCurrentNum,$foldersCurrentCount] = folder_info($current_path, false); + // overall size over limit + if (($MaxSizeTotal * 1024 * 1024) < ($sizeCurrentFolder + $sizeAdded)) { + return false; + } + } + + return true; +} + +/** + * Create directory for images and/or thumbnails. + * + * @param string $path + * @param string $path_thumbs + */ +function create_folder($path = null, $path_thumbs = null, $ftp = null, $config = null): void +{ + if ($ftp) { + $ftp->mkdir($path); + $ftp->mkdir($path_thumbs); + } else { + $oldumask = umask(0); + if ($path && !file_exists($path)) { + mkdir($path, 0755, true); + } // or even 01777 so you get the sticky bit set + if ($path_thumbs && !file_exists($path_thumbs)) { + mkdir($path_thumbs, 0755, true) || exit("$path_thumbs cannot be found"); + } // or even 01777 so you get the sticky bit set + umask($oldumask); + } +} + +/** + * Get file extension present in directory. + * + * @param string $path + * @param string $ext + */ +function check_files_extensions_on_path($path, $ext): void +{ + if (!is_dir($path)) { + $fileinfo = pathinfo($path); + if (!in_array(mb_strtolower($fileinfo['extension']), $ext)) { + unlink($path); + } + } else { + $files = scandir($path); + foreach ($files as $file) { + check_files_extensions_on_path(trim($path, '/').'/'.$file, $ext); + } + } +} + +/** + * Get file extension present in PHAR file. + * + * @param string $phar + * @param array $files + * @param string $basepath + * @param string $ext + */ +function check_files_extensions_on_phar($phar, &$files, $basepath, $ext): void +{ + foreach ($phar as $file) { + if ($file->isFile()) { + if (in_array(mb_strtolower($file->getExtension()), $ext)) { + $files[] = $basepath.$file->getFileName(); + } + } else { + if ($file->isDir()) { + $iterator = new DirectoryIterator($file); + check_files_extensions_on_phar($iterator, $files, $basepath.$file->getFileName().'/', $ext); + } + } + } +} + +/** + * Cleanup input. + * + * @param string $str + * + * @return string + */ +function fix_get_params($str) +{ + return strip_tags(preg_replace("/[^a-zA-Z0-9\.\[\]_| -]/", '', $str)); +} + +/** + * Cleanup filename. + * + * @param string $str + * @param bool $is_folder + * + * @return string + */ +function fix_filename($str, $config, $is_folder = false) +{ + if ($config['convert_spaces']) { + $str = str_replace(' ', $config['replace_with'], $str); + } + + if ($config['transliteration']) { + if (!mb_detect_encoding($str, 'UTF-8', true)) { + $str = utf8_encode($str); + } + if (function_exists('transliterator_transliterate')) { + $str = transliterator_transliterate('Any-Latin; Latin-ASCII', $str); + } else { + $str = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $str); + } + + $str = preg_replace("/[^a-zA-Z0-9\.\[\]_| -]/", '', $str); + } + + $str = str_replace(['"', "'", '/', '\\'], '', $str); + $str = strip_tags($str); + + // Empty or incorrectly transliterated filename. + // Here is a point: a good file UNKNOWN_LANGUAGE.jpg could become .jpg in previous code. + // So we add that default 'file' name to fix that issue. + if (strpos($str, '.') === 0 && $is_folder === false) { + $str = 'file'.$str; + } + + return trim($str); +} + +/** + * Cleanup directory name. + * + * @param string $str + * + * @return string + */ +function fix_dirname($str) +{ + return str_replace('~', ' ', dirname(str_replace(' ', '~', $str))); +} + +/** + * Correct strtoupper handling. + * + * @param string $str + * + * @return string + */ +function fix_strtoupper($str) +{ + if (function_exists('mb_strtoupper')) { + return mb_strtoupper($str); + } + + return strtoupper($str); +} + +/** + * Correct strtolower handling. + * + * @param string $str + * + * @return string + */ +function fix_strtolower($str) +{ + if (function_exists('mb_strtoupper')) { + return mb_strtolower($str); + } + + return strtolower($str); +} + +function fix_path($path, $config) +{ + $info = pathinfo($path); + $tmp_path = $info['dirname']; + $str = fix_filename($info['filename'], $config); + if ($tmp_path != '') { + return $tmp_path.\DIRECTORY_SEPARATOR.$str; + } + + return $str; +} + +/** + * @param $current_path + * @param $fld + * + * @return bool + */ +function config_loading($current_path, $fld) +{ + if (file_exists($current_path.$fld.'.config')) { + require_once $current_path.$fld.'.config'; + + return true; + } + echo '!!!!'.$parent = fix_dirname($fld); + if ($parent != '.' && !empty($parent)) { + config_loading($current_path, $parent); + } + + return false; +} + +/** + * Check if memory is enough to process image. + * + * @param string $img + * @param int $max_breedte + * @param int $max_hoogte + * + * @return bool + */ +function image_check_memory_usage($img, $max_breedte, $max_hoogte) +{ + if (file_exists($img)) { + $K64 = 65536; // number of bytes in 64K + $memory_usage = memory_get_usage(); + $memory_limit = abs((int) (str_replace('M', '', ini_get('memory_limit')) * 1024 * 1024)); + $image_properties = getimagesize($img); + $image_width = $image_properties[0] ?? 0; + $image_height = $image_properties[1] ?? 0; + if (isset($image_properties['bits'])) { + $image_bits = $image_properties['bits']; + } else { + $image_bits = 0; + } + $image_memory_usage = $K64 + ($image_width * $image_height * $image_bits * 2); + $thumb_memory_usage = $K64 + ($max_breedte * $max_hoogte * $image_bits * 2); + $memory_needed = abs((int) ($memory_usage + $image_memory_usage + $thumb_memory_usage)); + + if ($memory_needed > $memory_limit) { + return false; + } + + return true; + } + + return false; +} + +/** + * Check is string is ended with needle. + * + * @param string $haystack + * @param string $needle + * + * @return bool + */ +function endsWith($haystack, $needle) +{ + return $needle === '' || substr($haystack, -strlen($needle)) === $needle; +} + +/** + * TODO REFACTOR THIS! + * + * @param $targetPath + * @param $targetFile + * @param $name + * @param $current_path + * @param $relative_image_creation + * @param $relative_path_from_current_pos + * @param $relative_image_creation_name_to_prepend + * @param $relative_image_creation_name_to_append + * @param $relative_image_creation_width + * @param $relative_image_creation_height + * @param $relative_image_creation_option + * @param $fixed_image_creation + * @param $fixed_path_from_filemanager + * @param $fixed_image_creation_name_to_prepend + * @param $fixed_image_creation_to_append + * @param $fixed_image_creation_width + * @param $fixed_image_creation_height + * @param $fixed_image_creation_option + * + * @return bool + */ +function new_thumbnails_creation($targetPath, $targetFile, $name, $current_path, $relative_image_creation, $relative_path_from_current_pos, $relative_image_creation_name_to_prepend, $relative_image_creation_name_to_append, $relative_image_creation_width, $relative_image_creation_height, $relative_image_creation_option, $fixed_image_creation, $fixed_path_from_filemanager, $fixed_image_creation_name_to_prepend, $fixed_image_creation_to_append, $fixed_image_creation_width, $fixed_image_creation_height, $fixed_image_creation_option) +{ + // create relative thumbs + $all_ok = true; + if ($relative_image_creation) { + foreach ($relative_path_from_current_pos as $k => $path) { + if ($path != '' && $path[strlen($path) - 1] != '/') { + $path .= '/'; + } + if (!file_exists($targetPath.$path)) { + create_folder($targetPath.$path, false); + } + $info = pathinfo($name); + if (!endsWith($targetPath, $path)) { + if (!create_img($targetFile, $targetPath.$path.$relative_image_creation_name_to_prepend[$k].$info['filename'].$relative_image_creation_name_to_append[$k].'.'.$info['extension'], $relative_image_creation_width[$k], $relative_image_creation_height[$k], $relative_image_creation_option[$k])) { + $all_ok = false; + } + } + } + } + + // create fixed thumbs + if ($fixed_image_creation) { + foreach ($fixed_path_from_filemanager as $k => $path) { + if ($path != '' && $path[strlen($path) - 1] != '/') { + $path .= '/'; + } + $base_dir = $path.substr_replace($targetPath, '', 0, strlen($current_path)); + if (!file_exists($base_dir)) { + create_folder($base_dir, false); + } + $info = pathinfo($name); + if (!create_img($targetFile, $base_dir.$fixed_image_creation_name_to_prepend[$k].$info['filename'].$fixed_image_creation_to_append[$k].'.'.$info['extension'], $fixed_image_creation_width[$k], $fixed_image_creation_height[$k], $fixed_image_creation_option[$k])) { + $all_ok = false; + } + } + } + + return $all_ok; +} + +/** + * Get a remote file, using whichever mechanism is enabled. + * + * @param string $url + * + * @return bool|mixed|string + */ +function get_file_by_url($url) +{ + if (ini_get('allow_url_fopen')) { + $arrContextOptions = [ + 'ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ], + ]; + + return file_get_contents($url, false, stream_context_create($arrContextOptions)); + } + if (!function_exists('curl_version')) { + return false; + } + + $ch = curl_init(); + + curl_setopt($ch, \CURLOPT_HEADER, 0); + curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, \CURLOPT_URL, $url); + + $data = curl_exec($ch); + curl_close($ch); + + return $data; +} + +/** + * test for dir/file writability properly. + * + * @param string $dir + * + * @return bool + */ +function is_really_writable($dir) +{ + $dir = rtrim($dir, '/'); + // linux, safe off + if (\DIRECTORY_SEPARATOR == '/' && @ini_get('safe_mode') == false) { + return is_writable($dir); + } + + // Windows, safe ON. (have to write a file :S) + if (is_dir($dir)) { + $dir = $dir.'/'.md5(random_int(1, 1000).random_int(1, 1000)); + + if (($fp = @fopen($dir, 'a')) === false) { + return false; + } + + fclose($fp); + @chmod($dir, 0755); + @unlink($dir); + + return true; + } + if (!is_file($dir) || ($fp = @fopen($dir, 'a')) === false) { + return false; + } + + fclose($fp); + + return true; +} + +/** + * Check if a function is callable. + * Some servers disable copy,rename etc. + * + * @parm string $name + * + * @return bool + */ +function is_function_callable($name) +{ + if (function_exists($name) === false) { + return false; + } + $disabled = explode(',', ini_get('disable_functions')); + + return !in_array($name, $disabled); +} + +/** + * recursivly copies everything. + * + * @param string $source + * @param string $destination + * @param bool $is_rec + */ +function rcopy($source, $destination, $is_rec = false): void +{ + if (is_dir($source)) { + if ($is_rec === false) { + $pinfo = pathinfo($source); + $destination = rtrim($destination, '/').\DIRECTORY_SEPARATOR.$pinfo['basename']; + } + if (is_dir($destination) === false) { + mkdir($destination, 0755, true); + } + + $files = scandir($source); + foreach ($files as $file) { + if ($file != '.' && $file != '..') { + rcopy($source.\DIRECTORY_SEPARATOR.$file, rtrim($destination, '/').\DIRECTORY_SEPARATOR.$file, true); + } + } + } else { + if (file_exists($source)) { + if (is_dir($destination) === true) { + $pinfo = pathinfo($source); + $dest2 = rtrim($destination, '/').\DIRECTORY_SEPARATOR.$pinfo['basename']; + } else { + $dest2 = $destination; + } + + copy($source, $dest2); + } + } +} + +/** + * recursivly renames everything. + * + * I know copy and rename could be done with just one function + * but i split the 2 because sometimes rename fails on windows + * Need more feedback from users and refactor if needed + * + * @param string $source + * @param string $destination + * @param bool $is_rec + */ +function rrename($source, $destination, $is_rec = false): void +{ + if (is_dir($source)) { + if ($is_rec === false) { + $pinfo = pathinfo($source); + $destination = rtrim($destination, '/').\DIRECTORY_SEPARATOR.$pinfo['basename']; + } + if (is_dir($destination) === false) { + mkdir($destination, 0755, true); + } + + $files = scandir($source); + foreach ($files as $file) { + if ($file != '.' && $file != '..') { + rrename($source.\DIRECTORY_SEPARATOR.$file, rtrim($destination, '/').\DIRECTORY_SEPARATOR.$file, true); + } + } + } else { + if (file_exists($source)) { + if (is_dir($destination) === true) { + $pinfo = pathinfo($source); + $dest2 = rtrim($destination, '/').\DIRECTORY_SEPARATOR.$pinfo['basename']; + } else { + $dest2 = $destination; + } + + rename($source, $dest2); + } + } +} + +// On windows rename leaves folders sometime +// This will clear leftover folders +// After more feedback will merge it with rrename +function rrename_after_cleaner($source) +{ + $files = scandir($source); + + foreach ($files as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($source.\DIRECTORY_SEPARATOR.$file)) { + rrename_after_cleaner($source.\DIRECTORY_SEPARATOR.$file); + } else { + unlink($source.\DIRECTORY_SEPARATOR.$file); + } + } + } + + return rmdir($source); +} + +/** + * Recursive chmod. + * + * @param string $source + * @param int $mode + * @param string $rec_option + * @param bool $is_rec + */ +function rchmod($source, $mode, $rec_option = 'none', $is_rec = false): void +{ + if ($rec_option == 'none') { + chmod($source, $mode); + } else { + if ($is_rec === false) { + chmod($source, $mode); + } + + $files = scandir($source); + + foreach ($files as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($source.\DIRECTORY_SEPARATOR.$file)) { + if ($rec_option == 'folders' || $rec_option == 'both') { + chmod($source.\DIRECTORY_SEPARATOR.$file, $mode); + } + rchmod($source.\DIRECTORY_SEPARATOR.$file, $mode, $rec_option, true); + } else { + if ($rec_option == 'files' || $rec_option == 'both') { + chmod($source.\DIRECTORY_SEPARATOR.$file, $mode); + } + } + } + } + } +} + +/** + * @param string $input + * @param bool $trace + * @param bool $halt + */ +function debugger($input, $trace = false, $halt = false): void +{ + ob_start(); + + echo '
----- DEBUG DUMP -----'; + echo '

';
+    var_dump($input);
+    echo '
'; + + if ($trace) { + if (is_php('5.3.6')) { + $debug = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + } else { + $debug = debug_backtrace(false); + } + + echo '
-----STACK TRACE-----'; + echo '
';
+        var_dump($debug);
+        echo '
'; + } + + echo ''; + echo '---------------------------
'; + + $ret = ob_get_contents(); + ob_end_clean(); + + echo $ret; + + if ($halt == true) { + exit; + } +} + +/** + * @param string $version + * + * @return bool + */ +function is_php($version = '5.0.0') +{ + static $phpVer; + $version = (string) $version; + + if (!isset($phpVer[$version])) { + $phpVer[$version] = (version_compare(\PHP_VERSION, $version) < 0) ? false : true; + } + + return $phpVer[$version]; +} + +/** + * Return the caller location if set in config.php. + * + * @return bool + */ +function AddErrorLocation() +{ + if (defined('DEBUG_ERROR_MESSAGE') && DEBUG_ERROR_MESSAGE) { + $pile = debug_backtrace(); + + return ' (@'.$pile[0]['file'].'#'.$pile[0]['line'].')'; + } + + return ''; +} diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/ZeroClipboard.swf b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/ZeroClipboard.swf new file mode 100644 index 0000000000000000000000000000000000000000..d4e2561b366e131d3bae303acce90a137a4956e1 GIT binary patch literal 4036 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 literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/include.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/include.js new file mode 100644 index 0000000..989b3ab --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/filemanager/js/include.js @@ -0,0 +1,2 @@ +var encodeURL,show_animation,hide_animation,apply,apply_none,apply_img,apply_any,apply_video,apply_link,apply_file_rename,apply_file_duplicate,apply_folder_rename;!function(e,a,r){"use strict";function t(e){show_animation();var a=new Image;a.src=e,jQuery(a).on("load",function(){hide_animation()})}function n(){jQuery("#textfile_create_area").parent().parent().remove(),e.ajax({type:"GET",url:"ajax_calls.php?action=new_file_form"}).done(function(a){bootbox.dialog(a,[{label:jQuery("#cancel").val(),"class":"btn"},{label:jQuery("#ok").val(),"class":"btn-inverse",callback:function(){var a=jQuery("#create_text_file_name").val()+jQuery("#create_text_file_extension").val(),r=jQuery("#textfile_create_area").val();if(null!==a){a=_(a);var t=jQuery("#sub_folder").val()+jQuery("#fldr_value").val();e.ajax({type:"POST",url:"execute.php?action=create_file",data:{path:t,name:a,new_content:r}}).done(function(e){""!=e&&bootbox.alert(e,function(){setTimeout(function(){window.location.href=jQuery("#refresh").attr("href")+"&"+(new Date).getTime()},500)})})}}}],{header:jQuery("#lang_new_file").val()})})}function i(a){jQuery("#textfile_edit_area").parent().parent().remove();var r=a.find(".rename-file-paths").attr("data-path");e.ajax({type:"POST",url:"ajax_calls.php?action=get_file&sub_action=edit&preview_mode=text",data:{path:r}}).done(function(t){bootbox.dialog(t,[{label:jQuery("#cancel").val(),"class":"btn"},{label:jQuery("#ok").val(),"class":"btn-inverse",callback:function(){var a=jQuery("#textfile_edit_area").val();e.ajax({type:"POST",url:"execute.php?action=save_text_file",data:{path:r,new_content:a}}).done(function(e){""!=e&&bootbox.alert(e)})}}],{header:a.find(".name_download").val()})})}function l(){e.ajax({type:"POST",url:"ajax_calls.php?action=get_lang",data:{}}).done(function(a){bootbox.dialog(a,[{label:jQuery("#cancel").val(),"class":"btn"},{label:jQuery("#ok").val(),"class":"btn-inverse",callback:function(){var a=jQuery("#new_lang_select").val();e.ajax({type:"POST",url:"ajax_calls.php?action=change_lang",data:{choosen_lang:a}}).done(function(e){""!=e?bootbox.alert(e):setTimeout(function(){window.location.href=jQuery("#refresh").attr("href").replace(/lang=[\w]*&/i,"lang="+a+"&")+"&"+(new Date).getTime()},100)})}}],{header:jQuery("#lang_lang_change").val()})})}function o(a){jQuery("#files_permission_start").parent().parent().remove();var r=a.find(".rename-file-paths"),t=r.attr("data-path"),n=r.attr("data-permissions"),i=r.attr("data-folder");e.ajax({type:"POST",url:"ajax_calls.php?action=chmod",data:{path:t,permissions:n,folder:i}}).done(function(a){bootbox.dialog(a,[{label:jQuery("#cancel").val(),"class":"btn"},{label:jQuery("#ok").val(),"class":"btn-inverse",callback:function(){var a="-";a+=jQuery("#u_4").is(":checked")?"r":"-",a+=jQuery("#u_2").is(":checked")?"w":"-",a+=jQuery("#u_1").is(":checked")?"x":"-",a+=jQuery("#g_4").is(":checked")?"r":"-",a+=jQuery("#g_2").is(":checked")?"w":"-",a+=jQuery("#g_1").is(":checked")?"x":"-",a+=jQuery("#a_4").is(":checked")?"r":"-",a+=jQuery("#a_2").is(":checked")?"w":"-",a+=jQuery("#a_1").is(":checked")?"x":"-";var n=jQuery("#chmod_form #chmod_value").val();if(""!=n&&"undefined"!=typeof n){var l=jQuery("#chmod_form input[name=apply_recursive]:checked").val();""!=l&&"undefined"!=typeof l||(l="none"),e.ajax({type:"POST",url:"execute.php?action=chmod",data:{path:t,new_mode:n,is_recursive:l,folder:i}}).done(function(e){""!=e?bootbox.alert(e):r.attr("data-permissions",a)})}}}],{header:jQuery("#lang_file_permission").val()}),setTimeout(function(){u(!1)},100)})}function u(a){var r=[];if(r.user=0,r.group=0,r.all=0,"undefined"!=typeof a&&1==a){var t=jQuery("#chmod_form #chmod_value").val();r.user=t.substr(0,1),r.group=t.substr(1,1),r.all=t.substr(2,1),e.each(r,function(a){(""==r[a]||0==e.isNumeric(r[a])||parseInt(r[a])<0||parseInt(r[a])>7)&&(r[a]="0")}),jQuery("#chmod_form input:checkbox").each(function(){var e=jQuery(this).attr("data-group"),a=jQuery(this).attr("data-value");c(r[e],a)?jQuery(this).prop("checked",!0):jQuery(this).prop("checked",!1)})}else jQuery("#chmod_form input:checkbox:checked").each(function(){var e=jQuery(this).attr("data-group"),a=jQuery(this).attr("data-value");r[e]=parseInt(r[e])+parseInt(a)}),jQuery("#chmod_form #chmod_value").val(r.user.toString()+r.group.toString()+r.all.toString())}function c(a,r){var t=[];return t[1]=[1,3,5,7],t[2]=[2,3,6,7],t[4]=[4,5,6,7],a=parseInt(a),r=parseInt(r),e.inArray(a,t[r])!=-1}function s(){bootbox.confirm(jQuery("#lang_clear_clipboard_confirm").val(),jQuery("#cancel").val(),jQuery("#ok").val(),function(a){1==a&&e.ajax({type:"POST",url:"ajax_calls.php?action=clear_clipboard",data:{}}).done(function(e){""!=e?bootbox.alert(e):jQuery("#clipboard").val("0"),y(!1)})})}function d(a,r){if("copy"==r||"cut"==r){var t;t=a.hasClass("directory")?a.find(".rename-file-paths").attr("data-path"):a.find(".rename-file-paths").attr("data-path"),e.ajax({type:"POST",url:"ajax_calls.php?action=copy_cut",data:{path:t,sub_action:r}}).done(function(e){""!=e?bootbox.alert(e):(jQuery("#clipboard").val("1"),y(!0))})}}function f(a){bootbox.confirm(jQuery("#lang_paste_confirm").val(),jQuery("#cancel").val(),jQuery("#ok").val(),function(r){if(1==r){var t;t="undefined"!=typeof a?a.find(".rename-folder").attr("data-path"):jQuery("#sub_folder").val()+jQuery("#fldr_value").val(),e.ajax({type:"POST",url:"execute.php?action=paste_clipboard",data:{path:t}}).done(function(e){""!=e?bootbox.alert(e):(jQuery("#clipboard").val("0"),y(!1),setTimeout(function(){window.location.href=jQuery("#refresh").attr("href")+"&"+(new Date).getTime()},300))})}})}function p(a,r){var t;t=a.hasClass("directory")?a.find(".rename-folder"):a.find(".rename-file");var n=t.attr("data-path");a.parent().hide(100),e.ajax({type:"POST",url:"ajax_calls.php?action=copy_cut",data:{path:n,sub_action:"cut"}}).done(function(t){if(""!=t)bootbox.alert(t);else{var n;n="undefined"!=typeof r?r.hasClass("back-directory")?r.find(".path").val():r.find(".rename-folder").attr("data-path"):jQuery("#sub_folder").val()+jQuery("#fldr_value").val(),e.ajax({type:"POST",url:"execute.php?action=paste_clipboard",data:{path:n}}).done(function(e){""!=e?(bootbox.alert(e),a.parent().show(100)):(jQuery("#clipboard").val("0"),y(!1),a.parent().remove())})}}).error(function(){a.parent().show(100)})}function y(e){1==e?jQuery(".paste-here-btn, .clear-clipboard-btn").removeClass("disabled"):jQuery(".paste-here-btn, .clear-clipboard-btn").addClass("disabled")}function v(e){var r=jQuery(".breadcrumb").width()+e,t=jQuery("#view"),n=jQuery("#help");if(jQuery(".uploader").css("width",r),t.val()>0){if(1==t.val())jQuery("ul.grid li, ul.grid figure").css("width","100%");else{var i=Math.floor(r/380);0==i&&(i=1,jQuery("h4").css("font-size",12)),r=Math.floor(r/i-3),jQuery("ul.grid li, ul.grid figure").css("width",r)}n.hide()}else a.touch&&n.show()}function m(){var e=jQuery(this);0==jQuery("#view").val()&&(1==e.attr("toggle")?(e.attr("toggle",0),e.animate({top:"0px"},{queue:!1,duration:300})):(e.attr("toggle",1),e.animate({top:"-30px"},{queue:!1,duration:300})))}function j(e){var a=new RegExp("(?:[?&]|&)"+e+"=([^&]+)","i"),r=window.location.search.match(a);return r&&r.length>1?r[1]:null}function Q(){1==jQuery("#popup").val()?window.close():("function"==typeof parent.jQuery(".modal").modal&&parent.jQuery(".modal").modal("hide"),"undefined"!=typeof parent.jQuery&&parent.jQuery?"function"==typeof parent.jQuery.fancybox&&parent.jQuery.fancybox.close():"function"==typeof parent.$.fancybox&&parent.$.fancybox.close())}function Q(){1==jQuery("#popup").val()?window.close():("function"==typeof parent.jQuery(".modal:has(iframe[src*=filemanager])").modal&&parent.jQuery(".modal:has(iframe[src*=filemanager])").modal("hide"),"undefined"!=typeof parent.jQuery&&parent.jQuery?"function"==typeof parent.jQuery.fancybox&&parent.jQuery.fancybox.close():"function"==typeof parent.$.fancybox&&parent.$.fancybox.close())}function h(e){for(var e,a=[/[\300-\306]/g,/[\340-\346]/g,/[\310-\313]/g,/[\350-\353]/g,/[\314-\317]/g,/[\354-\357]/g,/[\322-\330]/g,/[\362-\370]/g,/[\331-\334]/g,/[\371-\374]/g,/[\321]/g,/[\361]/g,/[\307]/g,/[\347]/g],r=["A","a","E","e","I","i","O","o","U","u","N","n","C","c"],t=0;t]+(>|$)/g,""),e.trim(a)):null}function g(a,r,t,n,i){null!==t&&(t=_(t),e.ajax({type:"POST",url:"execute.php?action="+a,data:{path:r,name:t.replace("/","")}}).done(function(e){return""!=e?(bootbox.alert(e),!1):(""!=i&&window[i](n,t),!0)}))}function b(a,r){var t=jQuery("li.dir","ul.grid").filter(":visible"),n=jQuery("li.file","ul.grid").filter(":visible"),i=[],l=[],o=[],u=[];t.each(function(){var a=jQuery(this),t=a.find(r).val();if(e.isNumeric(t))for(t=parseFloat(t);"undefined"!=typeof i[t]&&i[t];)t=parseFloat(parseFloat(t)+parseFloat(.001));else t=t+"a"+a.find("h4 a").attr("data-file");i[t]=a.html(),l.push(t)}),n.each(function(){var a=jQuery(this),t=a.find(r).val();if(e.isNumeric(t))for(t=parseFloat(t);"undefined"!=typeof o[t]&&o[t];)t=parseFloat(parseFloat(t)+parseFloat(.001));else t=t+"a"+a.find("h4 a").attr("data-file");o[t]=a.html(),u.push(t)}),e.isNumeric(l[0])?l.sort(function(e,a){return parseFloat(e)-parseFloat(a)}):l.sort(),e.isNumeric(u[0])?u.sort(function(e,a){return parseFloat(e)-parseFloat(a)}):u.sort(),a&&(l.reverse(),u.reverse()),t.each(function(e){var a=jQuery(this);a.html(i[l[e]])}),n.each(function(e){var a=jQuery(this);a.html(o[u[e]])})}function w(e,a){return featherEditor.launch({image:e,url:a}),!1}function x(){jQuery(".lazy-loaded").lazyload()}var k="9.11.3",C=!0,T=0,I=function(){var e=0;return function(a,r){clearTimeout(e),e=setTimeout(a,r)}}(),S=function(e){if(1==jQuery("#ftp").val())var a=jQuery("#ftp_base_url").val()+jQuery("#upload_dir").val()+jQuery("#fldr_value").val();else var a=jQuery("#base_url").val()+jQuery("#cur_dir").val();var r=e.find("a.link").attr("data-file");return""!=r&&null!=r&&(a+=r),r=e.find("h4 a.folder-link").attr("data-file"),""!=r&&null!=r&&(a+=r),a},U={contextActions:{copy_url:function(e){var a=S(e);bootbox.alert('URL:
'),jQuery("#copy-button"+T).html(' '+jQuery("#lang_copy").val());var r=new ZeroClipboard(jQuery("#copy-button"+T));r.on("ready",function(e){r.on("wrongFlash noFlash",function(){ZeroClipboard.destroy()}),r.on("aftercopy",function(e){jQuery("#copy-button"+T).html(' '+jQuery("#ok").val()),jQuery("#copy-button"+T).attr("class","btn disabled"),T++}),r.on("error",function(e){})})},unzip:function(a){var r=jQuery("#sub_folder").val()+jQuery("#fldr_value").val()+a.find("a.link").attr("data-file");show_animation(),e.ajax({type:"POST",url:"ajax_calls.php?action=extract",data:{path:r}}).done(function(e){hide_animation(),""!=e?bootbox.alert(e):window.location.href=jQuery("#refresh").attr("href")+"&"+(new Date).getTime()})},edit_img:function(e){var a=e.attr("data-name");if(1==jQuery("#ftp").val())var r=jQuery("#ftp_base_url").val()+jQuery("#upload_dir").val()+jQuery("#fldr_value").val()+a;else var r=jQuery("#base_url").val()+jQuery("#cur_dir").val()+a;var t=jQuery("#aviary_img");t.attr("data-name",a),show_animation(),t.attr("src",r).load(w(t.attr("id"),r))},duplicate:function(e){var a=e.find("h4").text().trim();bootbox.prompt(jQuery("#lang_duplicate").val(),jQuery("#cancel").val(),jQuery("#ok").val(),function(r){if(null!==r&&(r=_(r),r!=a)){var t=e.find(".rename-file");g("duplicate_file",t.attr("data-path"),r,t,"apply_file_duplicate")}},a)},select:function(e){var a,r=S(e),t=jQuery("#field_id").val(),n=jQuery("#return_relative_url").val();if(1==n&&(r=r.replace(jQuery("#base_url").val(),""),r=r.replace(jQuery("#cur_dir").val(),"")),a=1==jQuery("#popup").val()?window.opener:window.parent,""!=t)if(1==jQuery("#crossdomain").val())a.postMessage({sender:"responsivefilemanager",url:r,field_id:t},"*");else{var i=jQuery("#"+t,a.document);i.val(r).trigger("change"),"function"==typeof a.responsive_filemanager_callback&&a.responsive_filemanager_callback(t),Q()}else apply_any(r)},copy:function(e){d(e,"copy")},cut:function(e){d(e,"cut")},paste:function(){f()},chmod:function(e){o(e)},edit_text_file:function(e){i(e)}},makeContextMenu:function(){var a=this;e.contextMenu({selector:"figure:not(.back-directory), .list-view2 figure:not(.back-directory)",autoHide:!0,build:function(e){e.addClass("selected");var t={callback:function(r,t){a.contextActions[r](e)},items:{}};return(e.find(".img-precontainer-mini .filetype").hasClass("png")||e.find(".img-precontainer-mini .filetype").hasClass("jpg")||e.find(".img-precontainer-mini .filetype").hasClass("jpeg"))&&r&&(t.items.edit_img={name:jQuery("#lang_edit_image").val(),icon:"edit_img",disabled:!1}),e.hasClass("directory")&&0!=jQuery("#type_param").val()&&(t.items.select={name:jQuery("#lang_select").val(),icon:"",disabled:!1}),t.items.copy_url={name:jQuery("#lang_show_url").val(),icon:"url",disabled:!1},(e.find(".img-precontainer-mini .filetype").hasClass("zip")||e.find(".img-precontainer-mini .filetype").hasClass("tar")||e.find(".img-precontainer-mini .filetype").hasClass("gz"))&&(t.items.unzip={name:jQuery("#lang_extract").val(),icon:"extract",disabled:!1}),e.find(".img-precontainer-mini .filetype").hasClass("edit-text-file-allowed")&&(t.items.edit_text_file={name:jQuery("#lang_edit_file").val(),icon:"edit",disabled:!1}),e.hasClass("directory")||1!=jQuery("#duplicate").val()||(t.items.duplicate={name:jQuery("#lang_duplicate").val(),icon:"duplicate",disabled:!1}),e.hasClass("directory")||1!=jQuery("#copy_cut_files_allowed").val()?e.hasClass("directory")&&1==jQuery("#copy_cut_dirs_allowed").val()&&(t.items.copy={name:jQuery("#lang_copy").val(),icon:"copy",disabled:!1},t.items.cut={name:jQuery("#lang_cut").val(),icon:"cut",disabled:!1}):(t.items.copy={name:jQuery("#lang_copy").val(),icon:"copy",disabled:!1},t.items.cut={name:jQuery("#lang_cut").val(),icon:"cut",disabled:!1}),0==jQuery("#clipboard").val()||e.hasClass("directory")||(t.items.paste={name:jQuery("#lang_paste_here").val(),icon:"clipboard-apply",disabled:!1}),e.hasClass("directory")||1!=jQuery("#chmod_files_allowed").val()?e.hasClass("directory")&&1==jQuery("#chmod_dirs_allowed").val()&&(t.items.chmod={name:jQuery("#lang_file_permission").val(),icon:"key",disabled:!1}):t.items.chmod={name:jQuery("#lang_file_permission").val(),icon:"key",disabled:!1},t.items.sep="----",t.items.info={name:""+jQuery("#lang_file_info").val()+"",disabled:!0},t.items.name={name:e.attr("data-name"),icon:"label",disabled:!0},"img"==e.attr("data-type")&&(t.items.dimension={name:e.find(".img-dimension").html(),icon:"dimension",disabled:!0}),"true"!==jQuery("#show_folder_size").val()&&"true"!==jQuery("#show_folder_size").val()||(e.hasClass("directory")?t.items.size={name:e.find(".file-size").html()+" - "+e.find(".nfiles").val()+" "+jQuery("#lang_files").val()+" - "+e.find(".nfolders").val()+" "+jQuery("#lang_folders").val(),icon:"size",disabled:!0}:t.items.size={name:e.find(".file-size").html(),icon:"size",disabled:!0}),t.items.date={name:e.find(".file-date").html(),icon:"date",disabled:!0},t},events:{hide:function(){jQuery("figure").removeClass("selected")}}}),jQuery(document).on("contextmenu",function(e){if(!jQuery(e.target).is("figure"))return!1})},bindGridEvents:function(){function a(e){window[e.attr("data-function")](e.attr("data-file"),jQuery("#field_id").val())}var r=jQuery("ul.grid");r.on("click",".modalAV",function(a){var r=jQuery(this);a.preventDefault();var t=jQuery("#previewAV"),n=jQuery(".body-preview");t.removeData("modal"),t.modal({backdrop:"static",keyboard:!1}),r.hasClass("audio")?n.css("height","80px"):n.css("height","345px"),e.ajax({url:r.attr("data-url"),success:function(e){n.html(e)}})}),r.on("click",".file-preview-btn",function(a){var r=jQuery(this);a.preventDefault(),e.ajax({url:r.attr("data-url"),success:function(e){bootbox.modal(e," "+r.parent().parent().parent().find(".name").val())}})}),r.on("click",".preview",function(){var e=jQuery(this);return 0==e.hasClass("disabled")&&jQuery("#full-img").attr("src",decodeURIComponent(e.attr("data-url"))),!0}),r.on("click",".rename-file",function(){var a=jQuery(this),r=a.parent().parent().parent(),t=r.find("h4"),n=e.trim(t.text());bootbox.prompt(jQuery("#rename").val(),jQuery("#cancel").val(),jQuery("#ok").val(),function(e){null!==e&&(e=_(e),e!=n&&g("rename_file",a.attr("data-path"),e,r,"apply_file_rename"))},n)}),r.on("click",".rename-folder",function(){var a=jQuery(this),r=a.parent().parent().parent(),t=r.find("h4"),n=e.trim(t.text());bootbox.prompt(jQuery("#rename").val(),jQuery("#cancel").val(),jQuery("#ok").val(),function(e){null!==e&&(e=_(e).replace(".",""),e!=n&&g("rename_folder",a.attr("data-path"),e,r,"apply_folder_rename"))},n)}),r.on("click",".delete-file",function(){var e=jQuery(this);bootbox.confirm(e.attr("data-confirm"),jQuery("#cancel").val(),jQuery("#ok").val(),function(a){if(1==a){g("delete_file",e.attr("data-path"),"","","");var r=jQuery("#files_number");r.text(parseInt(r.text())-1),e.parent().parent().parent().parent().remove()}})}),r.on("click",".delete-folder",function(){var e=jQuery(this);bootbox.confirm(e.attr("data-confirm"),jQuery("#cancel").val(),jQuery("#ok").val(),function(a){if(1==a){g("delete_folder",e.attr("data-path"),"","","");var r=jQuery("#folders_number");r.text(parseInt(r.text())-1),e.parent().parent().parent().remove()}})}),jQuery("ul.grid").on("click",".link",function(){a(jQuery(this))}),jQuery("ul.grid").on("click","div.box",function(e){var r=jQuery(this).find(".link");if(0!==r.length)a(r);else{var t=jQuery(this).find(".folder-link");0!==t.length&&(document.location=jQuery(t).prop("href"))}})},makeFilters:function(a){jQuery("#filter-input").on("keyup",function(){jQuery(".filters label").removeClass("btn-inverse"),jQuery(".filters label").find("i").removeClass("icon-white"),jQuery("#ff-item-type-all").addClass("btn-inverse"),jQuery("#ff-item-type-all").find("i").addClass("icon-white");var r=_(jQuery(this).val()).toLowerCase();jQuery(this).val(r),a&&I(function(){jQuery("li","ul.grid ").each(function(){var e=jQuery(this);""!=r&&e.attr("data-name").toLowerCase().indexOf(r)==-1?e.hide(100):e.show(100)}),e.ajax({url:"ajax_calls.php?action=filter&type="+r}).done(function(e){""!=e&&bootbox.alert(e)}),I(function(){var e=0!=jQuery("#descending").val();b(e,"."+jQuery("#sort_by").val()),x()},500)},300)}).keypress(function(e){13==e.which&&jQuery("#filter").trigger("click")}),jQuery("#filter").on("click",function(){var e=_(jQuery("#filter-input").val());window.location.href=jQuery("#current_url").val()+"&filter="+e})},makeUploader:function(){jQuery("#uploader-btn").on("click",function(){var e=jQuery("#sub_folder").val()+jQuery("#fldr_value").val()+"/";e=e.substring(0,e.length-1),jQuery("#iframe-container").html(jQuery(""}else"application/x-shockwave-flash"==i.source1mime?(o+='',i.poster&&(o+=''),o+=""):-1!=i.source1mime.indexOf("audio")?e.settings.audio_template_callback?o=e.settings.audio_template_callback(i):o+='":"script"==i.type?o+='':o=e.settings.video_template_callback?e.settings.video_template_callback(i):'"}return o}function s(e){var t={};return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!0,special:"script,noscript",start:function(e,n){if(t.source1||"param"!=e||(t.source1=n.map.movie),("iframe"==e||"object"==e||"embed"==e||"video"==e||"audio"==e)&&(t.type||(t.type=e),t=tinymce.extend(n.map,t)),"script"==e){var i=r(n.map.src);if(!i)return;t={type:"script",source1:n.map.src,width:i.width,height:i.height}}"source"==e&&(t.source1?t.source2||(t.source2=n.map.src):t.source1=n.map.src),"img"!=e||t.poster||(t.poster=n.map.src)}}).parse(e),t.source1=t.source1||t.src||t.data,t.source2=t.source2||"",t.poster=t.poster||"",t}function l(t){return t.getAttribute("data-mce-object")?s(e.serializer.serialize(t,{selection:!0})):{}}function c(t){if(e.settings.media_filter_html===!1)return t;var n,r=new tinymce.html.Writer;return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!1,special:"script,noscript",comment:function(e){r.comment(e)},cdata:function(e){r.cdata(e)},text:function(e,t){r.text(e,t)},start:function(t,i,o){if(n=!0,"script"!=t&&"noscript"!=t){for(var a=0;a=a&&(r(s,{src:t["source"+a],type:t["source"+a+"mime"]}),!t["source"+a]))return;break;case"img":if(!t.poster)return;i=!0}o.start(e,s,l)},end:function(e){if("video"==e&&n)for(var s=1;2>=s;s++)if(t["source"+s]){var l=[];l.map={},s>a&&(r(l,{src:t["source"+s],type:t["source"+s+"mime"]}),o.start("source",l,!0))}if(t.poster&&"object"==e&&n&&!i){var c=[];c.map={},r(c,{src:t.poster,width:t.width,height:t.height}),o.start("img",c,!0)}o.end(e)}},new tinymce.html.Schema({})).parse(e),o.getContent()}function d(t,n){var r,i,o,a,s;for(o=t.attributes,a=o.length;a--;)r=o[a].name,i=o[a].value,"width"!==r&&"height"!==r&&"style"!==r&&(("data"==r||"src"==r)&&(i=e.convertURL(i,r)),n.attr("data-mce-p-"+r,i));s=t.firstChild&&t.firstChild.value,s&&(n.attr("data-mce-html",escape(s)),n.firstChild=null)}function f(e){var t,n=e.name;return t=new tinymce.html.Node("img",1),t.shortEnded=!0,d(e,t),t.attr({width:e.attr("width")||"300",height:e.attr("height")||("audio"==n?"30":"150"),style:e.attr("style"),src:tinymce.Env.transparentSrc,"data-mce-object":n,"class":"mce-object mce-object-"+n}),t}function p(e){var t,n,r,i=e.name;return t=new tinymce.html.Node("span",1),t.attr({contentEditable:"false",style:e.attr("style"),"data-mce-object":i,"class":"mce-preview-object mce-object-"+i}),d(e,t),n=new tinymce.html.Node(i,1),n.attr({src:e.attr("src"),allowfullscreen:e.attr("allowfullscreen"),width:e.attr("width")||"300",height:e.attr("height")||("audio"==i?"30":"150"),frameborder:"0"}),r=new tinymce.html.Node("span",1),r.attr("class","mce-shim"),t.append(n),t.append(r),t}var m=[{regex:/youtu\.be\/([\w\-.]+)/,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)/,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$2",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\-]+)/i,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowfullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"//player.vimeo.com/video/$2?title=0&byline=0",allowfullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'//maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1}],h=tinymce.Env.ie&&tinymce.Env.ie<=8?"onChange":"onInput";e.on("ResolveName",function(e){var t;1==e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}),e.on("preInit",function(){var t=e.schema.getSpecialElements();tinymce.each("video audio iframe object".split(" "),function(e){t[e]=new RegExp("]*>","gi")});var n=e.schema.getBoolAttrs();tinymce.each("webkitallowfullscreen mozallowfullscreen allowfullscreen".split(" "),function(e){n[e]={}}),e.parser.addNodeFilter("iframe,video,audio,object,embed,script",function(t){for(var n,i,o,a=t.length;a--;)n=t[a],n.parent&&(n.parent.attr("data-mce-object")||("script"!=n.name||(o=r(n.attr("src"))))&&(o&&(o.width&&n.attr("width",o.width.toString()),o.height&&n.attr("height",o.height.toString())),i="iframe"==n.name&&e.settings.media_live_embeds!==!1&&tinymce.Env.ceFalse?p(n):f(n),n.replace(i)))}),e.serializer.addAttributeFilter("data-mce-object",function(e,t){for(var n,r,i,o,a,s,l,u,d=e.length;d--;)if(n=e[d],n.parent){for(l=n.attr(t),r=new tinymce.html.Node(l,1),"audio"!=l&&"script"!=l&&(u=n.attr("class"),u&&-1!==u.indexOf("mce-preview-object")?r.attr({width:n.firstChild.attr("width"),height:n.firstChild.attr("height")}):r.attr({width:n.attr("width"),height:n.attr("height")})),r.attr({style:n.attr("style")}),o=n.attributes,i=o.length;i--;){var f=o[i].name;0===f.indexOf("data-mce-p-")&&r.attr(f.substr(11),o[i].value)}"script"==l&&r.attr("type","text/javascript"),a=n.attr("data-mce-html"),a&&(s=new tinymce.html.Node("#text",3),s.raw=!0,s.value=c(unescape(a)),r.append(s)),n.replace(r)}})}),e.on("ObjectSelected",function(e){var t=e.target.getAttribute("data-mce-object");("audio"==t||"script"==t)&&e.preventDefault()}),e.on("objectResized",function(e){var t,n=e.target;n.getAttribute("data-mce-object")&&(t=n.getAttribute("data-mce-html"),t&&(t=unescape(t),n.setAttribute("data-mce-html",escape(u(t,{width:e.width,height:e.height})))))}),e.addButton("media",{tooltip:"Insert/edit video",onclick:i,stateSelector:["img[data-mce-object]","span[data-mce-object]"]}),e.addMenuItem("media",{icon:"media",text:"Insert/edit video",onclick:i,context:"insert",prependToContext:!0}),e.addCommand("mceMedia",i),this.showDialog=i}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/nonbreaking/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/nonbreaking/plugin.min.js new file mode 100644 index 0000000..1e4f334 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/nonbreaking/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("nonbreaking",function(e){var t=e.getParam("nonbreaking_force_tab");if(e.addCommand("mceNonBreaking",function(){e.insertContent(e.plugins.visualchars&&e.plugins.visualchars.state?' ':" "),e.dom.setAttrib(e.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),e.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),e.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),t){var n=+t>1?+t:3;e.on("keydown",function(t){if(9==t.keyCode){if(t.shiftKey)return;t.preventDefault();for(var r=0;n>r;r++)e.execCommand("mceNonBreaking")}})}}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/noneditable/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/noneditable/plugin.min.js new file mode 100644 index 0000000..b3d2add --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/noneditable/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("noneditable",function(e){function t(e){return function(t){return-1!==(" "+t.attr("class")+" ").indexOf(e)}}function n(t){function n(t){var n=arguments,r=n[n.length-2];return r>0&&'"'==a.charAt(r-1)?t:''+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+""}var r=o.length,a=t.content,s=tinymce.trim(i);if("raw"!=t.format){for(;r--;)a=a.replace(o[r],n);t.content=a}}var r,i,o,a="contenteditable";r=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",i=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";var s=t(r),l=t(i);o=e.getParam("noneditable_regexp"),o&&!o.length&&(o=[o]),e.on("PreInit",function(){o&&e.on("BeforeSetContent",n),e.parser.addAttributeFilter("class",function(e){for(var t,n=e.length;n--;)t=e[n],s(t)?t.attr(a,"true"):l(t)&&t.attr(a,"false")}),e.serializer.addAttributeFilter(a,function(e){for(var t,n=e.length;n--;)t=e[n],(s(t)||l(t))&&(o&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):t.attr(a,null))})})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/pagebreak/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/pagebreak/plugin.min.js new file mode 100644 index 0000000..b76e584 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/pagebreak/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("pagebreak",function(e){var t="mce-pagebreak",n=e.getParam("pagebreak_separator",""),r=new RegExp(n.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),i='';e.addCommand("mcePageBreak",function(){e.settings.pagebreak_split_block?e.insertContent("

"+i+"

"):e.insertContent(i)}),e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),e.on("ResolveName",function(n){"IMG"==n.target.nodeName&&e.dom.hasClass(n.target,t)&&(n.name="pagebreak")}),e.on("click",function(n){n=n.target,"IMG"===n.nodeName&&e.dom.hasClass(n,t)&&e.selection.select(n)}),e.on("BeforeSetContent",function(e){e.content=e.content.replace(r,i)}),e.on("PreInit",function(){e.serializer.addNodeFilter("img",function(t){for(var r,i,o=t.length;o--;)if(r=t[o],i=r.attr("class"),i&&-1!==i.indexOf("mce-pagebreak")){var a=r.parent;if(e.schema.getBlockElements()[a.name]&&e.settings.pagebreak_split_block){a.type=3,a.value=n,a.raw=!0,r.remove();continue}r.type=3,r.value=n,r.raw=!0}})})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/paste/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/paste/plugin.min.js new file mode 100644 index 0000000..a81b792 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/paste/plugin.min.js @@ -0,0 +1 @@ +!function(e,t){"use strict";function n(e,t){for(var n,r=[],o=0;o/g]),o(s.parse(i)),l}function o(e){function t(e,t,n){return t||n?"\xa0":" "}return e=r(e,[/^[\s\S]*]*>\s*|\s*<\/body[^>]*>[\s\S]*$/g,/|/g,[/( ?)\u00a0<\/span>( ?)/g,t],/
/g,/
$/i])}return{filter:r,innerText:i,trimHtml:o}}),r("tinymce/pasteplugin/Clipboard",["tinymce/Env","tinymce/dom/RangeUtils","tinymce/util/VK","tinymce/pasteplugin/Utils","tinymce/util/Delay"],function(e,t,n,r,i){return function(o){function a(e){var t,n=o.dom;if(t=o.fire("BeforePastePreProcess",{content:e}),t=o.fire("PastePreProcess",t),e=t.content,!t.isDefaultPrevented()){if(o.hasEventListeners("PastePostProcess")&&!t.isDefaultPrevented()){var r=n.add(o.getBody(),"div",{style:"display:none"},e);t=o.fire("PastePostProcess",{node:r}),n.remove(r),e=t.node.innerHTML}t.isDefaultPrevented()||o.insertContent(e,{merge:o.settings.paste_merge_formats!==!1,data:{paste:!0}})}}function s(e){e=o.dom.encode(e).replace(/\r\n/g,"\n");var t,n=o.dom.getParent(o.selection.getStart(),o.dom.isBlock),i=o.settings.forced_root_block;i&&(t=o.dom.createHTML(i,o.settings.forced_root_block_attrs),t=t.substr(0,t.length-3)+">"),n&&/^(PRE|DIV)$/.test(n.nodeName)||!i?e=r.filter(e,[[/\n/g,"
"]]):(e=r.filter(e,[[/\n\n/g,"

"+t],[/^(.*<\/p>)(

)$/,t+"$1"],[/\n/g,"
"]]),-1!=e.indexOf("

")&&(e=t+e)),a(e)}function l(){function t(e){var t,n,i,o=e.startContainer;if(t=e.getClientRects(),t.length)return t[0];if(e.collapsed&&1==o.nodeType){for(i=o.childNodes[w.startOffset];i&&3==i.nodeType&&!i.data.length;)i=i.nextSibling;if(i)return"BR"==i.tagName&&(n=r.doc.createTextNode("\ufeff"),i.parentNode.insertBefore(n,i),e=r.createRng(),e.setStartBefore(n),e.setEndAfter(n),t=e.getClientRects(),r.remove(n)),t.length?t[0]:void 0}}var n,r=o.dom,i=o.getBody(),a=o.dom.getViewPort(o.getWin()),s=a.y,l=20;if(w=o.selection.getRng(),o.inline&&(n=o.selection.getScrollContainer(),n&&n.scrollTop>0&&(s=n.scrollTop)),w.getClientRects){var c=t(w);if(c)l=s+(c.top-r.getPos(i).y);else{l=s;var u=w.startContainer;u&&(3==u.nodeType&&u.parentNode!=i&&(u=u.parentNode),1==u.nodeType&&(l=r.getPos(u,n||i).y))}}C=r.add(o.getBody(),"div",{id:"mcepastebin",contentEditable:!0,"data-mce-bogus":"all",style:"position: absolute; top: "+l+"px;width: 10px; height: 10px; overflow: hidden; opacity: 0"},S),(e.ie||e.gecko)&&r.setStyle(C,"left","rtl"==r.getStyle(i,"direction",!0)?65535:-65535),r.bind(C,"beforedeactivate focusin focusout",function(e){e.stopPropagation()}),C.focus(),o.selection.select(C,!0)}function c(){if(C){for(var e;e=o.dom.get("mcepastebin");)o.dom.remove(e),o.dom.unbind(e);w&&o.selection.setRng(w)}C=w=null}function u(){var e,t,n,r,i="";for(e=o.dom.select("div[id=mcepastebin]"),t=0;t>8);return decodeURIComponent(escape(n))}function f(e){var t,n,r;return n="",t=e.indexOf(n),-1!==t&&(e=e.substr(t+n.length)),r="",t=e.indexOf(r),-1!==t&&(e=e.substr(0,t)),e}function p(e){var t={};if(e){if(e.getData){var n=e.getData("Text");n&&n.length>0&&-1==n.indexOf(T)&&(t["text/plain"]=n)}if(e.types)for(var r=0;r')}var i,s,l,c=!1;if(n)for(i=0;i0}function b(e){return n.metaKeyPressed(e)&&86==e.keyCode||e.shiftKey&&45==e.keyCode}function x(){function t(e,t,n){var i;return y(e,"text/html")?i=e["text/html"]:(i=u(),i==S&&(n=!0)),i=r.trimHtml(i),C&&C.firstChild&&"mcepastebin"===C.firstChild.id&&(n=!0),c(),i.length||(n=!0),n&&(i=y(e,"text/plain")&&-1==i.indexOf("

")?e["text/plain"]:r.innerText(i)),i==S?void(t||o.windowManager.alert("Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.")):void(n?s(i):a(i))}o.on("keydown",function(t){function n(e){b(e)&&!e.isDefaultPrevented()&&c()}if(b(t)&&!t.isDefaultPrevented()){if(N=t.shiftKey&&86==t.keyCode,N&&e.webkit&&-1!=navigator.userAgent.indexOf("Version/"))return;if(t.stopImmediatePropagation(),E=(new Date).getTime(),e.ie&&N)return t.preventDefault(),void o.fire("paste",{ieFake:!0});c(),l(),o.once("keyup",n),o.once("paste",function(){o.off("keyup",n)})}}),o.on("paste",function(n){var r=(new Date).getTime(),a=m(n),s=(new Date).getTime()-r,d=(new Date).getTime()-E-s<1e3,f="text"==_.pasteFormat||N;return N=!1,n.isDefaultPrevented()||g(n)?void c():h(n)?void c():(d||n.preventDefault(),!e.ie||d&&!n.ieFake||(l(),o.dom.bind(C,"paste",function(e){e.stopPropagation()}),o.getDoc().execCommand("Paste",!1,null),a["text/html"]=u()),void(y(a,"text/html")?(n.preventDefault(),t(a,d,f)):i.setEditorTimeout(o,function(){t(a,d,f)},0)))}),o.on("dragstart dragend",function(e){k="dragstart"==e.type}),o.on("drop",function(e){var t=v(e);if(!e.isDefaultPrevented()&&!k&&!h(e,t)&&t&&o.settings.paste_filter_drop!==!1){var n=p(e.dataTransfer),i=n["mce-internal"]||n["text/html"]||n["text/plain"];i&&(e.preventDefault(),o.undoManager.transact(function(){n["mce-internal"]&&o.execCommand("Delete"),o.selection.setRng(t),i=r.trimHtml(i),n["text/html"]?a(i):s(i)}))}}),o.on("dragover dragend",function(e){o.settings.paste_data_images&&e.preventDefault()})}var C,w,N,_=this,E=0,k=!1,S="%MCEPASTEBIN%",T="data:text/mce-internal,";_.pasteHtml=a,_.pasteText=s,o.on("preInit",function(){x(),o.parser.addNodeFilter("img",function(t,n,r){function i(e){return e.data&&e.data.paste===!0}function a(t){t.attr("data-mce-object")||u===e.transparentSrc||t.remove()}function s(e){return 0===e.indexOf("webkit-fake-url")}function l(e){return 0===e.indexOf("data:")}if(!o.settings.paste_data_images&&i(r))for(var c=t.length;c--;){var u=t[c].attributes.map.src;u&&(s(u)?a(t[c]):!o.settings.allow_html_data_urls&&l(u)&&a(t[c]))}})})}}),r("tinymce/pasteplugin/WordFilter",["tinymce/util/Tools","tinymce/html/DomParser","tinymce/html/Schema","tinymce/html/Serializer","tinymce/html/Node","tinymce/pasteplugin/Utils"],function(e,t,n,r,i,o){function a(e){return/s?a&&(a=a.parent.parent):(c=a,a=null)),a&&a.name==t?a.append(e):(c=c||a,a=new i(t,1),o>1&&a.attr("start",""+o),e.wrap(a)),e.name="li",s>u&&c&&c.lastChild.append(a),u=s,r(e),n(e,/^\u00a0+/),n(e,/^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/),n(e,/^\u00a0+/)}for(var a,c,u=1,d=[],f=e.firstChild;"undefined"!=typeof f&&null!==f;)if(d.push(f),f=f.walk(),null!==f)for(;"undefined"!=typeof f&&f.parent!==e;)f=f.walk();for(var p=0;p]+id="?docs-internal-[^>]*>/gi,""),g=g.replace(/
/gi,""),m=u.paste_retain_style_properties,m&&(h=e.makeMap(m.split(/[, ]/))),u.paste_enable_default_filters!==!1&&a(d.content)){d.wordContent=!0,g=o.filter(g,[//gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/ /gi,"\xa0"],[/([\s\u00a0]*)<\/span>/gi,function(e,t){return t.length>0?t.replace(/./," ").slice(Math.floor(t.length/2)).split("").join("\xa0"):""}]]);var v=u.paste_word_valid_elements;v||(v="-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody");var y=new n({valid_elements:v,valid_children:"-li[p]"});e.each(y.elements,function(e){e.attributes["class"]||(e.attributes["class"]={},e.attributesOrder.push("class")),e.attributes.style||(e.attributes.style={},e.attributesOrder.push("style"))});var b=new t({},y);b.addAttributeFilter("style",function(e){for(var t,n=e.length;n--;)t=e[n],t.attr("style",p(t,t.attr("style"))),"span"==t.name&&t.parent&&!t.attributes.length&&t.unwrap()}),b.addAttributeFilter("class",function(e){for(var t,n,r=e.length;r--;)t=e[r],n=t.attr("class"),/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(n)&&t.remove(),t.attr("class",null)}),b.addNodeFilter("del",function(e){for(var t=e.length;t--;)e[t].remove()}),b.addNodeFilter("a",function(e){for(var t,n,r,i=e.length;i--;)if(t=e[i],n=t.attr("href"),r=t.attr("name"),n&&-1!=n.indexOf("#_msocom_"))t.remove();else if(n&&0===n.indexOf("file://")&&(n=n.split("#")[1],n&&(n="#"+n)),n||r){if(r&&!/^_?(?:toc|edn|ftn)/i.test(r)){t.unwrap();continue}t.attr({href:n,name:r})}else t.unwrap()});var x=b.parse(g);u.paste_convert_word_fake_lists!==!1&&f(x),d.content=new r({validate:u.validate},y).serialize(x)}})}return c.isWordContent=a,c}),r("tinymce/pasteplugin/Quirks",["tinymce/Env","tinymce/util/Tools","tinymce/pasteplugin/WordFilter","tinymce/pasteplugin/Utils"],function(e,t,n,r){return function(i){function o(e){i.on("BeforePastePreProcess",function(t){t.content=e(t.content)})}function a(e){if(!n.isWordContent(e))return e;var o=[];t.each(i.schema.getBlockElements(),function(e,t){o.push(t)});var a=new RegExp("(?:
 [\\s\\r\\n]+|
)*(<\\/?("+o.join("|")+")[^>]*>)(?:
 [\\s\\r\\n]+|
)*","g");return e=r.filter(e,[[a,"$1"]]),e=r.filter(e,[[/

/g,"

"],[/
/g," "],[/

/g,"
"]])}function s(e){if(n.isWordContent(e))return e;var t=i.settings.paste_webkit_styles;if(i.settings.paste_remove_styles_if_webkit===!1||"all"==t)return e;if(t&&(t=t.split(/[, ]/)),t){var r=i.dom,o=i.selection.getNode();e=e.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,function(e,n,i,a){var s=r.parseStyle(i,"span"),l={};if("none"===t)return n+a;for(var c=0;c]+) style="([^"]*)"([^>]*>)/gi,"$1$3");return e=e.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi,function(e,t,n,r){return t+' style="'+n+'"'+r})}e.webkit&&o(s),e.ie&&o(a)}}),r("tinymce/pasteplugin/Plugin",["tinymce/PluginManager","tinymce/pasteplugin/Clipboard","tinymce/pasteplugin/WordFilter","tinymce/pasteplugin/Quirks"],function(e,t,n,r){var i;e.add("paste",function(e){function o(){if("text"==a.pasteFormat)this.active(!1),a.pasteFormat="html";else if(a.pasteFormat="text",this.active(!0),!i){var t=e.translate("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.");e.notificationManager.open({text:t,type:"info"}),i=!0}}var a,s=this,l=e.settings;s.clipboard=a=new t(e),s.quirks=new r(e),s.wordFilter=new n(e),e.settings.paste_as_text&&(s.clipboard.pasteFormat="text"),l.paste_preprocess&&e.on("PastePreProcess",function(e){l.paste_preprocess.call(s,s,e)}),l.paste_postprocess&&e.on("PastePostProcess",function(e){l.paste_postprocess.call(s,s,e)}),e.addCommand("mceInsertClipboardContent",function(e,t){t.content&&s.clipboard.pasteHtml(t.content),t.text&&s.clipboard.pasteText(t.text)}),e.paste_block_drop&&e.on("dragend dragover draggesture dragdrop drop drag",function(e){e.preventDefault(),e.stopPropagation()}),e.settings.paste_data_images||e.on("drop",function(e){var t=e.dataTransfer;t&&t.files&&t.files.length>0&&e.preventDefault()}),e.addButton("pastetext",{icon:"pastetext",tooltip:"Paste as text",onclick:o,active:"text"==s.clipboard.pasteFormat}),e.addMenuItem("pastetext",{text:"Paste as text",selectable:!0,active:a.pasteFormat,onclick:o})})}),o(["tinymce/pasteplugin/Utils"])}(this); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/preview/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/preview/plugin.min.js new file mode 100644 index 0000000..7d5e047 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/preview/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("preview",function(e){var t=e.settings,n=!tinymce.Env.ie;e.addCommand("mcePreview",function(){e.windowManager.open({title:"Preview",width:parseInt(e.getParam("plugin_preview_width","650"),10),height:parseInt(e.getParam("plugin_preview_height","500"),10),html:'",buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var r,i="";i+='',tinymce.each(e.contentCSS,function(t){i+=''});var o=t.body_id||"tinymce";-1!=o.indexOf("=")&&(o=e.getParam("body_id","","hash"),o=o[e.id]||o);var a=t.body_class||"";-1!=a.indexOf("=")&&(a=e.getParam("body_class","","hash"),a=a[e.id]||"");var s=e.settings.directionality?' dir="'+e.settings.directionality+'"':"";if(r=""+i+'"+e.getContent()+"",n)this.getEl("body").firstChild.src="data:text/html;charset=utf-8,"+encodeURIComponent(r);else{var l=this.getEl("body").firstChild.contentWindow.document;l.open(),l.write(r),l.close()}}})}),e.addButton("preview",{title:"Preview",cmd:"mcePreview"}),e.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/print/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/print/plugin.min.js new file mode 100644 index 0000000..9f58535 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/print/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("print",function(e){e.addCommand("mcePrint",function(){e.getWin().print()}),e.addButton("print",{title:"Print",cmd:"mcePrint"}),e.addShortcut("Meta+P","","mcePrint"),e.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Meta+P",context:"file"})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/editor_plugin.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/editor_plugin.js new file mode 100644 index 0000000..fd42009 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/editor_plugin.js @@ -0,0 +1,126 @@ +(function() { + + tinymce.create('tinymce.plugins.ResponsiveFileManager', + { + + init : function(editor, url) + { + + // File manager callback + function openmanager() + { + editor.focus(true); + var title="RESPONSIVE FileManager"; + if (typeof editor.settings.filemanager_title !== "undefined" && editor.settings.filemanager_title) { + title=editor.settings.filemanager_title; + } + var akey="key"; + if (typeof editor.settings.filemanager_access_key !== "undefined" && editor.settings.filemanager_access_key) { + akey=editor.settings.filemanager_access_key; + } + var sort_by=""; + if (typeof editor.settings.filemanager_sort_by !== "undefined" && editor.settings.filemanager_sort_by) { + sort_by="&sort_by="+editor.settings.filemanager_sort_by; + } + var descending="false"; + if (typeof editor.settings.filemanager_descending !== "undefined" && editor.settings.filemanager_descending) { + descending=editor.settings.filemanager_descending; + } + var fldr=""; + if (typeof editor.settings.filemanager_subfolder !== "undefined" && editor.settings.filemanager_subfolder) { + fldr="&fldr="+editor.settings.filemanager_subfolder; + } + // Disabled because of bug + var type=2; + if (typeof editor.settings.filemanager_type !== "undefined" && editor.settings.filemanager_type) { + if ($.isNumeric(editor.settings.filemanager_type) === true && editor.settings.filemanager_type > 0 && editor.settings.filemanager_type <= 3) { + type=editor.settings.filemanager_type; + } + else if (editor.settings.filemanager_type == 'image'){ + type = 1; + } + else if (editor.settings.filemanager_type == 'media'){ + type = 3; + } + else { + type = 2; + } + } + + win = editor.windowManager.open({ + title: title, + file: editor.settings.external_filemanager_path+'dialog.php?type=4&descending='+descending+sort_by+fldr+'&lang='+editor.settings.language+'&akey='+akey, + width: 860, + height: 570, + inline: 1, + resizable: true, + maximizable: true + }); + } + + editor.settings.file_browser_callback = filemanager; + + function filemanager (id, value, type, win) { + // DEFAULT AS FILE + urltype=2; + if (type=='image') { urltype=1; } + if (type=='media') { urltype=3; } + var title="RESPONSIVE FileManager"; + if (typeof editor.settings.filemanager_title !== "undefined" && editor.settings.filemanager_title) { + title=editor.settings.filemanager_title; + } + var akey="key"; + if (typeof editor.settings.filemanager_access_key !== "undefined" && editor.settings.filemanager_access_key) { + akey=editor.settings.filemanager_access_key; + } + var sort_by=""; + if (typeof editor.settings.filemanager_sort_by !== "undefined" && editor.settings.filemanager_sort_by) { + sort_by="&sort_by="+editor.settings.filemanager_sort_by; + } + var descending="false"; + if (typeof editor.settings.filemanager_descending !== "undefined" && editor.settings.filemanager_descending) { + descending=editor.settings.filemanager_descending; + } + var fldr=""; + if (typeof editor.settings.filemanager_subfolder !== "undefined" && editor.settings.filemanager_subfolder) { + fldr="&fldr="+editor.settings.filemanager_subfolder; + } + + tinymce.activeEditor.windowManager.open({ + title: title, + file: editor.settings.external_filemanager_path+'dialog.php?type='+urltype+'&descending='+descending+sort_by+fldr+'&lang='+editor.settings.language+'&akey='+akey, + width: 860, + height: 570, + resizable: true, + maximizable: true, + inline: 1 + }, { + setUrl: function (url) { + var fieldElm = win.document.getElementById(id); + fieldElm.value = editor.convertURL(url); + if ("fireEvent" in fieldElm) { + fieldElm.fireEvent("onchange") + } else { + var evt = document.createEvent("HTMLEvents"); + evt.initEvent("change", false, true); + fieldElm.dispatchEvent(evt); + } + } + }); + }; + + // Register buttons + editor.addButton('responsivefilemanager', + { + title : 'Browse files', + image : url + '/img/insertfile.gif', + shortcut: 'Ctrl+E', + onclick: openmanager + }); + } + + }); + + // Register plugin + tinymce.PluginManager.add('responsivefilemanager', tinymce.plugins.ResponsiveFileManager); +})(); diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/img/insertfile.gif b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/img/insertfile.gif new file mode 100644 index 0000000000000000000000000000000000000000..93689cb34950fb518b02f808ba64cbc3a06df224 GIT binary patch literal 3325 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 0 && editor.settings.filemanager_type <= 3) { + type=editor.settings.filemanager_type; + } + else if (editor.settings.filemanager_type == 'image'){ + type = 1; + } + else if (editor.settings.filemanager_type == 'media'){ + type = 3; + } + else { + type = 2; + } + } + + win = editor.windowManager.open({ + title: title, + file: editor.settings.external_filemanager_path+'dialog.php?type=4&descending='+descending+sort_by+fldr+'&lang='+editor.settings.language+'&akey='+akey, + width: 860, + height: 570, + inline: 1, + resizable: true, + maximizable: true + }); + } + + editor.addButton('responsivefilemanager', { + icon: 'browse', + tooltip: 'Insert file', + shortcut: 'Ctrl+E', + onclick:openmanager + }); + + editor.addShortcut('Ctrl+E', '', openmanager); + + editor.addMenuItem('responsivefilemanager', { + icon: 'browse', + text: 'Insert file', + shortcut: 'Ctrl+E', + onclick: openmanager, + context: 'insert' + }); + +}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/plugin.min.js new file mode 100644 index 0000000..d5db47e --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/responsivefilemanager/plugin.min.js @@ -0,0 +1,9 @@ +/** + * plugin.js + * + * Copyright, Alberto Peripolli + * Released under Creative Commons Attribution-NonCommercial 3.0 Unported License. + * + * Contributing: https://github.com/trippo/ResponsiveFilemanager + */ +tinymce.PluginManager.add("responsivefilemanager",function(e){function t(){e.focus(true);var t="RESPONSIVE FileManager";if(typeof e.settings.filemanager_title!=="undefined"&&e.settings.filemanager_title){t=e.settings.filemanager_title}var n="key";if(typeof e.settings.filemanager_access_key!=="undefined"&&e.settings.filemanager_access_key){n=e.settings.filemanager_access_key}var r="";if(typeof e.settings.filemanager_sort_by!=="undefined"&&e.settings.filemanager_sort_by){r="&sort_by="+e.settings.filemanager_sort_by}var i="false";if(typeof e.settings.filemanager_descending!=="undefined"&&e.settings.filemanager_descending){i=e.settings.filemanager_descending}var s="";if(typeof e.settings.filemanager_subfolder!=="undefined"&&e.settings.filemanager_subfolder){s="&fldr="+e.settings.filemanager_subfolder}var o=2;if(typeof e.settings.filemanager_type!=="undefined"&&e.settings.filemanager_type){if($.isNumeric(e.settings.filemanager_type)===true&&e.settings.filemanager_type>0&&e.settings.filemanager_type<=3){o=e.settings.filemanager_type}else if(e.settings.filemanager_type=="image"){o=1}else if(e.settings.filemanager_type=="media"){o=3}else{o=2}}win=e.windowManager.open({title:t,file:e.settings.external_filemanager_path+"dialog.php?type=4&descending="+i+r+s+"&lang="+e.settings.language+"&akey="+n,width:860,height:570,inline:1,resizable:true,maximizable:true})}e.addButton("responsivefilemanager",{icon:"browse",tooltip:"Insert file",shortcut:"Ctrl+E",onclick:t});e.addShortcut("Ctrl+E","",t);e.addMenuItem("responsivefilemanager",{icon:"browse",text:"Insert file",shortcut:"Ctrl+E",onclick:t,context:"insert"})}) \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/save/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/save/plugin.min.js new file mode 100644 index 0000000..ff35bb4 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/save/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("save",function(e){function t(){var t;return t=tinymce.DOM.getParent(e.id,"form"),!e.getParam("save_enablewhendirty",!0)||e.isDirty()?(tinymce.triggerSave(),e.getParam("save_onsavecallback")?(e.execCallback("save_onsavecallback",e),void e.nodeChanged()):void(t?(e.setDirty(!1),(!t.onsubmit||t.onsubmit())&&("function"==typeof t.submit?t.submit():n(e.translate("Error: Form submit field collision."))),e.nodeChanged()):n(e.translate("Error: No form element found.")))):void 0}function n(t){e.notificationManager.open({text:t,type:"error"})}function r(){var t=tinymce.trim(e.startContent);return e.getParam("save_oncancelcallback")?void e.execCallback("save_oncancelcallback",e):(e.setContent(t),e.undoManager.clear(),void e.nodeChanged())}function i(){var t=this;e.on("nodeChange dirty",function(){t.disabled(e.getParam("save_enablewhendirty",!0)&&!e.isDirty())})}e.addCommand("mceSave",t),e.addCommand("mceCancel",r),e.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:i}),e.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:i}),e.addShortcut("Meta+S","","mceSave")}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/searchreplace/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/searchreplace/plugin.min.js new file mode 100644 index 0000000..811e3e6 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/searchreplace/plugin.min.js @@ -0,0 +1 @@ +!function(){function e(e){return e&&1==e.nodeType&&"false"===e.contentEditable}function t(t,n,r,i,o){function a(e,t){if(t=t||0,!e[0])throw"findAndReplaceDOMText cannot handle zero-length matches";var n=e.index;if(t>0){var r=e[t];if(!r)throw"Invalid capture group";n+=e[0].indexOf(r),e[0]=r}return[n,n+e[0].length,[e[0]]]}function s(t){var n;if(3===t.nodeType)return t.data;if(m[t.nodeName]&&!p[t.nodeName])return"";if(n="",e(t))return"\n";if((p[t.nodeName]||h[t.nodeName])&&(n+="\n"),t=t.firstChild)do n+=s(t);while(t=t.nextSibling);return n}function l(t,n,r){var i,o,a,s,l=[],c=0,u=t,d=n.shift(),f=0;e:for(;;){if((p[u.nodeName]||h[u.nodeName]||e(u))&&c++,3===u.nodeType&&(!o&&u.length+c>=d[1]?(o=u,s=d[1]-c):i&&l.push(u),!i&&u.length+c>d[0]&&(i=u,a=d[0]-c),c+=u.length),i&&o){if(u=r({startNode:i,startNodeIndex:a,endNode:o,endNodeIndex:s,innerNodes:l,match:d[2],matchIndex:f}),c-=o.length-s,i=null,o=null,l=[],d=n.shift(),f++,!d)break}else if(m[u.nodeName]&&!p[u.nodeName]||!u.firstChild){if(u.nextSibling){u=u.nextSibling;continue}}else if(!e(u)){u=u.firstChild;continue}for(;;){if(u.nextSibling){u=u.nextSibling;break}if(u.parentNode===t)break e;u=u.parentNode}}}function c(e){var t;if("function"!=typeof e){var n=e.nodeType?e:f.createElement(e);t=function(e,t){var r=n.cloneNode(!1);return r.setAttribute("data-mce-index",t),e&&r.appendChild(f.createTextNode(e)),r}}else t=e;return function(e){var n,r,i,o=e.startNode,a=e.endNode,s=e.matchIndex;if(o===a){var l=o;i=l.parentNode,e.startNodeIndex>0&&(n=f.createTextNode(l.data.substring(0,e.startNodeIndex)),i.insertBefore(n,l));var c=t(e.match[0],s);return i.insertBefore(c,l),e.endNodeIndexp;++p){var h=e.innerNodes[p],g=t(h.data,s);h.parentNode.replaceChild(g,h),d.push(g)}var v=t(a.data.substring(0,e.endNodeIndex),s);return i=o.parentNode,i.insertBefore(n,o),i.insertBefore(u,o),i.removeChild(o),i=a.parentNode,i.insertBefore(v,a),i.insertBefore(r,a),i.removeChild(a),v}}var u,d,f,p,m,h,g=[],v=0;if(f=n.ownerDocument,p=o.getBlockElements(),m=o.getWhiteSpaceElements(),h=o.getShortEndedElements(),d=s(n)){if(t.global)for(;u=t.exec(d);)g.push(a(u,i));else u=d.match(t),g.push(a(u,i));return g.length&&(v=g.length,l(n,g,c(r))),v}}function n(e){function n(){function t(){o.statusbar.find("#next").disabled(!a(d+1).length),o.statusbar.find("#prev").disabled(!a(d-1).length)}function n(){tinymce.ui.MessageBox.alert("Could not find the specified string.",function(){o.find("#find")[0].focus()})}var r,i={};r=tinymce.trim(e.selection.getContent({format:"text"}));var o=tinymce.ui.Factory.create({type:"window",layout:"flex",pack:"center",align:"center",onClose:function(){e.focus(),u.done()},onSubmit:function(e){var r,s,l,c;return e.preventDefault(),s=o.find("#case").checked(),c=o.find("#words").checked(),l=o.find("#find").value(),l.length?i.text==l&&i.caseState==s&&i.wholeWord==c?0===a(d+1).length?void n():(u.next(),void t()):(r=u.find(l,s,c),r||n(),o.statusbar.items().slice(1).disabled(0===r),t(),void(i={text:l,caseState:s,wholeWord:c})):(u.done(!1),void o.statusbar.items().slice(1).disabled(!0))},buttons:[{text:"Find",subtype:"primary",onclick:function(){o.submit()}},{text:"Replace",disabled:!0,onclick:function(){u.replace(o.find("#replace").value())||(o.statusbar.items().slice(1).disabled(!0),d=-1,i={})}},{text:"Replace all",disabled:!0,onclick:function(){u.replace(o.find("#replace").value(),!0,!0),o.statusbar.items().slice(1).disabled(!0),i={}}},{type:"spacer",flex:1},{text:"Prev",name:"prev",disabled:!0,onclick:function(){u.prev(),t()}},{text:"Next",name:"next",disabled:!0,onclick:function(){u.next(),t()}}],title:"Find and replace",items:{type:"form",padding:20,labelGap:30,spacing:10,items:[{type:"textbox",name:"find",size:40,label:"Find",value:r},{type:"textbox",name:"replace",size:40,label:"Replace with"},{type:"checkbox",name:"case",text:"Match case",label:" "},{type:"checkbox",name:"words",text:"Whole words",label:" "}]}}).renderTo().reflow()}function r(e){var t=e.getAttribute("data-mce-index");return"number"==typeof t?""+t:t}function i(n){var r,i;return i=e.dom.create("span",{"data-mce-bogus":1}),i.className="mce-match-marker",r=e.getBody(),u.done(!1),t(n,r,i,!1,e.schema)}function o(e){var t=e.parentNode;e.firstChild&&t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function a(t){var n,i=[];if(n=tinymce.toArray(e.getBody().getElementsByTagName("span")),n.length)for(var o=0;o0}var u=this,d=-1;u.init=function(e){e.addMenuItem("searchreplace",{text:"Find and replace",shortcut:"Meta+F",onclick:n,separator:"before",context:"edit"}),e.addButton("searchreplace",{tooltip:"Find and replace",shortcut:"Meta+F",onclick:n}),e.addCommand("SearchReplace",n),e.shortcuts.add("Meta+F","",n)},u.find=function(e,t,n){e=e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),e=n?"\\b"+e+"\\b":e;var r=i(new RegExp(e,t?"g":"gi"));return r&&(d=-1,d=s(!0)),r},u.next=function(){var e=s(!0);-1!==e&&(d=e)},u.prev=function(){var e=s(!1);-1!==e&&(d=e)},u.replace=function(t,n,i){var s,f,p,m,h,g,v=d;for(n=n!==!1,p=e.getBody(),f=tinymce.grep(tinymce.toArray(p.getElementsByTagName("span")),c),s=0;sd&&f[s].setAttribute("data-mce-index",h-1)}return e.undoManager.add(),d=v,n?(g=a(v+1).length>0,u.next()):(g=a(v-1).length>0,u.prev()),!i&&g},u.done=function(t){var n,i,a,s;for(i=tinymce.toArray(e.getBody().getElementsByTagName("span")),n=0;n=l.end?(o=d,s=l.end-u):i&&c.push(d),!i&&d.length+u>l.start&&(i=d,a=l.start-u),u+=d.length),i&&o){if(d=r({startNode:i,startNodeIndex:a,endNode:o,endNodeIndex:s,innerNodes:c,match:l.text,matchIndex:f}),u-=o.length-s,i=null,o=null,c=[],l=n.shift(),f++,!l)break}else if(_[d.nodeName]&&!N[d.nodeName]||!d.firstChild){if(d.nextSibling){d=d.nextSibling;continue}}else if(!e(d)){d=d.firstChild;continue}for(;;){if(d.nextSibling){d=d.nextSibling;break}if(d.parentNode===t)break e;d=d.parentNode}}}function a(e){function t(t,n){var r=k[n];r.stencil||(r.stencil=e(r));var i=r.stencil.cloneNode(!1);return i.setAttribute("data-mce-index",n),t&&i.appendChild(S.doc.createTextNode(t)),i}return function(e){var n,r,i,o=e.startNode,a=e.endNode,s=e.matchIndex,l=S.doc;if(o===a){var c=o;i=c.parentNode,e.startNodeIndex>0&&(n=l.createTextNode(c.data.substring(0,e.startNodeIndex)),i.insertBefore(n,c));var u=t(e.match,s);return i.insertBefore(u,c),e.endNodeIndexp;++p){var h=e.innerNodes[p],g=t(h.data,s);h.parentNode.replaceChild(g,h),f.push(g)}var v=t(a.data.substring(0,e.endNodeIndex),s);return i=o.parentNode,i.insertBefore(n,o),i.insertBefore(d,o),i.removeChild(o),i=a.parentNode,i.insertBefore(v,a),i.insertBefore(r,a),i.removeChild(a),v}}function s(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function l(e){var n=t.getElementsByTagName("*"),r=[];e="number"==typeof e?""+e:null;for(var i=0;it&&e(k[t],t)!==!1;t++);return this}function f(e){return k.length&&o(t,k,a(e)),this}function p(e,t){if(w&&e.global)for(;C=e.exec(w);)k.push(r(C,t));return this}function m(e){var t,n=l(e?c(e):null);for(t=n.length;t--;)s(n[t]);return this}function h(e){return k[e.getAttribute("data-mce-index")]}function g(e){return l(c(e))[0]}function v(e,t,n){return k.push({start:e,end:e+t,text:w.substr(e,t),data:n}),this}function y(e){var t=l(c(e)),r=n.dom.createRng();return r.setStartBefore(t[0]),r.setEndAfter(t[t.length-1]),r}function b(e,t){var r=y(e);return r.deleteContents(),t.length>0&&r.insertNode(n.dom.doc.createTextNode(t)),r}function x(){return k.splice(0,k.length),m(),this}var C,w,N,_,E,k=[],S=n.dom;return N=n.schema.getBlockElements(),_=n.schema.getWhiteSpaceElements(),E=n.schema.getShortEndedElements(),w=i(t),{text:w,matches:k,each:d,filter:u,reset:x,matchFromElement:h,elementFromMatch:g,find:p,add:v,wrap:f,unwrap:m,replace:b,rangeFromMatch:y,indexOf:c}}}),r("tinymce/spellcheckerplugin/Plugin",["tinymce/spellcheckerplugin/DomTextMatcher","tinymce/PluginManager","tinymce/util/Tools","tinymce/ui/Menu","tinymce/dom/DOMUtils","tinymce/util/XHR","tinymce/util/URI","tinymce/util/JSON"],function(e,t,n,r,i,o,a,s){t.add("spellchecker",function(t,l){function c(){return A.textMatcher||(A.textMatcher=new e(t.getBody(),t)),A.textMatcher}function u(e,t){var r=[];return n.each(t,function(e){r.push({selectable:!0,text:e.name,data:e.value})}),r}function d(e){for(var t in e)return!1;return!0}function f(e,o){var a=[],s=k[e];n.each(s,function(e){a.push({text:e,onclick:function(){t.insertContent(t.dom.encode(e)),t.dom.remove(o),v()}})}),a.push({text:"-"}),R&&a.push({text:"Add to Dictionary",onclick:function(){y(e,o)}}),a.push.apply(a,[{text:"Ignore",onclick:function(){b(e,o)}},{text:"Ignore all",onclick:function(){b(e,o,!0)}}]),T=new r({items:a,context:"contextmenu",onautohide:function(e){-1!=e.target.className.indexOf("spellchecker")&&e.preventDefault()},onhide:function(){T.remove(),T=null}}),T.renderTo(document.body);var l=i.DOM.getPos(t.getContentAreaContainer()),c=t.dom.getPos(o[0]),u=t.dom.getRoot();"BODY"==u.nodeName?(c.x-=u.ownerDocument.documentElement.scrollLeft||u.scrollLeft,c.y-=u.ownerDocument.documentElement.scrollTop||u.scrollTop):(c.x-=u.scrollLeft,c.y-=u.scrollTop),l.x+=c.x,l.y+=c.y,T.moveTo(l.x,l.y+o[0].offsetHeight)}function p(){return t.getParam("spellchecker_wordchar_pattern")||new RegExp('[^\\s!"#$%&()*+,-./:;<=>?@[\\]^_{|}`\xa7\xa9\xab\xae\xb1\xb6\xb7\xb8\xbb\xbc\xbd\xbe\xbf\xd7\xf7\xa4\u201d\u201c\u201e\xa0\u2002\u2003\u2009]+',"g")}function m(e,r,i,c){var u={method:e},d="";"spellcheck"==e&&(u.text=r,u.lang=B.spellchecker_language),"addToDictionary"==e&&(u.word=r),n.each(u,function(e,t){d&&(d+="&"),d+=t+"="+encodeURIComponent(e)}),o.send({url:new a(l).toAbsolute(B.spellchecker_rpc_url),type:"post",content_type:"application/x-www-form-urlencoded",data:d,success:function(e){if(e=s.parse(e))e.error?c(e.error):i(e);else{var n=t.translate("Server response wasn't proper JSON.");c(n)}},error:function(){var e=t.translate("The spelling service was not found: (")+B.spellchecker_rpc_url+t.translate(")");c(e)}})}function h(e,t,n,r){var i=B.spellchecker_callback||m;i.call(A,e,t,n,r)}function g(){function e(e){t.notificationManager.open({text:e,type:"error"}),t.setProgressState(!1),x()}x()||(t.setProgressState(!0),h("spellcheck",c().text,_,e),t.focus())}function v(){t.dom.select("span.mce-spellchecker-word").length||x()}function y(e,n){t.setProgressState(!0),h("addToDictionary",e,function(){t.setProgressState(!1),t.dom.remove(n,!0),v()},function(e){t.notificationManager.open({text:e,type:"error"}),t.setProgressState(!1)})}function b(e,r,i){t.selection.collapse(),i?n.each(t.dom.select("span.mce-spellchecker-word"),function(n){n.getAttribute("data-mce-word")==e&&t.dom.remove(n,!0)}):t.dom.remove(r,!0),v()}function x(){return c().reset(),A.textMatcher=null,S?(S=!1,t.fire("SpellcheckEnd"),!0):void 0}function C(e){var t=e.getAttribute("data-mce-index");return"number"==typeof t?""+t:t}function w(e){var r,i=[];if(r=n.toArray(t.getBody().getElementsByTagName("span")),r.length)for(var o=0;o0){var i=t.dom.createRng();i.setStartBefore(r[0]),i.setEndAfter(r[r.length-1]),t.selection.setRng(i),f(n.getAttribute("data-mce-word"),r)}}}),t.addMenuItem("spellchecker",{text:"Spellcheck",context:"tools",onclick:g,selectable:!0,onPostRender:function(){var e=this;e.active(S),t.on("SpellcheckStart SpellcheckEnd",function(){e.active(S)})}});var M={tooltip:"Spellcheck",onclick:g,onPostRender:function(){var e=this;t.on("SpellcheckStart SpellcheckEnd",function(){e.active(S)})}};E.length>1&&(M.type="splitbutton",M.menu=E,M.onshow=N,M.onselect=function(e){B.spellchecker_language=e.control.settings.data}),t.addButton("spellchecker",M),t.addCommand("mceSpellCheck",g),t.on("remove",function(){T&&(T.remove(),T=null)}),t.on("change",v),this.getTextMatcher=c,this.getWordCharPattern=p,this.markErrors=_,this.getLanguage=function(){return B.spellchecker_language},B.spellchecker_language=B.spellchecker_language||B.language||"en"})}),o(["tinymce/spellcheckerplugin/DomTextMatcher"])}(this); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/tabfocus/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/tabfocus/plugin.min.js new file mode 100644 index 0000000..25a990f --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/tabfocus/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("tabfocus",function(e){function t(e){9!==e.keyCode||e.ctrlKey||e.altKey||e.metaKey||e.preventDefault()}function n(t){function n(n){function o(e){return"BODY"===e.nodeName||"hidden"!=e.type&&"none"!=e.style.display&&"hidden"!=e.style.visibility&&o(e.parentNode)}function l(e){return/INPUT|TEXTAREA|BUTTON/.test(e.tagName)&&tinymce.get(t.id)&&-1!=e.tabIndex&&o(e)}if(s=r.select(":input:enabled,*[tabindex]:not(iframe)"),i(s,function(t,n){return t.id==e.id?(a=n,!1):void 0}),n>0){for(c=a+1;c=0;c--)if(l(s[c]))return s[c];return null}var a,s,l,c;if(!(9!==t.keyCode||t.ctrlKey||t.altKey||t.metaKey||t.isDefaultPrevented())&&(l=o(e.getParam("tab_focus",e.getParam("tabfocus_elements",":prev,:next"))),1==l.length&&(l[1]=l[0],l[0]=":prev"),s=t.shiftKey?":prev"==l[0]?n(-1):r.get(l[0]):":next"==l[1]?n(1):r.get(l[1]))){var u=tinymce.get(s.id||s.name);s.id&&u?u.focus():tinymce.util.Delay.setTimeout(function(){tinymce.Env.webkit||window.focus(),s.focus()},10),t.preventDefault()}}var r=tinymce.DOM,i=tinymce.each,o=tinymce.explode;e.on("init",function(){e.inline&&tinymce.DOM.setAttrib(e.getBody(),"tabIndex",null),e.on("keyup",t),tinymce.Env.gecko?e.on("keypress keydown",n):e.on("keydown",n)})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/table/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/table/plugin.min.js new file mode 100644 index 0000000..d9f89ca --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/table/plugin.min.js @@ -0,0 +1,2 @@ +!function(e,t){"use strict";function n(e,t){for(var n,r=[],a=0;a10)&&(t.innerHTML='
')}return{getSpanVal:t,paddCell:n}}),r("tinymce/tableplugin/TableGrid",["tinymce/util/Tools","tinymce/Env","tinymce/tableplugin/Utils"],function(e,n,r){var i=e.each,o=r.getSpanVal;return function(a,s){function l(e){return e===a.getBody()}function c(){var e=0;L=[],H=0,i(["thead","tbody","tfoot"],function(t){var n=W.select("> "+t+" tr",s);i(n,function(n,r){r+=e,i(W.select("> td, > th",n),function(e,n){var i,a,s,l;if(L[r])for(;L[r][n];)n++;for(s=o(e,"rowspan"),l=o(e,"colspan"),a=r;r+s>a;a++)for(L[a]||(L[a]=[]),i=n;n+l>i;i++)L[a][i]={part:t,real:a==r&&i==n,elm:e,rowspan:s,colspan:l};H=Math.max(H,n+1)})}),e+=n.length})}function u(e,t){return e=e.cloneNode(t),e.removeAttribute("id"),e}function d(e,t){var n;return n=L[t],n?n[e]:void 0}function f(e,t,n){e&&(n=parseInt(n,10),1===n?e.removeAttribute(t,1):e.setAttribute(t,n,1))}function p(e){return e&&(W.hasClass(e.elm,"mce-item-selected")||e==F)}function m(){var e=[];return i(s.rows,function(t){i(t.cells,function(n){return W.hasClass(n,"mce-item-selected")||F&&n==F.elm?(e.push(t),!1):void 0})}),e}function h(){var e=W.createRng();l(s)||(e.setStartAfter(s),e.setEndAfter(s),z.setRng(e),W.remove(s))}function g(t){var o,s={};return a.settings.table_clone_elements!==!1&&(s=e.makeMap((a.settings.table_clone_elements||"strong em b i span font h1 h2 h3 h4 h5 h6 p div").toUpperCase(),/[ ,]/)),e.walk(t,function(e){var r;return 3==e.nodeType?(i(W.getParents(e.parentNode,null,t).reverse(),function(e){s[e.nodeName]&&(e=u(e,!1),o?r&&r.appendChild(e):o=r=e,r=e)}),r&&(r.innerHTML=n.ie?" ":'
'),!1):void 0},"childNodes"),t=u(t,!1),f(t,"rowSpan",1),f(t,"colSpan",1),o?t.appendChild(o):r.paddCell(t),t}function v(){var e,t=W.createRng();return i(W.select("tr",s),function(e){0===e.cells.length&&W.remove(e)}),0===W.select("tr",s).length?(t.setStartBefore(s),t.setEndBefore(s),z.setRng(t),void W.remove(s)):(i(W.select("thead,tbody,tfoot",s),function(e){0===e.rows.length&&W.remove(e)}),c(),void(I&&(e=L[Math.min(L.length-1,I.y)],e&&(z.select(e[Math.min(e.length-1,I.x)].elm,!0),z.collapse(!0)))))}function y(e,t,n,r){var i,o,a,s,l;for(i=L[t][e].elm.parentNode,a=1;n>=a;a++)if(i=W.getNext(i,"tr")){for(o=e;o>=0;o--)if(l=L[t+a][o].elm,l.parentNode==i){for(s=1;r>=s;s++)W.insertAfter(g(l),l);break}if(-1==o)for(s=1;r>=s;s++)i.insertBefore(g(i.cells[0]),i.cells[0])}}function b(){i(L,function(e,t){i(e,function(e,n){var r,i,a;if(p(e)&&(e=e.elm,r=o(e,"colspan"),i=o(e,"rowspan"),r>1||i>1)){for(f(e,"rowSpan",1),f(e,"colSpan",1),a=0;r-1>a;a++)W.insertAfter(g(e),e);y(n,t,i-1,r)}})})}function x(t,n,r){var o,a,s,l,u,m,h,g,y,x,C;if(t?(o=A(t),a=o.x,s=o.y,l=a+(n-1),u=s+(r-1)):(I=O=null,i(L,function(e,t){i(e,function(e,n){p(e)&&(I||(I={x:n,y:t}),O={x:n,y:t})})}),I&&(a=I.x,s=I.y,l=O.x,u=O.y)),g=d(a,s),y=d(l,u),g&&y&&g.part==y.part){for(b(),c(),g=d(a,s).elm,f(g,"colSpan",l-a+1),f(g,"rowSpan",u-s+1),h=s;u>=h;h++)for(m=a;l>=m;m++)L[h]&&L[h][m]&&(t=L[h][m].elm,t!=g&&(x=e.grep(t.childNodes),i(x,function(e){g.appendChild(e)}),x.length&&(x=e.grep(g.childNodes),C=0,i(x,function(e){"BR"==e.nodeName&&W.getAttrib(e,"data-mce-bogus")&&C++0&&L[n-1][s]&&(m=L[n-1][s].elm,h=o(m,"rowSpan"),h>1)){f(m,"rowSpan",h+1);continue}}else if(h=o(r,"rowspan"),h>1){f(r,"rowSpan",h+1);continue}d=g(r),f(d,"colSpan",r.colSpan),c.appendChild(d),a=r}c.hasChildNodes()&&(e?l.parentNode.insertBefore(c,l):W.insertAfter(c,l))}}function w(e){var t,n;i(L,function(n){return i(n,function(n,r){return p(n)&&(t=r,e)?!1:void 0}),e?!t:void 0}),i(L,function(r,i){var a,s,l;r[t]&&(a=r[t].elm,a!=n&&(l=o(a,"colspan"),s=o(a,"rowspan"),1==l?e?(a.parentNode.insertBefore(g(a),a),y(t,i,s-1,l)):(W.insertAfter(g(a),a),y(t,i,s-1,l)):f(a,"colSpan",a.colSpan+1),n=a))})}function N(t){return e.grep(_(t),p)}function _(e){var t=[];return i(e,function(e){i(e,function(e){t.push(e)})}),t}function E(){var t=[];if(l(s)){if(1==L[0].length)return;if(N(L).length==_(L).length)return}i(L,function(n){i(n,function(n,r){p(n)&&-1===e.inArray(t,r)&&(i(L,function(e){var t,n=e[r].elm;t=o(n,"colSpan"),t>1?f(n,"colSpan",t-1):W.remove(n)}),t.push(r))})}),v()}function k(){function e(e){var t,n;i(e.cells,function(e){var n=o(e,"rowSpan");n>1&&(f(e,"rowSpan",n-1),t=A(e),y(t.x,t.y,1,1))}),t=A(e.cells[0]),i(L[t.y],function(e){var t;e=e.elm,e!=n&&(t=o(e,"rowSpan"),1>=t?W.remove(e):f(e,"rowSpan",t-1),n=e)})}var t;t=m(),l(s)&&t.length==s.rows.length||(i(t.reverse(),function(t){e(t)}),v())}function S(){var e=m();if(!l(s)||e.length!=s.rows.length)return W.remove(e),v(),e}function T(){var e=m();return i(e,function(t,n){e[n]=u(t,!0)}),e}function R(e,t){var n=m(),r=n[t?0:n.length-1],o=r.cells.length;e&&(i(L,function(e){var t;return o=0,i(e,function(e){e.real&&(o+=e.colspan),e.elm.parentNode==r&&(t=1)}),t?!1:void 0}),t||e.reverse(),i(e,function(e){var n,i,a=e.cells.length;for(n=0;a>n;n++)i=e.cells[n],f(i,"colSpan",1),f(i,"rowSpan",1);for(n=a;o>n;n++)e.appendChild(g(e.cells[a-1]));for(n=o;a>n;n++)W.remove(e.cells[n]);t?r.parentNode.insertBefore(e,r):W.insertAfter(e,r)}),W.removeClass(W.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"))}function A(e){var t;return i(L,function(n,r){return i(n,function(n,i){return n.elm==e?(t={x:i,y:r},!1):void 0}),!t}),t}function B(e){I=A(e)}function D(){var e,t;return e=t=0,i(L,function(n,r){i(n,function(n,i){var o,a;p(n)&&(n=L[r][i],i>e&&(e=i),r>t&&(t=r),n.real&&(o=n.colspan-1,a=n.rowspan-1,o&&i+o>e&&(e=i+o),a&&r+a>t&&(t=r+a)))})}),{x:e,y:t}}function M(e){var t,n,r,i,o,a,s,l,c,u;if(O=A(e),I&&O){for(t=Math.min(I.x,O.x),n=Math.min(I.y,O.y),r=Math.max(I.x,O.x),i=Math.max(I.y,O.y),o=r,a=i,u=n;a>=u;u++)e=L[u][t],e.real||t-(e.colspan-1)=c;c++)e=L[n][c],e.real||n-(e.rowspan-1)=u;u++)for(c=t;r>=c;c++)e=L[u][c],e.real&&(s=e.colspan-1,l=e.rowspan-1,s&&c+s>o&&(o=c+s),l&&u+l>a&&(a=u+l));for(W.removeClass(W.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),u=n;a>=u;u++)for(c=t;o>=c;c++)L[u][c]&&W.addClass(L[u][c].elm,"mce-item-selected")}}function P(e,t){var n,r,i;n=A(e),r=n.y*H+n.x;do{if(r+=t,i=d(r%H,Math.floor(r/H)),!i)break;if(i.elm!=e)return z.select(i.elm,!0),W.isEmpty(i.elm)&&z.collapse(!0),!0}while(i.elm==e);return!1}var L,H,I,O,F,z=a.selection,W=z.dom;s=s||W.getParent(z.getStart(!0),"table"),c(),F=W.getParent(z.getStart(!0),"th,td"),F&&(I=A(F),O=D(),F=d(I.x,I.y)),e.extend(this,{deleteTable:h,split:b,merge:x,insertRow:C,insertCol:w,deleteCols:E,deleteRows:k,cutRows:S,copyRows:T,pasteRows:R,getPos:A,setStartCell:B,setEndCell:M,moveRelIdx:P,refresh:c})}}),r("tinymce/tableplugin/Quirks",["tinymce/util/VK","tinymce/util/Delay","tinymce/Env","tinymce/util/Tools","tinymce/tableplugin/Utils"],function(e,t,n,r,i){var o=r.each,a=i.getSpanVal;return function(s){function l(){function n(n){function r(e,t){var r=e?"previousSibling":"nextSibling",o=s.dom.getParent(t,"tr"),a=o[r];if(a)return v(s,t,a,e),n.preventDefault(),!0;var l=s.dom.getParent(o,"table"),d=o.parentNode,f=d.nodeName.toLowerCase();if("tbody"===f||f===(e?"tfoot":"thead")){var p=i(e,l,d,"tbody");if(null!==p)return c(e,p,t)}return u(e,o,r,l)}function i(e,t,n,r){var i=s.dom.select(">"+r,t),o=i.indexOf(n);if(e&&0===o||!e&&o===i.length-1)return l(e,t);if(-1===o){var a="thead"===n.tagName.toLowerCase()?0:i.length-1;return i[a]}return i[o+(e?-1:1)]}function l(e,t){var n=e?"thead":"tfoot",r=s.dom.select(">"+n,t);return 0!==r.length?r[0]:null}function c(e,t,r){var i=d(t,e);return i&&v(s,r,i,e),n.preventDefault(),!0}function u(e,t,i,o){var a=o[i];if(a)return f(a),!0;var l=s.dom.getParent(o,"td,th");if(l)return r(e,l,n);var c=d(t,!e);return f(c),n.preventDefault(),!1}function d(e,t){var n=e&&e[t?"lastChild":"firstChild"];return n&&"BR"===n.nodeName?s.dom.getParent(n,"td,th"):n}function f(e){s.selection.setCursorLocation(e,0)}function p(){return x==e.UP||x==e.DOWN}function m(e){var t=e.selection.getNode(),n=e.dom.getParent(t,"tr");return null!==n}function h(e){for(var t=0,n=e;n.previousSibling;)n=n.previousSibling,t+=a(n,"colspan");return t}function g(e,t){var n=0,r=0;return o(e.children,function(e,i){return n+=a(e,"colspan"),r=i,n>t?!1:void 0}),r}function v(e,t,n,r){var i=h(s.dom.getParent(t,"td,th")),o=g(n,i),a=n.childNodes[o],l=d(a,r);f(l||a)}function y(e){var t=s.selection.getNode(),n=s.dom.getParent(t,"td,th"),r=s.dom.getParent(e,"td,th");return n&&n!==r&&b(n,r)}function b(e,t){return s.dom.getParent(e,"TABLE")===s.dom.getParent(t,"TABLE")}var x=n.keyCode;if(p()&&m(s)){var C=s.selection.getNode();t.setEditorTimeout(s,function(){y(C)&&r(!n.shiftKey&&x===e.UP,C,n)},0)}}s.on("KeyDown",function(e){n(e)})}function c(){function e(e,t){var n,r=t.ownerDocument,i=r.createRange();return i.setStartBefore(t),i.setEnd(e.endContainer,e.endOffset),n=r.createElement("body"),n.appendChild(i.cloneContents()),0===n.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length}s.on("KeyDown",function(t){var n,r,i=s.dom;(37==t.keyCode||38==t.keyCode)&&(n=s.selection.getRng(),r=i.getParent(n.startContainer,"table"),r&&s.getBody().firstChild==r&&e(n,r)&&(n=i.createRng(),n.setStartBefore(r),n.setEndBefore(r),s.selection.setRng(n),t.preventDefault()))})}function u(){s.on("KeyDown SetContent VisualAid",function(){var e;for(e=s.getBody().lastChild;e;e=e.previousSibling)if(3==e.nodeType){if(e.nodeValue.length>0)break}else if(1==e.nodeType&&("BR"==e.tagName||!e.getAttribute("data-mce-bogus")))break;e&&"TABLE"==e.nodeName&&(s.settings.forced_root_block?s.dom.add(s.getBody(),s.settings.forced_root_block,s.settings.forced_root_block_attrs,n.ie&&n.ie<11?" ":'
'):s.dom.add(s.getBody(),"br",{"data-mce-bogus":"1"}))}),s.on("PreProcess",function(e){var t=e.node.lastChild;t&&("BR"==t.nodeName||1==t.childNodes.length&&("BR"==t.firstChild.nodeName||"\xa0"==t.firstChild.nodeValue))&&t.previousSibling&&"TABLE"==t.previousSibling.nodeName&&s.dom.remove(t)})}function d(){function e(e,t,n,r){var i,o,a,s=3,l=e.dom.getParent(t.startContainer,"TABLE");return l&&(i=l.parentNode),o=t.startContainer.nodeType==s&&0===t.startOffset&&0===t.endOffset&&r&&("TR"==n.nodeName||n==i),a=("TD"==n.nodeName||"TH"==n.nodeName)&&!r,o||a}function t(){var t=s.selection.getRng(),n=s.selection.getNode(),r=s.dom.getParent(t.startContainer,"TD,TH");if(e(s,t,n,r)){r||(r=n);for(var i=r.lastChild;i.lastChild;)i=i.lastChild;3==i.nodeType&&(t.setEnd(i,i.data.length),s.selection.setRng(t))}}s.on("KeyDown",function(){t()}),s.on("MouseDown",function(e){2!=e.button&&t()})}function f(){function t(e){s.selection.select(e,!0),s.selection.collapse(!0)}function n(e){s.$(e).empty(),i.paddCell(e)}s.on("keydown",function(i){if((i.keyCode==e.DELETE||i.keyCode==e.BACKSPACE)&&!i.isDefaultPrevented()){var o,a,l,c;if(o=s.dom.getParent(s.selection.getStart(),"table")){if(a=s.dom.select("td,th",o),l=r.grep(a,function(e){return s.dom.hasClass(e,"mce-item-selected")}),0===l.length)return c=s.dom.getParent(s.selection.getStart(),"td,th"),void(s.selection.isCollapsed()&&c&&s.dom.isEmpty(c)&&(i.preventDefault(),n(c),t(c)));i.preventDefault(),s.undoManager.transact(function(){a.length==l.length?s.execCommand("mceTableDelete"):(r.each(l,n),t(l[0]))})}}})}f(),n.webkit&&(l(),d()),n.gecko&&(c(),u()),n.ie>10&&(c(),u())}}),r("tinymce/tableplugin/CellSelection",["tinymce/tableplugin/TableGrid","tinymce/dom/TreeWalker","tinymce/util/Tools"],function(e,t,n){return function(r){function i(e){r.getBody().style.webkitUserSelect="",(e||d)&&(r.dom.removeClass(r.dom.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=!1)}function o(t){var n,i,o=t.target;if(!c&&s&&(a||o!=s)&&("TD"==o.nodeName||"TH"==o.nodeName)){i=u.getParent(o,"table"),i==l&&(a||(a=new e(r,i),a.setStartCell(s),r.getBody().style.webkitUserSelect="none"),a.setEndCell(o),d=!0),n=r.selection.getSel();try{n.removeAllRanges?n.removeAllRanges():n.empty()}catch(f){}t.preventDefault()}}var a,s,l,c,u=r.dom,d=!0;return r.on("MouseDown",function(e){2==e.button||c||(i(),s=u.getParent(e.target,"td,th"),l=u.getParent(s,"table"))}),r.on("mouseover",o),r.on("remove",function(){u.unbind(r.getDoc(),"mouseover",o)}),r.on("MouseUp",function(){function e(e,r){var o=new t(e,e);do{if(3==e.nodeType&&0!==n.trim(e.nodeValue).length)return void(r?i.setStart(e,0):i.setEnd(e,e.nodeValue.length));if("BR"==e.nodeName)return void(r?i.setStartBefore(e):i.setEndBefore(e))}while(e=r?o.next():o.prev())}var i,o,c,d,f,p=r.selection;if(s){if(a&&(r.getBody().style.webkitUserSelect=""),o=u.select("td.mce-item-selected,th.mce-item-selected"),o.length>0){i=u.createRng(),d=o[0],i.setStartBefore(d),i.setEndAfter(d),e(d,1),c=new t(d,u.getParent(o[0],"table"));do if("TD"==d.nodeName||"TH"==d.nodeName){if(!u.hasClass(d,"mce-item-selected"))break;f=d}while(d=c.next());e(f),p.setRng(i)}r.nodeChanged(),s=a=l=null}}),r.on("KeyUp Drop SetContent",function(e){i("setcontent"==e.type),s=a=l=null,c=!1}),r.on("ObjectResizeStart ObjectResized",function(e){c="objectresized"!=e.type}),{clear:i}}}),r("tinymce/tableplugin/Dialogs",["tinymce/util/Tools","tinymce/Env"],function(e,t){var n=e.each;return function(r){function i(){var e=r.settings.color_picker_callback;return e?function(){var t=this;e.call(r,function(e){t.value(e).fire("change")},t.value())}:void 0}function o(e){return{title:"Advanced",type:"form",defaults:{onchange:function(){d(e,this.parents().reverse()[0],"style"==this.name())}},items:[{label:"Style",name:"style",type:"textbox"},{type:"form",padding:0,formItemDefaults:{layout:"grid",alignH:["start","right"]},defaults:{size:7},items:[{label:"Border color",type:"colorbox",name:"borderColor",onaction:i()},{label:"Background color",type:"colorbox",name:"backgroundColor",onaction:i()}]}]}}function a(e){return e?e.replace(/px$/,""):""}function s(e){return/^[0-9]+$/.test(e)&&(e+="px"),e}function l(e){n("left center right".split(" "),function(t){r.formatter.remove("align"+t,{},e)})}function c(e){n("top middle bottom".split(" "),function(t){r.formatter.remove("valign"+t,{},e)})}function u(t,n,r){function i(t,r){return r=r||[],e.each(t,function(e){var t={text:e.text||e.title};e.menu?t.menu=i(e.menu):(t.value=e.value,n&&n(t)),r.push(t)}),r}return i(t,r||[])}function d(e,t,n){var r=t.toJSON(),i=e.parseStyle(r.style);n?(t.find("#borderColor").value(i["border-color"]||"")[0].fire("change"),t.find("#backgroundColor").value(i["background-color"]||"")[0].fire("change")):(i["border-color"]=r.borderColor,i["background-color"]=r.backgroundColor),t.find("#style").value(e.serializeStyle(e.parseStyle(e.serializeStyle(i))))}function f(e,t,n){var r=e.parseStyle(e.getAttrib(n,"style"));r["border-color"]&&(t.borderColor=r["border-color"]),r["background-color"]&&(t.backgroundColor=r["background-color"]),t.style=e.serializeStyle(r)}function p(e,t,r){var i=e.parseStyle(e.getAttrib(t,"style"));n(r,function(e){i[e.name]=e.value}),e.setAttrib(t,"style",e.serializeStyle(e.parseStyle(e.serializeStyle(i))))}var m=this;m.tableProps=function(){m.table(!0)},m.table=function(i){function c(){function n(e,t,r){if("TD"===e.tagName||"TH"===e.tagName)C.setStyle(e,t,r);else if(e.children)for(var i=0;i',h.insertBefore(i,h.firstChild)),l(h),w.align&&r.formatter.apply("align"+w.align,{},h),r.focus(),r.addVisual()})}function m(e,t){function n(e,n){for(var r=0;rr;r++)n.push(r);return n}function S(e,t,n){for(var r,i=e(),o=0;o0?y(i,o,a):[],u=s.length>0?y(d,f,s):[];w(c,e.offsetWidth,l),N(u,e.offsetHeight,l)}function B(e,t,n,r){if(0>t||t>=e.length-1)return"";var i=e[t];if(i)i={value:i,delta:0};else for(var o=e.slice(0,t).reverse(),a=0;a0?i:o}function P(t,n,r){for(var i=T(t),o=e.map(i,function(e){return d(e.colIndex,e.element).x}),a=[],s=0;s1?B(o,s):M(i[s].element,n,r);c=c?c:Ce,a.push(c)}return a}function L(e){var t=D(e,"height"),n=parseInt(t,10);return V(t)&&(n=0),!isNaN(n)&&n>0?n:m(e,"height")}function H(t){for(var n=R(t),r=e.map(n,function(e){return i(e.rowIndex,e.element).y}),o=[],a=0;a1?B(r,a):L(n[a].element);l=l?l:we,o.push(l)}return o}function I(t,n,r,i,o){function a(t){return e.map(t,function(){return 0})}function s(){var e;if(o)e=[100-d[0]];else{var t=Math.max(i,d[0]+r);e=[t-d[0]]}return e}function l(e,t){var n,o=a(d.slice(0,e)),s=a(d.slice(t+1));if(r>=0){var l=Math.max(i,d[t]-r);n=o.concat([r,l-d[t]]).concat(s)}else{var c=Math.max(i,d[e]+r),u=d[e]-c;n=o.concat([c-d[e],u]).concat(s)}return n}function c(e,t){var n,o=a(d.slice(0,t));if(r>=0)n=o.concat([r]);else{var s=Math.max(i,d[t]+r);n=o.concat([s-d[t]])}return n}var u,d=t.slice(0);return u=0===t.length?[]:1===t.length?s():0===n?l(0,1):n>0&&ni;i++)r+=n[i];return r}function F(t,n){var r=t.getAllCells();return e.map(r,function(e){var t=O(e.colIndex,e.colIndex+e.colspan,n);return{element:e.element,width:t,colspan:e.colspan}})}function z(t,n){var r=t.getAllCells();return e.map(r,function(e){var t=O(e.rowIndex,e.rowIndex+e.rowspan,n);return{element:e.element,height:t,rowspan:e.rowspan}})}function W(t,n){var r=t.getAllRows();return e.map(r,function(e,t){return{element:e.element,height:n[t]}})}function V(e){return _e.test(e)}function U(e){return Ee.test(e)}function $(t,n,i){function o(t,n){e.each(t,function(e){r.dom.setStyle(e.element,"width",e.width+n),r.dom.setAttrib(e.element,"width",null)})}function a(){return in;n++){for(i+="",r=0;e>r;r++)i+=""+(s.ie?" ":"
")+"";i+=""}return i+="",o.undoManager.transact(function(){o.insertContent(i),a=o.dom.get("__mce"),o.dom.setAttrib(a,"id",null),o.dom.setAttribs(a,o.settings.table_default_attributes||{}),o.dom.setStyles(a,o.settings.table_default_styles||{})}),a}function c(e,t){function n(){e.disabled(!o.dom.getParent(o.selection.getStart(),t)),o.selection.selectorChanged(t,function(t){e.disabled(!t)})}o.initialized?n():o.on("init",n)}function d(){c(this,"table")}function f(){c(this,"td,th")}function p(){var e="";e='';for(var t=0;10>t;t++){e+="";for(var n=0;10>n;n++)e+='';e+=""}return e+="
",e+=''}function m(e,t,n){var r,i,a,s,l,c=n.getEl().getElementsByTagName("table")[0],u=n.isRtl()||"tl-tr"==n.parent().rel;for(c.nextSibling.innerHTML=e+1+" x "+(t+1),u&&(e=9-e),i=0;10>i;i++)for(r=0;10>r;r++)s=c.rows[i].childNodes[r].firstChild,l=(u?r>=e:e>=r)&&t>=i,o.dom.toggleClass(s,"mce-active",l),l&&(a=s);return a.parentNode}function h(){o.addButton("tableprops",{title:"Table properties",onclick:C.tableProps,icon:"table"}),o.addButton("tabledelete",{title:"Delete table",onclick:a("mceTableDelete")}),o.addButton("tablecellprops",{title:"Cell properties",onclick:a("mceTableCellProps")}),o.addButton("tablemergecells",{title:"Merge cells",onclick:a("mceTableMergeCells")}),o.addButton("tablesplitcells",{title:"Split cell",onclick:a("mceTableSplitCells")}),o.addButton("tableinsertrowbefore",{title:"Insert row before",onclick:a("mceTableInsertRowBefore")}),o.addButton("tableinsertrowafter",{title:"Insert row after",onclick:a("mceTableInsertRowAfter")}),o.addButton("tabledeleterow",{title:"Delete row",onclick:a("mceTableDeleteRow")}),o.addButton("tablerowprops",{title:"Row properties",onclick:a("mceTableRowProps")}),o.addButton("tablecutrow",{title:"Cut row",onclick:a("mceTableCutRow")}),o.addButton("tablecopyrow",{title:"Copy row",onclick:a("mceTableCopyRow")}),o.addButton("tablepasterowbefore",{title:"Paste row before",onclick:a("mceTablePasteRowBefore")}),o.addButton("tablepasterowafter",{title:"Paste row after",onclick:a("mceTablePasteRowAfter")}),o.addButton("tableinsertcolbefore",{title:"Insert column before",onclick:a("mceTableInsertColBefore")}),o.addButton("tableinsertcolafter",{title:"Insert column after",onclick:a("mceTableInsertColAfter")}),o.addButton("tabledeletecol",{title:"Delete column",onclick:a("mceTableDeleteCol")})}function g(e){var t=o.dom.is(e,"table")&&o.getBody().contains(e);return t}function v(){var e=o.settings.table_toolbar;""!==e&&e!==!1&&(e||(e="tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol"),o.addContextToolbar(g,e))}var y,b,x=this,C=new r(o);!o.settings.object_resizing||o.settings.object_resizing!==!0&&"table"!==o.settings.object_resizing||(b=i(o)),o.settings.table_grid===!1?o.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",onclick:C.table}):o.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",ariaHideMenu:!0,onclick:function(e){e.aria&&(this.parent().hideAll(),e.stopImmediatePropagation(),C.table())},onshow:function(){m(0,0,this.menu.items()[0])},onhide:function(){var e=this.menu.items()[0].getEl().getElementsByTagName("a");o.dom.removeClass(e,"mce-active"),o.dom.addClass(e[0],"mce-active")},menu:[{type:"container",html:p(),onPostRender:function(){this.lastX=this.lastY=0},onmousemove:function(e){var t,n,r=e.target;"A"==r.tagName.toUpperCase()&&(t=parseInt(r.getAttribute("data-mce-x"),10),n=parseInt(r.getAttribute("data-mce-y"),10),(this.isRtl()||"tl-tr"==this.parent().rel)&&(t=9-t),(t!==this.lastX||n!==this.lastY)&&(m(t,n,e.control),this.lastX=t,this.lastY=n))},onclick:function(e){var t=this;"A"==e.target.tagName.toUpperCase()&&(e.preventDefault(),e.stopPropagation(),t.parent().cancel(),o.undoManager.transact(function(){l(t.lastX+1,t.lastY+1)}),o.addVisual())}}]}),o.addMenuItem("tableprops",{text:"Table properties",context:"table",onPostRender:d,onclick:C.tableProps}),o.addMenuItem("deletetable",{text:"Delete table",context:"table",onPostRender:d,cmd:"mceTableDelete"}),o.addMenuItem("cell",{separator:"before",text:"Cell",context:"table",menu:[{text:"Cell properties",onclick:a("mceTableCellProps"),onPostRender:f},{text:"Merge cells",onclick:a("mceTableMergeCells"),onPostRender:f},{text:"Split cell",onclick:a("mceTableSplitCells"),onPostRender:f}]}),o.addMenuItem("row",{text:"Row",context:"table",menu:[{text:"Insert row before",onclick:a("mceTableInsertRowBefore"),onPostRender:f},{text:"Insert row after",onclick:a("mceTableInsertRowAfter"),onPostRender:f},{text:"Delete row",onclick:a("mceTableDeleteRow"),onPostRender:f},{text:"Row properties",onclick:a("mceTableRowProps"),onPostRender:f},{text:"-"},{text:"Cut row",onclick:a("mceTableCutRow"),onPostRender:f},{text:"Copy row",onclick:a("mceTableCopyRow"),onPostRender:f},{text:"Paste row before",onclick:a("mceTablePasteRowBefore"),onPostRender:f},{text:"Paste row after",onclick:a("mceTablePasteRowAfter"),onPostRender:f}]}),o.addMenuItem("column",{text:"Column",context:"table",menu:[{text:"Insert column before",onclick:a("mceTableInsertColBefore"),onPostRender:f},{text:"Insert column after",onclick:a("mceTableInsertColAfter"),onPostRender:f},{text:"Delete column",onclick:a("mceTableDeleteCol"),onPostRender:f}]});var w=[];u("inserttable tableprops deletetable | cell row column".split(" "),function(e){"|"==e?w.push({text:"-"}):w.push(o.menuItems[e])}),o.addButton("table",{type:"menubutton",title:"Table",menu:w}),s.isIE||o.on("click",function(e){e=e.target,"TABLE"===e.nodeName&&(o.selection.select(e),o.nodeChanged())}),x.quirks=new t(o),o.on("Init",function(){x.cellSelection=new n(o),x.resizeBars=b}),o.on("PreInit",function(){o.serializer.addAttributeFilter("data-mce-cell-padding,data-mce-border,data-mce-border-color",function(e,t){for(var n=e.length;n--;)e[n].attr(t,null)})}),u({mceTableSplitCells:function(e){e.split()},mceTableMergeCells:function(e){var t;t=o.dom.getParent(o.selection.getStart(),"th,td"),o.dom.select("td.mce-item-selected,th.mce-item-selected").length?e.merge():C.merge(e,t)},mceTableInsertRowBefore:function(e){e.insertRow(!0)},mceTableInsertRowAfter:function(e){e.insertRow()},mceTableInsertColBefore:function(e){e.insertCol(!0)},mceTableInsertColAfter:function(e){e.insertCol()},mceTableDeleteCol:function(e){e.deleteCols()},mceTableDeleteRow:function(e){e.deleteRows()},mceTableCutRow:function(e){y=e.cutRows()},mceTableCopyRow:function(e){y=e.copyRows()},mceTablePasteRowBefore:function(e){e.pasteRows(y,!0)},mceTablePasteRowAfter:function(e){e.pasteRows(y)},mceTableDelete:function(e){b&&b.clearBars(),e.deleteTable()}},function(t,n){o.addCommand(n,function(){var n=new e(o);n&&(t(n),o.execCommand("mceRepaint"),x.cellSelection.clear())})}),u({mceInsertTable:C.table,mceTableProps:function(){C.table(!0)},mceTableRowProps:C.row,mceTableCellProps:C.cell},function(e,t){o.addCommand(t,function(t,n){e(n)})}),h(),v(),o.settings.table_tab_navigation!==!1&&o.on("keydown",function(t){var n,r,i;9==t.keyCode&&(n=o.dom.getParent(o.selection.getStart(),"th,td"),n&&(t.preventDefault(),r=new e(o),i=t.shiftKey?-1:1,o.undoManager.transact(function(){!r.moveRelIdx(n,i)&&i>0&&(r.insertRow(),r.refresh(),r.moveRelIdx(n,i))})))}),x.insertTable=l}var u=o.each;l.add("table",c)})}(this); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/template/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/template/plugin.min.js new file mode 100644 index 0000000..53cc04c --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/template/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("template",function(e){function t(t){return function(){var n=e.settings.templates;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function n(t){function n(t){function n(t){if(-1==t.indexOf("")){var n="";tinymce.each(e.contentCSS,function(t){n+=''}),t=""+n+""+t+""}t=o(t,"template_preview_replace_values");var i=r.find("iframe")[0].getEl().contentWindow.document;i.open(),i.write(t),i.close()}var a=t.control.value();a.url?tinymce.util.XHR.send({url:a.url,success:function(e){i=e,n(i)}}):(i=a.content,n(i)),r.find("#description")[0].text(t.control.value().description)}var r,i,s=[];if(!t||0===t.length){var l=e.translate("No templates defined.");return void e.notificationManager.open({text:l,type:"info"})}tinymce.each(t,function(e){s.push({selected:!s.length,text:e.title,value:{url:e.url,content:e.content,description:e.description}})}),r=e.windowManager.open({title:"Insert template",layout:"flex",direction:"column",align:"stretch",padding:15,spacing:10,items:[{type:"form",flex:0,padding:0,items:[{type:"container",label:"Templates",items:{type:"listbox",label:"Templates",name:"template",values:s,onselect:n}}]},{type:"label",name:"description",label:"Description",text:"\xa0"},{type:"iframe",flex:1,border:1}],onsubmit:function(){a(!1,i)},width:e.getParam("template_popup_width",600),height:e.getParam("template_popup_height",500)}),r.find("listbox")[0].fire("select")}function r(t,n){function r(e,t){if(e=""+e,e.length0&&(l=u.create("div",null),l.appendChild(c[0].cloneNode(!0))),s(u.select("*",l),function(t){a(t,e.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))&&(t.innerHTML=r(e.getParam("template_cdate_format",e.getLang("template.cdate_format")))),a(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=r(e.getParam("template_mdate_format",e.getLang("template.mdate_format")))),a(t,e.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))&&(t.innerHTML=d)}),i(l),e.execCommand("mceInsertContent",!1,l.innerHTML),e.addVisual()}var s=tinymce.each;e.addCommand("mceInsertTemplate",a),e.addButton("template",{title:"Insert template",onclick:t(n)}),e.addMenuItem("template",{text:"Insert template",onclick:t(n),context:"insert"}),e.on("PreProcess",function(t){var n=e.dom;s(n.select("div",t.node),function(t){n.hasClass(t,"mceTmpl")&&(s(n.select("*",t),function(t){n.hasClass(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=r(e.getParam("template_mdate_format",e.getLang("template.mdate_format"))))}),i(t))})})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textcolor/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textcolor/plugin.min.js new file mode 100644 index 0000000..c762f75 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textcolor/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("textcolor",function(e){function t(t){var n;return e.dom.getParents(e.selection.getStart(),function(e){var r;(r=e.style["forecolor"==t?"color":"background-color"])&&(n=r)}),n}function n(){var t,n,r=[];for(n=e.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Red violet","FFFFFF","White","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum"],t=0;t
'+(n?"×":"")+"
"}var r,i,o,a,s,u,d,f=this,p=f._id,m=0;for(r=n(),r.push({text:tinymce.translate("No color"),color:"transparent"}),o='',a=r.length-1,u=0;c>u;u++){for(o+="",s=0;l>s;s++)d=u*l+s,d>a?o+="":(i=r[d],o+=t(i.color,i.text));o+=""}if(e.settings.color_picker_callback){for(o+='",o+="",s=0;l>s;s++)o+=t("","Custom color");o+=""}return o+="
"}function i(t,n){e.undoManager.transact(function(){e.focus(),e.formatter.apply(t,{value:n}),e.nodeChanged()})}function o(t){e.undoManager.transact(function(){e.focus(),e.formatter.remove(t,{value:null},null,!0),e.nodeChanged()})}function a(n){function r(e){u.hidePanel(),u.color(e),i(u.settings.format,e)}function a(){u.hidePanel(),u.resetColor(),o(u.settings.format)}function s(e,t){e.style.background=t,e.setAttribute("data-mce-color",t)}var c,u=this.parent();tinymce.DOM.getParent(n.target,".mce-custom-color-btn")&&(u.hidePanel(),e.settings.color_picker_callback.call(e,function(e){var t,n,i,o=u.panel.getEl().getElementsByTagName("table")[0];for(t=tinymce.map(o.rows[o.rows.length-1].childNodes,function(e){return e.firstChild}),i=0;ii;i++)s(t[i],t[i+1].getAttribute("data-mce-color"));s(n,e),r(e)},t(u.settings.format))),c=n.target.getAttribute("data-mce-color"),c?(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),n.target.setAttribute("aria-selected",!0),this.lastId=n.target.id,"transparent"==c?a():r(c)):null!==c&&u.hidePanel()}function s(){var e=this;e._color?i(e.settings.format,e._color):o(e.settings.format)}var l,c;c=e.settings.textcolor_rows||5,l=e.settings.textcolor_cols||8,e.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",format:"forecolor",panel:{role:"application",ariaRemember:!0,html:r,onclick:a},onclick:s}),e.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",format:"hilitecolor",panel:{role:"application",ariaRemember:!0,html:r,onclick:a},onclick:s})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textpattern/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textpattern/plugin.min.js new file mode 100644 index 0000000..5f2f45c --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/textpattern/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("textpattern",function(e){function t(){return c&&(l.sort(function(e,t){return e.start.length>t.start.length?-1:e.start.length'+e+"
"}function o(){var e,t="";for(e in p)t+=e;return new RegExp("["+t+"]","g")}function a(){var e,t="";for(e in p)t&&(t+=","),t+="span.mce-"+p[e];return t}var s,l,c,u,d,f,p,m,h=e.getBody(),g=e.selection;if(p={"\xa0":"nbsp","\xad":"shy"},r=!r,i.state=r,e.fire("VisualChars",{state:r}),m=o(),t&&(f=g.getBookmark()),r)for(l=[],tinymce.walk(h,function(e){3==e.nodeType&&e.nodeValue&&m.test(e.nodeValue)&&l.push(e)},"childNodes"),c=0;c=0;c--)e.dom.remove(l[c],1);g.moveToBookmark(f)}function n(){var t=this;e.on("VisualChars",function(e){t.active(e.state)})}var r,i=this;e.addCommand("mceVisualChars",t),e.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:n}),e.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:n,selectable:!0,context:"view",prependToContext:!0}),e.on("beforegetcontent",function(e){r&&"raw"!=e.format&&!e.draft&&(r=!0,t(!1))})}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/wordcount/plugin.min.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/wordcount/plugin.min.js new file mode 100644 index 0000000..d31b926 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/wordcount/plugin.min.js @@ -0,0 +1 @@ +tinymce.PluginManager.add("wordcount",function(e){function t(){e.theme.panel.find("#wordcount").text(["Words: {0}",i.getCount()])}var n,r,i=this;n=e.getParam("wordcount_countregex",/[\w\u2019\x27\-\u00C0-\u1FFF]+/g),r=e.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),e.on("init",function(){var n=e.theme.panel&&e.theme.panel.find("#statusbar")[0];n&&tinymce.util.Delay.setEditorTimeout(e,function(){n.insert({type:"label",name:"wordcount",text:["Words: {0}",i.getCount()],classes:"wordcount",disabled:e.settings.readonly},0),e.on("setcontent beforeaddundo",t),e.on("keyup",function(e){32==e.keyCode&&t()})},0)}),i.getCount=function(){var t=e.getContent({format:"raw"}),i=0;if(t){t=t.replace(/\.\.\./g," "),t=t.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," "),t=t.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i,"$1$3").replace(/&.+?;/g," "),t=t.replace(r,"");var o=t.match(n);o&&(i=o.length)}return i}}); \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/README.md b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/README.md new file mode 100644 index 0000000..951fbce --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/README.md @@ -0,0 +1,78 @@ +Plugin youtube for TinyMCE 4 +====================== + +Insert YouTube video W3C valid with optionnals (HD, similar vidéos) + + +Authors +------- + + * Gerits Aurelien (Author-Developer) contact[at]aurelien-gerits[point]be + +Official link in french : + +###Screenshot + +![tinyMCE plugin YouTube](http://blog.aurelien-gerits.be/wp-content/uploads/2013/09/youtube-tinymce-2.0.png "tinyMCE plugin YouTube") + +###Installation + * Download the dist/youtube.zip archive + * Unzip archive in tinyMCE plugin directory (tiny_mce/plugins/) + +###Configuration + ```html + +``` + +###Languages + * English + * French + * Russian + * Spanish + * German + * Italian + * Brazilian + * Hungarian + * Polish + + You can send me translations in other languages + +### Old Version + +[Plugin YouTube for tinyMCE 3](http://magix-cjquery.com/post/2012/05/11/plugin-youtube-v1.4-pour-tinyMCE) + +
+This file is part of tinyMCE.
+YouTube for tinyMCE
+Copyright (C) 2011 - 2013  Gerits Aurelien aurelien[at]magix-dev[dot]be - contact[at]aurelien-gerits[dot]be
+
+Redistributions of files must retain the above copyright notice.
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see .
+
+####DISCLAIMER
+
+Do not edit or add to this file if you wish to upgrade jimagine to newer
+versions in the future. If you wish to customize jimagine for your
+needs please refer to magix-dev.be for more information.
+
diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/css/styles.css b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/css/styles.css new file mode 100644 index 0000000..fa6367a --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/css/styles.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.0 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}h1{margin:.67em 0}b,strong{font-weight:700}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}button,input,select,textarea{margin:0}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;box-sizing:border-box}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:focus,a:hover{color:#2a6496;text-decoration:underline}a:focus{outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.1px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:400;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}.h1 small,h1 small{font-size:24px}.h2 small,h2 small{font-size:18px}.h3 small,.h4 small,h3 small,h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dd,dt{line-height:1.428571429}dt{font-weight:700}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:after,.dl-horizontal dd:before{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}blockquote:after,blockquote:before,q:after,q:before{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:after,.container:before{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:after,.row:before{display:table;content:" "}.row:after{clear:both}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-10,.col-md-11,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table tbody>tr>td,.table tbody>tr>th,.table tfoot>tr>td,.table tfoot>tr>th,.table thead>tr>td,.table thead>tr>th{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child td,.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child td,.table thead:first-child tr:first-child th{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed tbody>tr>td,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>td,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{display:table-column;float:none}table td[class*=col-],table th[class*=col-]{display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6;border-color:#c9e2b3}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc;border-color:#e6c1c7}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>thead>tr:last-child>th{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}input[type=file]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.checkbox,.radio{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.checkbox label,.radio label{display:inline;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{float:left;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline[disabled],.checkbox[disabled],.radio-inline[disabled],.radio[disabled],fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .control-label,.has-warning .help-block{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .control-label,.has-error .help-block{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .control-label,.has-success .help-block{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .checkbox,.form-inline .radio{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{float:none;margin-left:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:after,.form-horizontal .form-group:before{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff}.btn-default.active,.btn-default:active,.btn-default:focus,.btn-default:hover,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default.active,.btn-default:active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca}.btn-primary.active,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary.active,.btn-primary:active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e}.btn-warning.active,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f}.btn-danger.active,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success.active,.btn-success:active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de}.btn-info.active,.btn-info:active,.btn-info:focus,.btn-info:hover,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info.active,.btn-info:active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:400;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#fff;text-decoration:none}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#999}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-danger .caret,.btn-info .caret,.btn-primary .caret,.btn-success .caret,.btn-warning .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-danger .caret,.dropup .btn-info .caret,.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group-vertical>.btn:focus,.btn-group>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:after,.btn-toolbar:before{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle=buttons]>.btn>input[type=checkbox],[data-toggle=buttons]>.btn>input[type=radio]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:active,.input-group-btn>.btn:hover{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:after,.nav:before{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-right:0;border-bottom:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:after,.tabbable:before{display:table;content:" "}.tabbable:after{clear:both}.pill-content>.pill-pane,.tab-content>.tab-pane{display:none}.pill-content>.active,.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:after,.navbar:before{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:after,.navbar-header:before{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse:after,.navbar-collapse:before{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:focus .caret,.navbar-default .navbar-nav>.dropdown>a:hover .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:focus .caret,.navbar-default .navbar-nav>.open>a:hover .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{background-color:#eee}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:after,.pager:before{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:focus,.label[href]:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:focus,.label-default[href]:hover{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}.nav-pills>.active>a>.badge,a.list-group-item.active>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:focus,a.thumbnail:hover{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,.15)),color-stop(0.75,rgba(255,255,255,.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15)25%,transparent 25%,transparent 50%,rgba(255,255,255,.15)50%,rgba(255,255,255,.15)75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px}.panel-body{padding:15px}.panel-body:after,.panel-body:before{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal-open .navbar-fixed-bottom,.modal-open .navbar-fixed-top,body.modal-open{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:after,.modal-footer:before{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5)0),color-stop(rgba(0,0,0,.0001)100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,.5)0,rgba(0,0,0,.0001)100%);background-image:linear-gradient(to right,rgba(0,0,0,.5)0,rgba(0,0,0,.0001)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001)0),color-stop(rgba(0,0,0,.5)100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,.0001)0,rgba(0,0,0,.5)100%);background-image:linear-gradient(to right,rgba(0,0,0,.0001)0,rgba(0,0,0,.5)100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:after,.clearfix:before{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-lg,.visible-md,.visible-sm,.visible-xs,td.visible-lg,td.visible-md,td.visible-sm,td.visible-xs,th.visible-lg,th.visible-md,th.visible-sm,th.visible-xs,tr.visible-lg,tr.visible-md,tr.visible-sm,tr.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}td.visible-xs.visible-sm,th.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}td.visible-xs.visible-md,th.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}td.visible-xs.visible-lg,th.visible-xs.visible-lg{display:table-cell!important}}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}td.visible-sm.visible-xs,th.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}td.visible-sm.visible-md,th.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}td.visible-sm.visible-lg,th.visible-sm.visible-lg{display:table-cell!important}}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}td.visible-md.visible-xs,th.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}td.visible-md.visible-sm,th.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}td.visible-md.visible-lg,th.visible-md.visible-lg{display:table-cell!important}}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}td.visible-lg.visible-xs,th.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}td.visible-lg.visible-sm,th.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}td.visible-lg.visible-md,th.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}td.hidden-xs,th.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,td.hidden-xs,th.hidden-xs,tr.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,td.hidden-xs.hidden-md,th.hidden-xs.hidden-md,tr.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}td.hidden-sm,th.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,td.hidden-sm,th.hidden-sm,tr.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,td.hidden-sm.hidden-md,th.hidden-sm.hidden-md,tr.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}td.hidden-md,th.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,td.hidden-md.hidden-xs,th.hidden-md.hidden-xs,tr.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,td.hidden-md.hidden-sm,th.hidden-md.hidden-sm,tr.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,td.hidden-md,th.hidden-md,tr.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,td.hidden-md.hidden-lg,th.hidden-md.hidden-lg,tr.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}td.hidden-lg,th.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,td.hidden-lg.hidden-md,th.hidden-lg.hidden-md,tr.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,td.hidden-lg,th.hidden-lg,tr.hidden-lg{display:none!important}}.visible-print,td.visible-print,th.visible-print,tr.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}.hidden-print,td.hidden-print,th.hidden-print,tr.hidden-print{display:none!important}}.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,0,#e6e6e6,100%);background-image:-moz-linear-gradient(top,#fff 0,#e6e6e6 100%);background-image:linear-gradient(to bottom,#fff 0,#e6e6e6 100%);background-repeat:repeat-x;border-color:#e0e0e0;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0)}.btn-default.active,.btn-default:active{background-color:#e6e6e6;border-color:#e0e0e0}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;border-color:#2d6ca2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.btn-primary.active,.btn-primary:active{background-color:#3071a9;border-color:#2d6ca2}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;border-color:#419641;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.btn-success.active,.btn-success:active{background-color:#449d44;border-color:#419641}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;border-color:#eb9316;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.btn-warning.active,.btn-warning:active{background-color:#ec971f;border-color:#eb9316}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;border-color:#c12e2a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.btn-danger.active,.btn-danger:active{background-color:#c9302c;border-color:#c12e2a}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;border-color:#2aabd2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.btn-info.active,.btn-info:active{background-color:#31b0d5;border-color:#2aabd2}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover,.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.navbar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff,0,#f8f8f8,100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar .navbar-nav>.active>a{background-color:#f8f8f8}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c,0,#222,100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0)}.navbar-inverse .navbar-nav>.active>a{background-color:#222}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8,0,#c8e5bc,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7,0,#b9def0,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3,0,#f8efc0,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede,0,#e7c3c3,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb,0,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca,0,#3278b3,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5,0,#e8e8e8,100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8,0,#d0e9c6,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7,0,#c4e3f3,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3,0,#faf2cc,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede,0,#ebcccc,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8,0,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}body{padding:10px}a:active,a:focus{outline:0}a img{border:none}#preview{background-image:url(../img/Google-YouTube-128.png);background-repeat:no-repeat;background-position:center center;height:325px;width:430px}#insert-btn{margin-left:5px}.alert{margin-bottom:5px;padding:5px}.form-group{margin-bottom:0}.alert-info{font-size:12px} \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/Google-YouTube-128.png b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/Google-YouTube-128.png new file mode 100644 index 0000000000000000000000000000000000000000..ef60bd04b08c8a4e8c262b9df0e87661d32dc8e1 GIT binary patch literal 11800 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 GH#s%4|H~Bs literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/youtube.gif b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/img/youtube.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d673d1d6781d47552da8ced38acb3f844c88e88 GIT binary patch literal 212 zcmZ?wbhEHb6k!ly*v!fB9|+Ez`9E{!|FpFK#>W2{7|xtIV{B~9zyOj0l4wBjCkrD3 z11EzHNE~Da152a9Nzc`LZ!k6d`1in#kxfa#O``8Wqs-gWQ{}C<8{g`@-2P}+@Y?M^ zcP6ZpJ+LgRkEMkv(My(tiSgj3aE_cstPUkw5;>}mK9o3|a9h|?tfb2pvo$iOLPRv3 uH8s4ds3bQmHG(;(r8c)LE|r0?+BPR7G%zPkC$($d{HP+y#Y-dv8LR;@J4?a< literal 0 HcmV?d00001 diff --git a/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/js/main.js b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/js/main.js new file mode 100644 index 0000000..3f55be0 --- /dev/null +++ b/domokits/local/modules/Tinymce/Resources/js/tinymce/plugins/youtube/js/main.js @@ -0,0 +1,807 @@ +/*! + * bootstrap.js v3.0.0 by @fat and @mdo + * Copyright 2013 Twitter Inc. + * http://www.apache.org/licenses/LICENSE-2.0 + */ +if (!jQuery)throw new Error("Bootstrap requires jQuery"); ++function(t) { + "use strict"; + function e() { + var t = document.createElement("bootstrap"), e = {WebkitTransition: "webkitTransitionEnd", MozTransition: "transitionend", OTransition: "oTransitionEnd otransitionend", transition: "transitionend"}; + for (var i in e)if (void 0 !== t.style[i])return{end: e[i]} + } + + t.fn.emulateTransitionEnd = function(e) { + var i = !1, n = this; + t(this).one(t.support.transition.end, function() { + i = !0 + }); + var o = function() { + i || t(n).trigger(t.support.transition.end) + }; + return setTimeout(o, e), this + }, t(function() { + t.support.transition = e() + }) +}(window.jQuery), +function(t) { + "use strict"; + var e = '[data-dismiss="alert"]', i = function(i) { + t(i).on("click", e, this.close) + }; + i.prototype.close = function(e) { + function i() { + s.trigger("closed.bs.alert").remove() + } + + var n = t(this), o = n.attr("data-target"); + o || (o = n.attr("href"), o = o && o.replace(/.*(?=#[^\s]*$)/, "")); + var s = t(o); + e && e.preventDefault(), s.length || (s = n.hasClass("alert") ? n : n.parent()), s.trigger(e = t.Event("close.bs.alert")), e.isDefaultPrevented() || (s.removeClass("in"), t.support.transition && s.hasClass("fade") ? s.one(t.support.transition.end, i).emulateTransitionEnd(150) : i()) + }; + var n = t.fn.alert; + t.fn.alert = function(e) { + return this.each(function() { + var n = t(this), o = n.data("bs.alert"); + o || n.data("bs.alert", o = new i(this)), "string" == typeof e && o[e].call(n) + }) + }, t.fn.alert.Constructor = i, t.fn.alert.noConflict = function() { + return t.fn.alert = n, this + }, t(document).on("click.bs.alert.data-api", e, i.prototype.close) +}(window.jQuery), +function(t) { + "use strict"; + var e = function(i, n) { + this.$element = t(i), this.options = t.extend({}, e.DEFAULTS, n) + }; + e.DEFAULTS = {loadingText: "loading..."}, e.prototype.setState = function(t) { + var e = "disabled", i = this.$element, n = i.is("input") ? "val" : "html", o = i.data(); + t += "Text", o.resetText || i.data("resetText", i[n]()), i[n](o[t] || this.options[t]), setTimeout(function() { + "loadingText" == t ? i.addClass(e).attr(e, e) : i.removeClass(e).removeAttr(e) + }, 0) + }, e.prototype.toggle = function() { + var t = this.$element.closest('[data-toggle="buttons"]'); + if (t.length) { + var e = this.$element.find("input").prop("checked", !this.$element.hasClass("active")).trigger("change"); + "radio" === e.prop("type") && t.find(".active").removeClass("active") + } + this.$element.toggleClass("active") + }; + var i = t.fn.button; + t.fn.button = function(i) { + return this.each(function() { + var n = t(this), o = n.data("bs.button"), s = "object" == typeof i && i; + o || n.data("bs.button", o = new e(this, s)), "toggle" == i ? o.toggle() : i && o.setState(i) + }) + }, t.fn.button.Constructor = e, t.fn.button.noConflict = function() { + return t.fn.button = i, this + }, t(document).on("click.bs.button.data-api", "[data-toggle^=button]", function(e) { + var i = t(e.target); + i.hasClass("btn") || (i = i.closest(".btn")), i.button("toggle"), e.preventDefault() + }) +}(window.jQuery), +function(t) { + "use strict"; + var e = function(e, i) { + this.$element = t(e), this.$indicators = this.$element.find(".carousel-indicators"), this.options = i, this.paused = this.sliding = this.interval = this.$active = this.$items = null, "hover" == this.options.pause && this.$element.on("mouseenter", t.proxy(this.pause, this)).on("mouseleave", t.proxy(this.cycle, this)) + }; + e.DEFAULTS = {interval: 5e3, pause: "hover", wrap: !0}, e.prototype.cycle = function(e) { + return e || (this.paused = !1), this.interval && clearInterval(this.interval), this.options.interval && !this.paused && (this.interval = setInterval(t.proxy(this.next, this), this.options.interval)), this + }, e.prototype.getActiveIndex = function() { + return this.$active = this.$element.find(".item.active"), this.$items = this.$active.parent().children(), this.$items.index(this.$active) + }, e.prototype.to = function(e) { + var i = this, n = this.getActiveIndex(); + return e > this.$items.length - 1 || 0 > e ? void 0 : this.sliding ? this.$element.one("slid", function() { + i.to(e) + }) : n == e ? this.pause().cycle() : this.slide(e > n ? "next" : "prev", t(this.$items[e])) + }, e.prototype.pause = function(e) { + return e || (this.paused = !0), this.$element.find(".next, .prev").length && t.support.transition.end && (this.$element.trigger(t.support.transition.end), this.cycle(!0)), this.interval = clearInterval(this.interval), this + }, e.prototype.next = function() { + return this.sliding ? void 0 : this.slide("next") + }, e.prototype.prev = function() { + return this.sliding ? void 0 : this.slide("prev") + }, e.prototype.slide = function(e, i) { + var n = this.$element.find(".item.active"), o = i || n[e](), s = this.interval, a = "next" == e ? "left" : "right", r = "next" == e ? "first" : "last", l = this; + if (!o.length) { + if (!this.options.wrap)return; + o = this.$element.find(".item")[r]() + } + this.sliding = !0, s && this.pause(); + var h = t.Event("slide.bs.carousel", {relatedTarget: o[0], direction: a}); + if (!o.hasClass("active")) { + if (this.$indicators.length && (this.$indicators.find(".active").removeClass("active"), this.$element.one("slid", function() { + var e = t(l.$indicators.children()[l.getActiveIndex()]); + e && e.addClass("active") + })), t.support.transition && this.$element.hasClass("slide")) { + if (this.$element.trigger(h), h.isDefaultPrevented())return; + o.addClass(e), o[0].offsetWidth, n.addClass(a), o.addClass(a), n.one(t.support.transition.end,function() { + o.removeClass([e, a].join(" ")).addClass("active"), n.removeClass(["active", a].join(" ")), l.sliding = !1, setTimeout(function() { + l.$element.trigger("slid") + }, 0) + }).emulateTransitionEnd(600) + } else { + if (this.$element.trigger(h), h.isDefaultPrevented())return; + n.removeClass("active"), o.addClass("active"), this.sliding = !1, this.$element.trigger("slid") + } + return s && this.cycle(), this + } + }; + var i = t.fn.carousel; + t.fn.carousel = function(i) { + return this.each(function() { + var n = t(this), o = n.data("bs.carousel"), s = t.extend({}, e.DEFAULTS, n.data(), "object" == typeof i && i), a = "string" == typeof i ? i : s.slide; + o || n.data("bs.carousel", o = new e(this, s)), "number" == typeof i ? o.to(i) : a ? o[a]() : s.interval && o.pause().cycle() + }) + }, t.fn.carousel.Constructor = e, t.fn.carousel.noConflict = function() { + return t.fn.carousel = i, this + }, t(document).on("click.bs.carousel.data-api", "[data-slide], [data-slide-to]", function(e) { + var i, n = t(this), o = t(n.attr("data-target") || (i = n.attr("href")) && i.replace(/.*(?=#[^\s]+$)/, "")), s = t.extend({}, o.data(), n.data()), a = n.attr("data-slide-to"); + a && (s.interval = !1), o.carousel(s), (a = n.attr("data-slide-to")) && o.data("bs.carousel").to(a), e.preventDefault() + }), t(window).on("load", function() { + t('[data-ride="carousel"]').each(function() { + var e = t(this); + e.carousel(e.data()) + }) + }) +}(window.jQuery), +function(t) { + "use strict"; + var e = function(i, n) { + this.$element = t(i), this.options = t.extend({}, e.DEFAULTS, n), this.transitioning = null, this.options.parent && (this.$parent = t(this.options.parent)), this.options.toggle && this.toggle() + }; + e.DEFAULTS = {toggle: !0}, e.prototype.dimension = function() { + var t = this.$element.hasClass("width"); + return t ? "width" : "height" + }, e.prototype.show = function() { + if (!this.transitioning && !this.$element.hasClass("in")) { + var e = t.Event("show.bs.collapse"); + if (this.$element.trigger(e), !e.isDefaultPrevented()) { + var i = this.$parent && this.$parent.find("> .panel > .in"); + if (i && i.length) { + var n = i.data("bs.collapse"); + if (n && n.transitioning)return; + i.collapse("hide"), n || i.data("bs.collapse", null) + } + var o = this.dimension(); + this.$element.removeClass("collapse").addClass("collapsing")[o](0), this.transitioning = 1; + var s = function() { + this.$element.removeClass("collapsing").addClass("in")[o]("auto"), this.transitioning = 0, this.$element.trigger("shown.bs.collapse") + }; + if (!t.support.transition)return s.call(this); + var a = t.camelCase(["scroll", o].join("-")); + this.$element.one(t.support.transition.end, t.proxy(s, this)).emulateTransitionEnd(350)[o](this.$element[0][a]) + } + } + }, e.prototype.hide = function() { + if (!this.transitioning && this.$element.hasClass("in")) { + var e = t.Event("hide.bs.collapse"); + if (this.$element.trigger(e), !e.isDefaultPrevented()) { + var i = this.dimension(); + this.$element[i](this.$element[i]())[0].offsetHeight, this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"), this.transitioning = 1; + var n = function() { + this.transitioning = 0, this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse") + }; + return t.support.transition ? void this.$element[i](0).one(t.support.transition.end, t.proxy(n, this)).emulateTransitionEnd(350) : n.call(this) + } + } + }, e.prototype.toggle = function() { + this[this.$element.hasClass("in") ? "hide" : "show"]() + }; + var i = t.fn.collapse; + t.fn.collapse = function(i) { + return this.each(function() { + var n = t(this), o = n.data("bs.collapse"), s = t.extend({}, e.DEFAULTS, n.data(), "object" == typeof i && i); + o || n.data("bs.collapse", o = new e(this, s)), "string" == typeof i && o[i]() + }) + }, t.fn.collapse.Constructor = e, t.fn.collapse.noConflict = function() { + return t.fn.collapse = i, this + }, t(document).on("click.bs.collapse.data-api", "[data-toggle=collapse]", function(e) { + var i, n = t(this), o = n.attr("data-target") || e.preventDefault() || (i = n.attr("href")) && i.replace(/.*(?=#[^\s]+$)/, ""), s = t(o), a = s.data("bs.collapse"), r = a ? "toggle" : n.data(), l = n.attr("data-parent"), h = l && t(l); + a && a.transitioning || (h && h.find('[data-toggle=collapse][data-parent="' + l + '"]').not(n).addClass("collapsed"), n[s.hasClass("in") ? "addClass" : "removeClass"]("collapsed")), s.collapse(r) + }) +}(window.jQuery), +function(t) { + "use strict"; + function e() { + t(n).remove(), t(o).each(function(e) { + var n = i(t(this)); + n.hasClass("open") && (n.trigger(e = t.Event("hide.bs.dropdown")), e.isDefaultPrevented() || n.removeClass("open").trigger("hidden.bs.dropdown")) + }) + } + + function i(e) { + var i = e.attr("data-target"); + i || (i = e.attr("href"), i = i && /#/.test(i) && i.replace(/.*(?=#[^\s]*$)/, "")); + var n = i && t(i); + return n && n.length ? n : e.parent() + } + + var n = ".dropdown-backdrop", o = "[data-toggle=dropdown]", s = function(e) { + t(e).on("click.bs.dropdown", this.toggle) + }; + s.prototype.toggle = function(n) { + var o = t(this); + if (!o.is(".disabled, :disabled")) { + var s = i(o), a = s.hasClass("open"); + if (e(), !a) { + if ("ontouchstart"in document.documentElement && !s.closest(".navbar-nav").length && t(' + +
+
+
+ {intl l='List of the text area where the wysiwyg editor will be used' d='tinymce.bo.default'} +
+
+

+ {intl l='This is a critical data, to update it you have to inform the ids (#timymce_configuration-id-test_zone for example) or the classes (.wysiwyg for example) , separated with comas, of the text areas you want to have the wysiwyg editor directly in the data base.' d='tinymce.bo.default'} +

+
+ +
+ {render_form_field form=$form field="available_text_areas"} +
+
+
+ +
+
+ {if $form_error} +
{$form_error_message}
+ {/if} + +
+ {render_form_field form=$form field="editor_height"} + + {render_form_field form=$form field="force_pasting_as_text"} + {render_form_field form=$form field="set_images_as_responsive"} + {render_form_field form=$form field="show_menu_bar"} + {render_form_field form=$form field="custom_css"} +
+ +
+ {render_form_field form=$form field="test_zone" extra_class="wysiwyg"} +
+
+
+ + {/form} +
+ + + + \ No newline at end of file diff --git a/domokits/local/modules/Tinymce/templates/backOffice/default/tinymce_init.tpl b/domokits/local/modules/Tinymce/templates/backOffice/default/tinymce_init.tpl new file mode 100644 index 0000000..1b03d0d --- /dev/null +++ b/domokits/local/modules/Tinymce/templates/backOffice/default/tinymce_init.tpl @@ -0,0 +1,123 @@ + + + diff --git a/domokits/local/modules/UrlSanitizer/.github/workflows/release.yml b/domokits/local/modules/UrlSanitizer/.github/workflows/release.yml new file mode 100644 index 0000000..e880140 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/.github/workflows/release.yml @@ -0,0 +1,7 @@ +name: "Auto Release" +on: + push: + branches: [ master, main ] +jobs: + release: + uses: thelia-modules/ReusableWorkflow/.github/workflows/auto_release.yml@main diff --git a/domokits/local/modules/UrlSanitizer/Config/config.xml b/domokits/local/modules/UrlSanitizer/Config/config.xml new file mode 100644 index 0000000..8ac8854 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Config/config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/domokits/local/modules/UrlSanitizer/Config/module.xml b/domokits/local/modules/UrlSanitizer/Config/module.xml new file mode 100644 index 0000000..64d0a58 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Config/module.xml @@ -0,0 +1,22 @@ + + + UrlSanitizer\UrlSanitizer + + Sanitize URLs + + + Nettoie les URLs + + + en_US + fr_FR + + 2.1.1 + classic + 2.5.0 + other + 0 + 0 + diff --git a/domokits/local/modules/UrlSanitizer/Config/routing.xml b/domokits/local/modules/UrlSanitizer/Config/routing.xml new file mode 100644 index 0000000..fc772b7 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Config/routing.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/domokits/local/modules/UrlSanitizer/Config/schema.xml b/domokits/local/modules/UrlSanitizer/Config/schema.xml new file mode 100644 index 0000000..08ba2de --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Config/schema.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/domokits/local/modules/UrlSanitizer/Controller/ConfigurationController.php b/domokits/local/modules/UrlSanitizer/Controller/ConfigurationController.php new file mode 100644 index 0000000..0bdfe53 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Controller/ConfigurationController.php @@ -0,0 +1,59 @@ +checkAuth([AdminResources::MODULE], ["UrlSanitizer"], AccessManager::UPDATE)) { + return $response; + } + + $urlSanitizerService->sanitizeAllExistingUrls(); + + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/UrlSanitizer', [])); + } + + #[Route('/configuration', name: 'configuration', methods: ['POST'])] + public function SaveConfiguration(ParserContext $parserContext): RedirectResponse|Response + { + $form = $this->createForm(ConfigurationForm::getName()); + + try { + $data = $this->validateForm($form)->getData(); + + UrlSanitizer::setConfigValue(UrlSanitizer::REMOVE_HTML_CONFIG_KEY, $data['remove_html']); + + return $this->generateSuccessRedirect($form); + } catch (FormValidationException $e) { + $error_message = $this->createStandardFormValidationErrorMessage($e); + } catch (Exception $e) { + $error_message = $e->getMessage(); + } + + $form->setErrorMessage($error_message); + + $parserContext + ->addForm($form) + ->setGeneralError($error_message); + + return $this->generateErrorRedirect($form); + } +} diff --git a/domokits/local/modules/UrlSanitizer/EventListener/RewriteUrlListener.php b/domokits/local/modules/UrlSanitizer/EventListener/RewriteUrlListener.php new file mode 100644 index 0000000..bd5ece0 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/EventListener/RewriteUrlListener.php @@ -0,0 +1,39 @@ +sanitizerService = $sanitizerService; + } + + public function sanitizeUrl(RewritingUrlEvent $event) + { + /** @var RewritingUrl $rewritingUrl */ + $rewritingUrl = $event->getModel(); + + $sanitizedUrl = $this->sanitizerService->unifyUrl( + $this->sanitizerService->sanitizeUrl($rewritingUrl->getUrl()), + $rewritingUrl + ); + + $rewritingUrl->setUrl($sanitizedUrl); + } + + public static function getSubscribedEvents() + { + return [ + RewritingUrlEvent::PRE_INSERT => ['sanitizeUrl', 64] + ]; + } +} diff --git a/domokits/local/modules/UrlSanitizer/Form/ConfigurationForm.php b/domokits/local/modules/UrlSanitizer/Form/ConfigurationForm.php new file mode 100644 index 0000000..66cec64 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Form/ConfigurationForm.php @@ -0,0 +1,21 @@ +formBuilder + ->add('remove_html', CheckboxType::class, [ + 'required' => false, + 'label' => Translator::getInstance()?->trans('Remove html extension from rewrite url ?', [], UrlSanitizer::DOMAIN_NAME), + 'data' => (bool)UrlSanitizer::getConfigValue(UrlSanitizer::REMOVE_HTML_CONFIG_KEY) + ]); + } +} \ No newline at end of file diff --git a/domokits/local/modules/UrlSanitizer/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/UrlSanitizer/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..a3af34c --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,9 @@ + 'Attention, cette opération est irréversible.', + 'If you want to sanitize the existing rewritten urls in your database, click on the button below.' => 'Pour effectuer cette opération sur les URL déjà existantes dans la base de données, cliquez sur le bouton ci-dessous.', + 'Once this module is activated, every rewritten url saved will be automatically sanitized.' => 'Lorsque ce module est activé, si une URL réécrite est sauvegardée elle sera automatiquement nettoyée.', + 'Sanitize existing URLs' => 'Nettoyer les URLs existantes', + 'This will create a sanitized url and redirect the old url to the new one.' => 'Ceci va créer une nouvelle url nettoyée et rediriger l\'ancienne vers la nouvelle.', +); diff --git a/domokits/local/modules/UrlSanitizer/Readme.md b/domokits/local/modules/UrlSanitizer/Readme.md new file mode 100644 index 0000000..01f4354 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Readme.md @@ -0,0 +1,19 @@ +# UrlSanitizer + +This module allows you to sanitize your urls. + +Only compatible with Thelia >= 2.4.0. + +For Thelia <= 2.4.0 you can install this module https://github.com/thelia-modules/UrlRemoveAccent +but he only replace accent and he override Thelia url sanitize. + +## Installation + +``` +composer require thelia/url-sanitizer-module ~1.0.0 +``` + +## Usage + +- If the module is activated, every rewritten url saved will be automatically sanitized. +- If you want to sanitize the existing urls in your database, go to the module configuration and follow the instructions. diff --git a/domokits/local/modules/UrlSanitizer/Service/UrlSanitizerService.php b/domokits/local/modules/UrlSanitizer/Service/UrlSanitizerService.php new file mode 100644 index 0000000..f935977 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/Service/UrlSanitizerService.php @@ -0,0 +1,223 @@ +filterByRedirected(null, Criteria::ISNULL) + ->find(); + + /** @var RewritingUrl $rewrittenUrl */ + foreach ($allDefaultRewrittenUrl as $rewrittenUrl) { + $baseUrl = $rewrittenUrl->getUrl(); + + $cleanUrl = $this->sanitizeUrl($baseUrl); + + if ("" == $cleanUrl) { + continue; + } + + // If url doesn't change do nothing + if ($baseUrl === $cleanUrl) { + continue; + } + + // If clean url already exist for the same view get it + $cleanRewritingUrl = RewritingUrlQuery::create() + ->filterByView($rewrittenUrl->getView()) + ->filterByViewId($rewrittenUrl->getViewId()) + ->filterByViewLocale($rewrittenUrl->getViewLocale()) + ->filterByUrl($cleanUrl) + ->findOne(); + + // Else create new url sanitized + if (!$cleanRewritingUrl) { + $cleanRewritingUrl = new RewritingUrl(); + + $uniqueUrl = $this->unifyUrl($cleanUrl, $rewrittenUrl); + + $cleanRewritingUrl->setUrl($uniqueUrl) + ->setView($rewrittenUrl->getView()) + ->setViewId($rewrittenUrl->getViewId()) + ->setViewLocale($rewrittenUrl->getViewLocale()) + ->save(); + } + + // Keep "Dirty" redirect before transfer + $oldRedirect = $rewrittenUrl->getRedirected(); + + // Redirect "Dirty" to "Clean" + $rewrittenUrl->setRedirected($cleanRewritingUrl->getId()) + ->save(); + + // Transfer "Dirty" Redirect to "Clean" + $cleanRewritingUrl->setRedirected($oldRedirect) + ->save(); + } + } + + public function sanitizeUrl($url) + { + $url = filter_var( + $this->replaceSpecialCaractere( + $this->replaceSpace( + $this->convertAccents( + $url + ) + ) + ), FILTER_SANITIZE_URL); + + if (UrlSanitizer::getConfigValue(UrlSanitizer::REMOVE_HTML_CONFIG_KEY)) { + $url = $this->removeHtmlExtension($url); + } + + return $url; + } + + public function unifyUrl($cleanedUrl, RewritingUrl $rewritingUrl) + { + $urlExist = RewritingUrlQuery::create() + ->filterByUrl($cleanedUrl) + ->filterById($rewritingUrl->getId(), Criteria::NOT_EQUAL) + ->findOne(); + + if (null === $urlExist) { + return $cleanedUrl; + } + + $urlWithPrefix = $rewritingUrl->getViewId()."-".$cleanedUrl; + + return $this->unifyUrl($urlWithPrefix, $rewritingUrl); + } + + protected function replaceSpace($string, $replacement = '-') + { + return preg_replace("/\s+/", $replacement, $string); + } + + protected function replaceSpecialCaractere($string, $replacement = '') + { + return preg_replace("/^[^a-zA-Z0-9]+/", $replacement, $string); + } + + protected function removeHtmlExtension($string, $replacement = '') + { + return str_replace('.html', $replacement, $string); + } + + protected function convertAccents($string) + { + if (!preg_match('/[\x80-\xff]/', $string)) { + return $string; + } + + $chars = array( + // Decompositions for Latin-1 Supplement + chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', + chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', + chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', + chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', + chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', + chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', + chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', + chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', + chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', + chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', + chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', + chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', + chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', + chr(195).chr(159) => 's', chr(195).chr(160) => 'a', + chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', + chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', + chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', + chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', + chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', + chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', + chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', + chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', + chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', + chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', + chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', + chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', + chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', + chr(195).chr(191) => 'y', + // Decompositions for Latin Extended-A + chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', + chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', + chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', + chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', + chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', + chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', + chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', + chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', + chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', + chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', + chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', + chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', + chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', + chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', + chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', + chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', + chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', + chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', + chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', + chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', + chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', + chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', + chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', + chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', + chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', + chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', + chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', + chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', + chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', + chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', + chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', + chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', + chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', + chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', + chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', + chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', + chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', + chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', + chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', + chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', + chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', + chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', + chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', + chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', + chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', + chr(197).chr(154) => 'S',chr(197).chr(155) => 's', + chr(197).chr(156) => 'S',chr(197).chr(157) => 's', + chr(197).chr(158) => 'S',chr(197).chr(159) => 's', + chr(197).chr(160) => 'S', chr(197).chr(161) => 's', + chr(197).chr(162) => 'T', chr(197).chr(163) => 't', + chr(197).chr(164) => 'T', chr(197).chr(165) => 't', + chr(197).chr(166) => 'T', chr(197).chr(167) => 't', + chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', + chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', + chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', + chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', + chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', + chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', + chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', + chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', + chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', + chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', + chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', + chr(197).chr(190) => 'z', chr(197).chr(191) => 's' + ); + + $string = strtr($string, $chars); + + return $string; + } +} \ No newline at end of file diff --git a/domokits/local/modules/UrlSanitizer/UrlSanitizer.php b/domokits/local/modules/UrlSanitizer/UrlSanitizer.php new file mode 100644 index 0000000..1af5355 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/UrlSanitizer.php @@ -0,0 +1,25 @@ +load(self::getModuleCode().'\\', __DIR__) + ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->autowire(true) + ->autoconfigure(true); + } +} diff --git a/domokits/local/modules/UrlSanitizer/composer.json b/domokits/local/modules/UrlSanitizer/composer.json new file mode 100644 index 0000000..3386286 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/composer.json @@ -0,0 +1,15 @@ +{ + "name": "thelia/url-sanitizer-module", + "description": "Sanitize Urls", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "replace": { + "thelia/url-remove-accent-module":"~1.0.0" + }, + "extra": { + "installer-name": "UrlSanitizer" + } +} diff --git a/domokits/local/modules/UrlSanitizer/templates/backOffice/default/UrlSanitizer/module-configuration.html b/domokits/local/modules/UrlSanitizer/templates/backOffice/default/UrlSanitizer/module-configuration.html new file mode 100644 index 0000000..f584339 --- /dev/null +++ b/domokits/local/modules/UrlSanitizer/templates/backOffice/default/UrlSanitizer/module-configuration.html @@ -0,0 +1,39 @@ +
+
+
+
+ {intl l="Once this module is activated, every rewritten url saved will be automatically sanitized." d="urlsanitizer.bo.default"} +
+ {intl l="If you want to sanitize the existing rewritten urls in your database, click on the button below." d="urlsanitizer.bo.default"} +
+ {intl l="This will create a sanitized url and redirect the old url to the new one." d="urlsanitizer.bo.default"} +
+ {intl l="Be careful ! This cannot be undone." d="urlsanitizer.bo.default"} +
+ {intl l="Sanitize existing URLs" d="urlsanitizer.bo.default"} + +


+ {form name="urlsanitizer_form_configuration_form"} +
+ {form_hidden_fields form=$form} + + {render_form_field field="success_url" value={url path='/admin/module/UrlSanitizer'}} + {render_form_field field="error_url" value={url path='/admin/module/UrlSanitizer'}} + + {if $form_error} +
+
+
{$form_error_message}
+
+
+ {/if} + + {render_form_field field='remove_html'} + +
+ +
+ {/form} +
+
+
diff --git a/domokits/local/modules/VirtualProductControl/Config/config.xml b/domokits/local/modules/VirtualProductControl/Config/config.xml new file mode 100644 index 0000000..689f790 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/Config/config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/domokits/local/modules/VirtualProductControl/Config/module.xml b/domokits/local/modules/VirtualProductControl/Config/module.xml new file mode 100644 index 0000000..d797929 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/Config/module.xml @@ -0,0 +1,20 @@ + + + VirtualProductControl\VirtualProductControl + + Virtual Product Controller + Check if a virtual product delivery module is enabled if at least one product is virtual + + + Contrôle de produit virtuel + Vérifie qu'un module de livraison pour produit virtuel soit activé si des produits virtuels existent + + 2.5.4 + + Manuel Raynaud + manu@raynaud.io + + classic + 2.5.4 + alpha + diff --git a/domokits/local/modules/VirtualProductControl/Hook/VirtualProductHook.php b/domokits/local/modules/VirtualProductControl/Hook/VirtualProductHook.php new file mode 100644 index 0000000..f76f8c8 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/Hook/VirtualProductHook.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductControl\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; +use Thelia\Core\Security\AccessManager; +use Thelia\Core\Security\Resource\AdminResources; +use Thelia\Core\Security\SecurityContext; +use Thelia\Model\ModuleQuery; +use Thelia\Model\ProductQuery; + +/** + * Class VirtualProductHook. + * + * @author Manuel Raynaud + */ +class VirtualProductHook extends BaseHook +{ + /** + * @var SecurityContext + */ + protected $securityContext; + + public function __construct(SecurityContext $securityContext) + { + $this->securityContext = $securityContext; + } + + public function onMainBeforeContent(HookRenderEvent $event): void + { + if ($this->securityContext->isGranted( + ['ADMIN'], + [AdminResources::PRODUCT], + [], + [AccessManager::VIEW] + )) { + $products = ProductQuery::create() + ->filterByVirtual(1) + ->filterByVisible(1) + ->count(); + + if ($products > 0) { + $deliveryModule = ModuleQuery::create()->retrieveVirtualProductDelivery(); + + if (false === $deliveryModule) { + $event->add($this->render('virtual-delivery-warning.html')); + } + } + } + } +} diff --git a/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/de_DE.php b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/de_DE.php new file mode 100644 index 0000000..3b4be4e --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Mindestens ein virtuelles Produkt ist verfügbar, aber kein Liefermodul für virtuellen Produkte ist aktiviert', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/en_US.php b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/en_US.php new file mode 100644 index 0000000..a544616 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'At least one virtual product is online but no virtual product delivery module enabled', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/fr_FR.php b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/fr_FR.php new file mode 100644 index 0000000..50f2511 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Au moins un produit virtuel est en vente mais aucun module de livraison pour produit virtuel n\'est activé', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/it_IT.php b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/it_IT.php new file mode 100644 index 0000000..2f36aa7 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Almeno un prodotto virtuale è online, ma nessun modulo di consegna del prodotto virtuale è abilitato', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/tr_TR.php b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/tr_TR.php new file mode 100644 index 0000000..03149bc --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/backOffice/default/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'En az bir sanal ürün hiç sanal ürün teslim modülü etkin yayında', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/de_DE.php b/domokits/local/modules/VirtualProductControl/I18n/de_DE.php new file mode 100644 index 0000000..3b4be4e --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Mindestens ein virtuelles Produkt ist verfügbar, aber kein Liefermodul für virtuellen Produkte ist aktiviert', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/en_US.php b/domokits/local/modules/VirtualProductControl/I18n/en_US.php new file mode 100644 index 0000000..a544616 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'At least one virtual product is online but no virtual product delivery module enabled', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/fr_FR.php b/domokits/local/modules/VirtualProductControl/I18n/fr_FR.php new file mode 100644 index 0000000..50f2511 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Au moins un produit virtuel est en vente mais aucun module de livraison pour produit virtuel n\'est activé', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/it_IT.php b/domokits/local/modules/VirtualProductControl/I18n/it_IT.php new file mode 100644 index 0000000..2f36aa7 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Almeno un prodotto virtuale è online, ma nessun modulo di consegna del prodotto virtuale è abilitato', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/ru_RU.php b/domokits/local/modules/VirtualProductControl/I18n/ru_RU.php new file mode 100644 index 0000000..744f33e --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'Включен по крайне мере один виртуальный товар, но модуль доставки виртуальных товаров не активирован', +]; diff --git a/domokits/local/modules/VirtualProductControl/I18n/tr_TR.php b/domokits/local/modules/VirtualProductControl/I18n/tr_TR.php new file mode 100644 index 0000000..03149bc --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/I18n/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'warning-message' => 'En az bir sanal ürün hiç sanal ürün teslim modülü etkin yayında', +]; diff --git a/domokits/local/modules/VirtualProductControl/LICENSE.txt b/domokits/local/modules/VirtualProductControl/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/VirtualProductControl/VirtualProductControl.php b/domokits/local/modules/VirtualProductControl/VirtualProductControl.php new file mode 100644 index 0000000..cfe6f56 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/VirtualProductControl.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductControl; + +use Thelia\Module\BaseModule; + +class VirtualProductControl extends BaseModule +{ +} diff --git a/domokits/local/modules/VirtualProductControl/composer.json b/domokits/local/modules/VirtualProductControl/composer.json new file mode 100644 index 0000000..7bf1b28 --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/virtual-product-control-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "VirtualProductControl" + } +} diff --git a/domokits/local/modules/VirtualProductControl/templates/backOffice/default/virtual-delivery-warning.html b/domokits/local/modules/VirtualProductControl/templates/backOffice/default/virtual-delivery-warning.html new file mode 100644 index 0000000..cc5c13a --- /dev/null +++ b/domokits/local/modules/VirtualProductControl/templates/backOffice/default/virtual-delivery-warning.html @@ -0,0 +1,7 @@ +
+
+ +
+
\ No newline at end of file diff --git a/domokits/local/modules/VirtualProductDelivery/Config/config.xml b/domokits/local/modules/VirtualProductDelivery/Config/config.xml new file mode 100644 index 0000000..1b16d36 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/Config/config.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/VirtualProductDelivery/Config/module.xml b/domokits/local/modules/VirtualProductDelivery/Config/module.xml new file mode 100644 index 0000000..c3815f8 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/Config/module.xml @@ -0,0 +1,24 @@ + + + VirtualProductDelivery\VirtualProductDelivery + + Virtual Products Delivery + + + Livraison Produits Virtuels + + + en_US + fr_FR + + 2.5.4 + + Julien Chanséaume + jchanseaume@openstudio.fr + + delivery + 2.5.4 + alpha + diff --git a/domokits/local/modules/VirtualProductDelivery/EventListeners/SendMail.php b/domokits/local/modules/VirtualProductDelivery/EventListeners/SendMail.php new file mode 100755 index 0000000..b105262 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/EventListeners/SendMail.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductDelivery\EventListeners; + +use Propel\Runtime\ActiveQuery\Criteria; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Core\Event\Order\OrderEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Log\Tlog; +use Thelia\Mailer\MailerFactory; +use Thelia\Model\OrderProductQuery; +use VirtualProductDelivery\Events\VirtualProductDeliveryEvents; + +/** + * Class SendMail. + * + * @author Julien Chanséaume + */ +class SendMail implements EventSubscriberInterface +{ + /** @var MailerFactory */ + protected $mailer; + + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + + public function __construct(MailerFactory $mailer, EventDispatcherInterface $eventDispatcher) + { + $this->mailer = $mailer; + $this->eventDispatcher = $eventDispatcher; + } + + public function updateStatus(OrderEvent $event): void + { + $order = $event->getOrder(); + + if ($order->hasVirtualProduct() && $order->isPaid(true)) { + $this->eventDispatcher->dispatch( + $event, + VirtualProductDeliveryEvents::ORDER_VIRTUAL_FILES_AVAILABLE + ); + } + } + + /** + * Send email to notify customer that files for virtual products are available. + * + * @throws \Exception + */ + public function sendEmail(OrderEvent $event): void + { + $order = $event->getOrder(); + + // Be sure that we have a document to download + $virtualProductCount = OrderProductQuery::create() + ->filterByOrderId($order->getId()) + ->filterByVirtual(true) + ->filterByVirtualDocument(null, Criteria::NOT_EQUAL) + ->count(); + + if ($virtualProductCount > 0) { + $customer = $order->getCustomer(); + + $this->mailer->sendEmailToCustomer( + 'mail_virtualproduct', + $customer, + [ + 'customer_id' => $customer->getId(), + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef(), + 'order_date' => $order->getCreatedAt(), + 'update_date' => $order->getUpdatedAt(), + ] + ); + } else { + Tlog::getInstance()->warning( + "Virtual product download message not sent to customer: there's nothing to downnload" + ); + } + } + + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::ORDER_UPDATE_STATUS => ['updateStatus', 128], + VirtualProductDeliveryEvents::ORDER_VIRTUAL_FILES_AVAILABLE => ['sendEmail', 128], + ]; + } +} diff --git a/domokits/local/modules/VirtualProductDelivery/EventListeners/VirtualProductEvents.php b/domokits/local/modules/VirtualProductDelivery/EventListeners/VirtualProductEvents.php new file mode 100644 index 0000000..e2fc3ff --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/EventListeners/VirtualProductEvents.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductDelivery\EventListeners; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; +use Thelia\Core\Event\Product\VirtualProductOrderDownloadResponseEvent; +use Thelia\Core\Event\Product\VirtualProductOrderHandleEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Translation\Translator; +use Thelia\Model\ConfigQuery; +use Thelia\Model\MetaData as MetaDataModel; +use Thelia\Model\MetaDataQuery; +use Thelia\Model\ProductDocumentQuery; +use VirtualProductDelivery\VirtualProductDelivery; + +/** + * Class VirtualProductEvents. + * + * @author Julien Chanséaume + */ +class VirtualProductEvents implements EventSubscriberInterface +{ + public function handleOrder(VirtualProductOrderHandleEvent $event): void + { + $documentId = MetaDataQuery::getVal( + 'virtual', + MetaDataModel::PSE_KEY, + $event->getPseId() + ); + + if (null !== $documentId) { + $productDocument = ProductDocumentQuery::create()->findPk($documentId); + if (null !== $productDocument) { + $event->setPath($productDocument->getFile()); + } + } + } + + public function download(VirtualProductOrderDownloadResponseEvent $event): void + { + $orderProduct = $event->getOrderProduct(); + + if ($orderProduct->getVirtualDocument()) { + $baseSourceFilePath = ConfigQuery::read('documents_library_path'); + if ($baseSourceFilePath === null) { + $baseSourceFilePath = THELIA_LOCAL_DIR.'media'.DS.'documents'; + } else { + $baseSourceFilePath = THELIA_ROOT.$baseSourceFilePath; + } + + // try to get the file + $path = $baseSourceFilePath.DS.'product'.DS.$orderProduct->getVirtualDocument(); + + if (!is_file($path) || !is_readable($path)) { + throw new \ErrorException( + Translator::getInstance()->trans( + 'The file [%file] does not exist', + [ + '%file' => $orderProduct->getId(), + ], + VirtualProductDelivery::MESSAGE_DOMAIN + ) + ); + } + + $response = new BinaryFileResponse($path); + $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT); + $event->setResponse($response); + } + } + + /** + * Returns an array of event names this subscriber wants to listen to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::VIRTUAL_PRODUCT_ORDER_HANDLE => ['handleOrder', 128], + TheliaEvents::VIRTUAL_PRODUCT_ORDER_DOWNLOAD_RESPONSE => ['download', 128], + ]; + } +} diff --git a/domokits/local/modules/VirtualProductDelivery/Events/VirtualProductDeliveryEvents.php b/domokits/local/modules/VirtualProductDelivery/Events/VirtualProductDeliveryEvents.php new file mode 100644 index 0000000..f65603c --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/Events/VirtualProductDeliveryEvents.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductDelivery\Events; + +use Thelia\Core\Event\ActionEvent; + +/** + * Class VirtualProductDeliveryEvents. + * + * @author Julien Chanséaume + */ +class VirtualProductDeliveryEvents extends ActionEvent +{ + public const ORDER_VIRTUAL_FILES_AVAILABLE = 'virtual_product_delivery.virtual_files_available'; +} diff --git a/domokits/local/modules/VirtualProductDelivery/Hook/HookManager.php b/domokits/local/modules/VirtualProductDelivery/Hook/HookManager.php new file mode 100644 index 0000000..359c7fd --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/Hook/HookManager.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductDelivery\Hook; + +use Thelia\Core\Event\Hook\HookRenderEvent; +use Thelia\Core\Hook\BaseHook; + +/** + * Class HookManager. + * + * @author Julien Chanséaume + */ +class HookManager extends BaseHook +{ + public function onAccountOrderAfterProducts(HookRenderEvent $event): void + { + $orderId = $event->getArgument('order'); + + if (null !== $orderId) { + $render = $this->render( + 'account-order-after-products.html', + [ + 'order_id' => $orderId, + ] + ); + $event->add($render); + } + } +} diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/de_DE.php b/domokits/local/modules/VirtualProductDelivery/I18n/de_DE.php new file mode 100644 index 0000000..ce73744 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/de_DE.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Bestellung {$order_ref} validiert. Laden Sie Ihre Dateien herunter.', + 'The file [%file] does not exist' => 'Die Datei [%file] existiert nicht', + 'This module cannot be used on the current cart.' => 'Dieses Modul kann nicht für diesen Warenkorb benutzt werden. ', + 'Virtual product download message' => 'Virtuelles Produkt Herunterladung Nachricht', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/email/default/en_US.php b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/en_US.php new file mode 100644 index 0000000..2e806f9 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/en_US.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Best Regards.' => 'Best Regards.', + 'Feel free to contact us for any further information.' => 'Feel free to contact us for any further information.', + 'Products:' => 'Products:', + 'You have to be logged in to your account to download this files.' => 'You have to be logged in to your account to download this files.', + 'Your order %ref has been validated. You can download your files.' => 'Your order %ref has been validated. You can download your files.', + 'have to be logged in to your account to download this files.' => 'have to be logged in to your account to download this files.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/email/default/fr_FR.php b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/fr_FR.php new file mode 100644 index 0000000..16e3553 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/fr_FR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Best Regards.' => 'Cordialement', + 'Feel free to contact us for any further information.' => 'N\'hésitez pas à nous contacter pour toute information complémentaire.', + 'Products:' => 'Articles à télécharger:', + 'You have to be logged in to your account to download this files.' => 'Vous devez être connecté à votre compte pour pouvoir télécharger le fichier.', + 'Your order %ref has been validated. You can download your files.' => 'Votre commande %ref a été validé. Vous pouvez désormais télécharger vos fichiers.', + 'have to be logged in to your account to download this files.' => 'Vous devez être connecté à votre compte pour pouvoir télécharger les fichiers.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/email/default/it_IT.php b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/it_IT.php new file mode 100644 index 0000000..373c73e --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/it_IT.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Best Regards.' => 'Distinti saluti.', + 'Feel free to contact us for any further information.' => 'Non esitate a contattarci per qualsiasi ulteriore informazione.', + 'Products:' => 'Prodotti:', + 'You have to be logged in to your account to download this files.' => 'Devi essere loggato al tuo account per poter scaricare questi file.', + 'Your order %ref has been validated. You can download your files.' => 'Il vostro ordine %ref è stato convalidato. È possibile scaricare i file.', + 'have to be logged in to your account to download this files.' => 'devi essere loggato al tuo account per poter scaricare questi file.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/email/default/ru_RU.php b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/ru_RU.php new file mode 100644 index 0000000..1c808aa --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/ru_RU.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Best Regards.' => 'С наилучшими пожеланиями.', + 'Feel free to contact us for any further information.' => 'Не стесняйтесь обращаться к нам за любой дополнительной информацией.', + 'Products:' => 'Товары:', + 'You have to be logged in to your account to download this files.' => 'Вы должны войти в ваш аккаунт, чтобы скачать эти файлы', + 'Your order %ref has been validated. You can download your files.' => 'Ваш заказ %ref подтвержден. Можете скачивать ваши файлы.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/email/default/tr_TR.php b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/tr_TR.php new file mode 100644 index 0000000..d010fb6 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/email/default/tr_TR.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Best Regards.' => 'Saygılarımızla,.', + 'Feel free to contact us for any further information.' => 'Daha fazla bilgi için bizimle temas kurmaktan çekinmeyin.', + 'Products:' => 'ürün:', + 'You have to be logged in to your account to download this files.' => 'Bu dosyaları karşıdan yüklemek için hesabınıza oturum açmış olmanız gerekir.', + 'Your order %ref has been validated. You can download your files.' => 'Sipariş %ref doğrulandı. Sen-ebilmek download senin eğe.', + 'have to be logged in to your account to download this files.' => 'Bu dosyaları karşıdan yüklemek için hesabınıza oturum açmış olmanız gerekir.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/en_US.php b/domokits/local/modules/VirtualProductDelivery/I18n/en_US.php new file mode 100755 index 0000000..963fd4b --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/en_US.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Order {$order_ref} validated. Download your files.', + 'The file [%file] does not exist' => 'The file [%file] does not exist', + 'This module cannot be used on the current cart.' => 'This module cannot be used on the current cart.', + 'Virtual product download message' => 'Virtual product download message', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/fr_FR.php b/domokits/local/modules/VirtualProductDelivery/I18n/fr_FR.php new file mode 100755 index 0000000..179b26a --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/fr_FR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Commande {$order_ref} validée. Téléchargez vos fichiers.', + 'The file [%file] does not exist' => 'le fichier [%file] n\'existe pas', + 'This module cannot be used on the current cart.' => 'Ce module ne peut pas être utilisé avec le panier actuel.', + 'Virtual product download message' => 'Message pour le téléchargement des produits virtuels', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/de_DE.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/de_DE.php new file mode 100644 index 0000000..fc50921 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/de_DE.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Lieferadresse', + 'Download' => 'Herunterladen', + 'File' => 'Datei', + 'List of downloadable files' => 'Liste der herunterladbaren Dateien', + 'No delivery address for this delivery method' => 'Keine Lieferadresse für diese Liefermethode', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/en_US.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/en_US.php new file mode 100755 index 0000000..43f5ce2 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/en_US.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Delivery address', + 'Download' => 'Download', + 'File' => 'File', + 'List of downloadable files' => 'List of downloadable files', + 'No delivery address for this delivery method' => 'No delivery address for this delivery method', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/fr_FR.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/fr_FR.php new file mode 100755 index 0000000..3c7de26 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/fr_FR.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Adresse de livraison', + 'Download' => 'Télécharger', + 'File' => 'Fichier', + 'List of downloadable files' => 'Liste des fichiers téléchargeables', + 'No delivery address for this delivery method' => 'L\'adresse de livraison n\'est pas nécessaire pour cette méthode de livraison', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/it_IT.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/it_IT.php new file mode 100644 index 0000000..0fc49b5 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/it_IT.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Indirizzo di consegna', + 'File' => 'File', + 'List of downloadable files' => 'Elenco dei file scaricabili', + 'No delivery address for this delivery method' => 'Nessun indirizzo di consegna per questo metodo di consegna', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/ru_RU.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/ru_RU.php new file mode 100755 index 0000000..7f10712 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/ru_RU.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Адрес доставки', + 'Download' => 'Скачать', + 'File' => 'Файл', + 'List of downloadable files' => 'Список скачиваемых файлов', + 'No delivery address for this delivery method' => 'Нет адреса доставки для этого метода доставки', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/tr_TR.php b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/tr_TR.php new file mode 100644 index 0000000..1a06df9 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/frontOffice/default/tr_TR.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Delivery address' => 'Teslimat adresi', + 'Download' => 'İndir', + 'File' => 'Dosya', + 'List of downloadable files' => 'İndirilebilir dosyalar', + 'No delivery address for this delivery method' => 'Bu teslim yöntemi için hiçbir teslimat adresi', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/it_IT.php b/domokits/local/modules/VirtualProductDelivery/I18n/it_IT.php new file mode 100644 index 0000000..d68e2dc --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/it_IT.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Ordine {$order_ref} convalidato. Scarica i tuoi file.', + 'The file [%file] does not exist' => 'Il file [%file] non esiste', + 'This module cannot be used on the current cart.' => 'Questo modulo non può essere utilizzato sul carrello attuale.', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/de_DE.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/de_DE.php new file mode 100644 index 0000000..8e362d3 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/de_DE.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'Keine Lieferadresse für diese Liefermethode', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/en_US.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/en_US.php new file mode 100644 index 0000000..3256c53 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'No delivery address for this delivery method', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/fr_FR.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/fr_FR.php new file mode 100644 index 0000000..ba2dbaf --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'L\'adresse de livraison n\'est pas nécessaire pour cette méthode de livraison', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/it_IT.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/it_IT.php new file mode 100644 index 0000000..a925248 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/it_IT.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'Nessun indirizzo di consegna per questo metodo di consegna', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/ru_RU.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/ru_RU.php new file mode 100644 index 0000000..dd6c4ea --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/ru_RU.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'Нет адреса доставки для этого метода доставки', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/tr_TR.php b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/tr_TR.php new file mode 100644 index 0000000..6441d14 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/pdf/default/tr_TR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'No delivery address for this delivery method' => 'Bu teslim yöntemi için hiçbir teslimat adresi', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/ru_RU.php b/domokits/local/modules/VirtualProductDelivery/I18n/ru_RU.php new file mode 100755 index 0000000..6a70c30 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/ru_RU.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Заказ {$order_ref} подтвержден. Можете скачивать ваши файлы.', + 'The file [%file] does not exist' => 'Файл [%file] не найден', + 'This module cannot be used on the current cart.' => 'Этот модуль не может быть использован с текущей корзиной', + 'Virtual product download message' => 'Сообщения при скачивании виртуального товара', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/I18n/tr_TR.php b/domokits/local/modules/VirtualProductDelivery/I18n/tr_TR.php new file mode 100644 index 0000000..49e4b18 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/I18n/tr_TR.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'Order {$order_ref} validated. Download your files.' => 'Doğrulanmış {$order_ref} sipariş. Download senin eğe.', + 'The file [%file] does not exist' => '[%file] dosyası yok', + 'This module cannot be used on the current cart.' => 'Bu modül geçerli arabaya kullanılamaz.', + 'Virtual product download message' => 'Sanal ürün indir mesaj', +]; diff --git a/domokits/local/modules/VirtualProductDelivery/LICENSE.txt b/domokits/local/modules/VirtualProductDelivery/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/domokits/local/modules/VirtualProductDelivery/VirtualProductDelivery.php b/domokits/local/modules/VirtualProductDelivery/VirtualProductDelivery.php new file mode 100644 index 0000000..3a7b91c --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/VirtualProductDelivery.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace VirtualProductDelivery; + +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Core\Translation\Translator; +use Thelia\Model\Country; +use Thelia\Model\LangQuery; +use Thelia\Model\Message; +use Thelia\Model\MessageQuery; +use Thelia\Model\State; +use Thelia\Module\AbstractDeliveryModuleWithState; +use Thelia\Module\Exception\DeliveryException; + +class VirtualProductDelivery extends AbstractDeliveryModuleWithState +{ + public const MESSAGE_DOMAIN = 'virtualproductdelivery'; + + /** @var Translator */ + protected $translator; + + /** + * The module is valid if the cart contains only virtual products. + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return bool true if there is only virtual products in cart elsewhere false + */ + public function isValidDelivery(Country $country, State $state = null) + { + return $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->isVirtual(); + } + + public function getPostage(Country $country, State $state = null) + { + if (!$this->isValidDelivery($country, $state)) { + throw new DeliveryException( + $this->trans('This module cannot be used on the current cart.') + ); + } + + return 0.0; + } + + /** + * This module manages virtual product delivery. + * + * @return bool + */ + public function handleVirtualProductDelivery() + { + return true; + } + + public function postActivation(ConnectionInterface $con = null): void + { + // create new message + if (null === MessageQuery::create()->findOneByName('mail_virtualproduct')) { + $message = new Message(); + $message + ->setName('mail_virtualproduct') + ->setHtmlTemplateFileName('virtual-product-download.html') + ->setHtmlLayoutFileName('') + ->setTextTemplateFileName('virtual-product-download.txt') + ->setTextLayoutFileName('') + ->setSecured(0); + + $languages = LangQuery::create()->find(); + + foreach ($languages as $language) { + $locale = $language->getLocale(); + + $message->setLocale($locale); + + $message->setSubject( + $this->trans('Order {$order_ref} validated. Download your files.', [], $locale) + ); + $message->setTitle( + $this->trans('Virtual product download message', [], $locale) + ); + } + + $message->save(); + } + } + + protected function trans($id, $parameters = [], $locale = null) + { + if (null === $this->translator) { + $this->translator = Translator::getInstance(); + } + + return $this->translator->trans($id, $parameters, self::MESSAGE_DOMAIN, $locale); + } +} diff --git a/domokits/local/modules/VirtualProductDelivery/composer.json b/domokits/local/modules/VirtualProductDelivery/composer.json new file mode 100644 index 0000000..77460d8 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/virtual-product-delivery-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "VirtualProductDelivery" + } +} diff --git a/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.html b/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.html new file mode 100644 index 0000000..f7069b3 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.html @@ -0,0 +1,29 @@ +{default_translation_domain domain="virtualproductdelivery.email.default"} +{default_locale locale={$locale}} + +{loop name="order.invoice" type="order" id=$order_id customer="*" limit="1" backend_context="1"} +

+ {intl l="Your order %ref has been validated. You can download your files." ref={$REF}}

+ +

{intl l="Products:"}

+ +
    + {loop type="order_product" name="order-products" order=$ID virtual="1" backend_context="1"} +
  • + {$TITLE} : {url path="/account/download/$ID"} + {ifloop rel="combinations"} +
    + {loop type="order_product_attribute_combination" name="combinations" order_product=$ID} + {$ATTRIBUTE_TITLE} - {$ATTRIBUTE_AVAILABILITY_TITLE} + {/loop} + {/ifloop} +
  • + {/loop} +
+{/loop} + +

{intl l="You have to be logged in to your account to download this files."}

+ +

{intl l="Feel free to contact us for any further information."}

+ +

{intl l="Best Regards."}

\ No newline at end of file diff --git a/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.txt b/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.txt new file mode 100644 index 0000000..9fc5592 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/templates/email/default/virtual-product-download.txt @@ -0,0 +1,26 @@ +{default_translation_domain domain="virtualproductdelivery.email.default"} +{default_locale locale={$locale}} + +{loop name="order.invoice" type="order" id=$order_id customer="*" limit="1" backend_context="1"} + +{intl l="Your order %ref has been validated. You can download your files." ref={$REF}} + +---------------------------------------------------------------------- +{intl l="Products:"} +---------------------------------------------------------------------- +{loop type="order_product" name="order-products" order=$ID virtual="1" backend_context="1"} +{$TITLE} : {url path="/account/download/$ID"} +{ifloop rel="combinations"} +{loop type="order_product_attribute_combination" name="combinations" order_product=$ID} +{$ATTRIBUTE_TITLE} - {$ATTRIBUTE_AVAILABILITY_TITLE} +{/loop} +{/ifloop} +---------------------------------------------------------------------- +{/loop} +{/loop} + +{intl l="You have to be logged in to your account to download this files."} + +{intl l="Feel free to contact us for any further information."} + +{intl l="Best Regards."} \ No newline at end of file diff --git a/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/account-order-after-products.html b/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/account-order-after-products.html new file mode 100644 index 0000000..c4384e7 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/account-order-after-products.html @@ -0,0 +1,24 @@ +{loop type="order" name="virtual.order" id="$order_id" limit="1"} +{if $STATUS >=2 && $VIRTUAL} + + + + + + + + + {loop name="virtual.order.products" type="order_product" virtual="1" order={$ID}} + + + + + {/loop} + +
{intl l="File" d='virtualproductdelivery.fo.default'}{intl l="Download" d='virtualproductdelivery.fo.default'}
{$TITLE} + + {intl l="Download" d='virtualproductdelivery.fo.default'} + +
+{/if} +{/loop} diff --git a/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/delivery-address.html b/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/delivery-address.html new file mode 100644 index 0000000..ceb1e75 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/templates/frontOffice/default/delivery-address.html @@ -0,0 +1,6 @@ +
+
{intl l="Delivery address" d="virtualproductdelivery.fo.default"}
+
+ {intl l="No delivery address for this delivery method" d="virtualproductdelivery.fo.default"} +
+
\ No newline at end of file diff --git a/domokits/local/modules/VirtualProductDelivery/templates/pdf/default/delivery-address.html b/domokits/local/modules/VirtualProductDelivery/templates/pdf/default/delivery-address.html new file mode 100644 index 0000000..6a5a1f9 --- /dev/null +++ b/domokits/local/modules/VirtualProductDelivery/templates/pdf/default/delivery-address.html @@ -0,0 +1,3 @@ +

+ {intl l="No delivery address for this delivery method" d="virtualproductdelivery.pdf.default"} +

\ No newline at end of file diff --git a/domokits/local/modules/WebProfiler/Config/config.xml b/domokits/local/modules/WebProfiler/Config/config.xml new file mode 100644 index 0000000..d75e6f6 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/config.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/Config/config_dev.xml b/domokits/local/modules/WebProfiler/Config/config_dev.xml new file mode 100644 index 0000000..d75e6f6 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/config_dev.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/Config/config_prod.xml b/domokits/local/modules/WebProfiler/Config/config_prod.xml new file mode 100644 index 0000000..d75e6f6 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/config_prod.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/Config/config_test.xml b/domokits/local/modules/WebProfiler/Config/config_test.xml new file mode 100644 index 0000000..d75e6f6 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/config_test.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/Config/module.xml b/domokits/local/modules/WebProfiler/Config/module.xml new file mode 100644 index 0000000..07e5948 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/module.xml @@ -0,0 +1,43 @@ + + + WebProfiler\WebProfiler + + Add thelia specific data to web profiler + + + + Ajoute des données spécifique a thelia dans le web profiler + + + + + en_US + fr_FR + + 2.5.4 + + + + + + + classic + + 2.5.4 + other + 0 + 1 + diff --git a/domokits/local/modules/WebProfiler/Config/routing.xml b/domokits/local/modules/WebProfiler/Config/routing.xml new file mode 100644 index 0000000..f687f50 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/routing.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/domokits/local/modules/WebProfiler/Config/schema.xml b/domokits/local/modules/WebProfiler/Config/schema.xml new file mode 100644 index 0000000..793d486 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Config/schema.xml @@ -0,0 +1,25 @@ + + + + diff --git a/domokits/local/modules/WebProfiler/DataCollector/SmartyDataCollector.php b/domokits/local/modules/WebProfiler/DataCollector/SmartyDataCollector.php new file mode 100644 index 0000000..2dd4864 --- /dev/null +++ b/domokits/local/modules/WebProfiler/DataCollector/SmartyDataCollector.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace WebProfiler\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use TheliaSmarty\Template\DataCollectorSmartyParser; + +class SmartyDataCollector extends DataCollector +{ + private $smartyParser; + + public function __construct(DataCollectorSmartyParser $smartyParser) + { + $this->smartyParser = $smartyParser; + } + + public function collect(Request $request, Response $response, \Throwable $exception = null): void + { + $this->data['templates'] = $this->smartyParser->getCollectedTemplates(); + } + + public function getTemplates() + { + return $this->data['templates']; + } + + public function getTemplateCount() + { + return \count($this->data['templates']); + } + + public function getTotalExecutionTime() + { + return array_reduce($this->data['templates'], function ($carry, $template) { return $carry + $template['executionTime']; }, 0); + } + + public function getName() + { + return 'smarty'; + } + + public function reset(): void + { + $this->data['templates'] = []; + } +} diff --git a/domokits/local/modules/WebProfiler/DataCollector/TheliaCollector.php b/domokits/local/modules/WebProfiler/DataCollector/TheliaCollector.php new file mode 100644 index 0000000..a0cff16 --- /dev/null +++ b/domokits/local/modules/WebProfiler/DataCollector/TheliaCollector.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace WebProfiler\DataCollector; + +use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Thelia\Core\Thelia; + +class TheliaCollector extends AbstractDataCollector +{ + public function collect(Request $request, Response $response, \Throwable $exception = null): void + { + $this->data = [ + 'theliaVersion' => Thelia::THELIA_VERSION, + ]; + } + + public function getTheliaVersion() + { + return $this->data['theliaVersion']; + } + + public static function getTemplate(): ?string + { + return '@WebProfilerModule/debug/dataCollector/thelia.html.twig'; + } +} diff --git a/domokits/local/modules/WebProfiler/I18n/en_US.php b/domokits/local/modules/WebProfiler/I18n/en_US.php new file mode 100644 index 0000000..d391ee9 --- /dev/null +++ b/domokits/local/modules/WebProfiler/I18n/en_US.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + // 'an english string' => 'The displayed english string', +]; diff --git a/domokits/local/modules/WebProfiler/I18n/fr_FR.php b/domokits/local/modules/WebProfiler/I18n/fr_FR.php new file mode 100644 index 0000000..ff066ca --- /dev/null +++ b/domokits/local/modules/WebProfiler/I18n/fr_FR.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + // 'an english string' => 'La traduction française de la chaine', +]; diff --git a/domokits/local/modules/WebProfiler/Readme.md b/domokits/local/modules/WebProfiler/Readme.md new file mode 100644 index 0000000..f07f8c3 --- /dev/null +++ b/domokits/local/modules/WebProfiler/Readme.md @@ -0,0 +1,55 @@ +# Web Profiler + +Add a short description here. You can also add a screenshot if needed. + +## Installation + +### Manually + +* Copy the module into ```/local/modules/``` directory and be sure that the name of the module is WebProfiler. +* Activate it in your thelia administration panel + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require your-vendor/web-profiler-module:~1.0 +``` + +## Usage + +Explain here how to use your module, how to configure it, etc. + +## Hook + +If your module use one or more hook, fill this part. Explain which hooks are used. + + +## Loop + +If your module declare one or more loop, describe them here like this : + +[loop name] + +### Input arguments + +|Argument |Description | +|--- |--- | +|**arg1** | describe arg1 with an exemple. | +|**arg2** | describe arg2 with an exemple. | + +### Output arguments + +|Variable |Description | +|--- |--- | +|$VAR1 | describe $VAR1 variable | +|$VAR2 | describe $VAR2 variable | + +### Exemple + +Add a complete exemple of your loop + +## Other ? + +If you have other think to put, feel free to complete your readme as you want. diff --git a/domokits/local/modules/WebProfiler/WebProfiler.php b/domokits/local/modules/WebProfiler/WebProfiler.php new file mode 100644 index 0000000..0042bb3 --- /dev/null +++ b/domokits/local/modules/WebProfiler/WebProfiler.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace WebProfiler; + +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Thelia\Module\BaseModule; +use TheliaSmarty\Template\DataCollectorSmartyParser; +use WebProfiler\DataCollector\SmartyDataCollector; + +use function Symfony\Component\DependencyInjection\Loader\Configurator\service; + +class WebProfiler extends BaseModule +{ + /** @var string */ + public const DOMAIN_NAME = 'webprofiler'; + + /* + * You may now override BaseModuleInterface methods, such as: + * install, destroy, preActivation, postActivation, preDeactivation, postDeactivation + * + * Have fun ! + */ + + /** + * Defines how services are loaded in your modules. + */ + public static function configureServices(ServicesConfigurator $servicesConfigurator): void + { + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) + ->exclude( + [ + THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*', + THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/DataCollector/SmartyDataCollector', + ] + ) + ->autowire(true) + ->autoconfigure(true); + + $servicesConfigurator->set('data_collector.smarty', SmartyDataCollector::class) + ->args([ + service(DataCollectorSmartyParser::class)->ignoreOnInvalid(), + ]) + ->tag( + 'data_collector', + [ + 'template' => '@WebProfilerModule/debug/dataCollector/smarty.html.twig', + 'id' => 'smarty', + 'priority' => 42, + ] + ); + } +} diff --git a/domokits/local/modules/WebProfiler/composer.json b/domokits/local/modules/WebProfiler/composer.json new file mode 100644 index 0000000..97554a3 --- /dev/null +++ b/domokits/local/modules/WebProfiler/composer.json @@ -0,0 +1,12 @@ +{ + "name": "your-vendor/web-profiler-module", + "description": "WebProfiler module for Thelia", + "license": "LGPL-3.0-or-later", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "WebProfiler" + } +} diff --git a/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/base.html.twig b/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/base.html.twig new file mode 100644 index 0000000..538f7e1 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/base.html.twig @@ -0,0 +1,25 @@ + + + + + + + {% block title %}Thelia Profiler{% endblock %} + + {% block head %} + + {% endblock %} + + + + +{% block body '' %} + + diff --git a/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/header.html.twig b/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/header.html.twig new file mode 100644 index 0000000..3536442 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/bundles/WebProfilerBundle/Profiler/header.html.twig @@ -0,0 +1,5 @@ + diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smarty.svg b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smarty.svg new file mode 100644 index 0000000..efa16fe --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smarty.svg @@ -0,0 +1,48 @@ + +image/svg+xml + + diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smartyColor.svg b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smartyColor.svg new file mode 100644 index 0000000..6d0a989 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/smartyColor.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/thelia.svg b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/thelia.svg new file mode 100644 index 0000000..c0d85bd --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/thelia.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/theliaWhite.svg b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/theliaWhite.svg new file mode 100644 index 0000000..7a2ca27 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/Icon/theliaWhite.svg @@ -0,0 +1,41 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/smarty.html.twig b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/smarty.html.twig new file mode 100644 index 0000000..93f3139 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/smarty.html.twig @@ -0,0 +1,94 @@ +{% extends '@WebProfiler/Profiler/layout.html.twig' %} + +{% block toolbar %} + {% set icon %} + + {{ include('@WebProfilerModule/debug/dataCollector/Icon/smarty.svg') }} + + {{ collector.totalExecutionTime is defined ? collector.totalExecutionTime : 'n/a' }} + ms + + {% set text %} +
+ Render Time + {{ collector.totalExecutionTime is defined ? collector.totalExecutionTime : 'n/a' }} ms +
+
+ Template Calls + {{ collector.templatecount }} +
+ {% endset %} + {% endset %} + + {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: true, name: 'smarty', status: '', block_attrs: 'title=""' }) }} +{% endblock %} + +{% block menu %} + + {{ include('@WebProfilerModule/debug/dataCollector/Icon/smarty.svg') }} + Smarty + +{% endblock %} + +{% block panel %} + {% if collector.templatecount == 0 %} +

Smarty

+ +
+

No smarty templates were rendered for this request.

+
+ {% else %} +

Smarty Metrics

+ +
+
+ {{ collector.totalExecutionTime is defined ? collector.totalExecutionTime : 'n/a' }} ms + Render time +
+ +
+ {{ collector.templatecount }} + Template calls +
+
+ +

+ Render time includes sub-requests rendering time (if any). +

+ +

Rendered Templates

+ + + + + + + + + + {% for template in collector.templates %} + {%- set file = template.name -%} + {%- set link = file ? file|file_link(1) : false -%} + + + + + {% endfor %} + +
Template Name & PathRender time
+ {{ include('@WebProfilerModule/debug/dataCollector/Icon/smartyColor.svg') }} + {% if link %} + {{ template.name }} + + {% else %} + {{ template.name }} + {% endif %} + + {{ template.executionTime }} +
+ {% endif %} +{% endblock %} diff --git a/domokits/local/modules/WebProfiler/templates/debug/dataCollector/thelia.html.twig b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/thelia.html.twig new file mode 100644 index 0000000..f30e6c4 --- /dev/null +++ b/domokits/local/modules/WebProfiler/templates/debug/dataCollector/thelia.html.twig @@ -0,0 +1,12 @@ +{% extends '@WebProfiler/Profiler/layout.html.twig' %} + +{% block toolbar %} + {% set icon %} + + {{ include('@WebProfilerModule/debug/dataCollector/Icon/thelia.svg') }} + + {{ collector.theliaVersion is defined ? collector.theliaVersion : 'n/a' }} + {% endset %} + + {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false, name: 'thelia', status: '', additional_classes: 'sf-toolbar-block-right', block_attrs: 'title=""' }) }} +{% endblock %} diff --git a/domokits/templates/frontOffice/custom/Gruntfile.js b/domokits/templates/frontOffice/custom/Gruntfile.js index a9db3ed..ff0bc87 100644 --- a/domokits/templates/frontOffice/custom/Gruntfile.js +++ b/domokits/templates/frontOffice/custom/Gruntfile.js @@ -38,7 +38,8 @@ module.exports = function (grunt) { cssmin: { target: { files: { - 'assets/dist/css/thelia.min.css': 'assets/src/css/thelia.css' + 'assets/dist/css/thelia.min.css': 'assets/src/css/thelia.css', + 'assets/dist/css/custom.min.css': 'assets/src/css/custom.css' } } }, @@ -177,7 +178,9 @@ module.exports = function (grunt) { dev: { src: [ 'assets/src/css/thelia.css', - 'assets/dist/css/thelia.min.css' + 'assets/dist/css/thelia.min.css', + 'assets/src/css/custom.css', + 'assets/dist/css/custom.min.css' ] } }, @@ -198,7 +201,7 @@ module.exports = function (grunt) { } }, cssmin: { - files: ['assets/src/css/thelia.css'], + files: ['assets/src/css/thelia.css', 'assets/src/css/custom.css'], tasks: ['autoprefixer', 'cssmin'], options: { spawn: false, diff --git a/domokits/templates/frontOffice/custom/assets/dist/css/thelia.min.css b/domokits/templates/frontOffice/custom/assets/dist/css/thelia.min.css index f3675a8..e5372b0 100644 --- a/domokits/templates/frontOffice/custom/assets/dist/css/thelia.min.css +++ b/domokits/templates/frontOffice/custom/assets/dist/css/thelia.min.css @@ -2,7 +2,7 @@ * Bootstrap v3.3.6 (http://getbootstrap.com) * Copyright 2011-2015 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */@import url(//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800);hr,img{border:0}body,figure{margin:0}.btn-group>.btn-group,.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.dropdown-menu{float:left}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{vertical-align:middle}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}.glyphicon,address{font-style:normal}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{blockquote,img,pre,tr{page-break-inside:avoid}*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none}.img-thumbnail,body{background-color:#fff}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/bootstrap/glyphicons-halflings-regular.eot);src:url(../fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/bootstrap/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/bootstrap/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/bootstrap/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/bootstrap/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before,.glyphicon-btc:before,.glyphicon-xbt:before{content:"\e227"}.glyphicon-jpy:before,.glyphicon-yen:before{content:"\00a5"}.glyphicon-rub:before,.glyphicon-ruble:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*,:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:'Open Sans',sans-serif;font-size:14px;line-height:1.42857143;color:#7a7a7a}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#f49a17;text-decoration:none}a:focus,a:hover{color:#b66f09;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:3px;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#e5e5e5}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}dt,kbd kbd{font-weight:700}address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{padding-left:0;list-style:none}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#e5e5e5}.text-primary{color:#f49a17}a.text-primary:focus,a.text-primary:hover{color:#ce7e0a}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#f49a17}a.bg-primary:focus,a.bg-primary:hover{background-color:#ce7e0a}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}pre code,table{background-color:transparent}.page-header{padding-bottom:9px;margin:40px 0 20px}dl,ol,ul{margin-top:0}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0}address,dl{margin-bottom:20px}ol,ul{margin-bottom:10px}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}legend,pre{display:block}dd{margin-left:0}@media (min-width:992px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #e5e5e5}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#e5e5e5}legend,pre{color:#7a7a7a}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}code,kbd{padding:2px 4px;font-size:90%;border-radius:3px}caption,th{text-align:left}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{color:#c7254e;background-color:#f9f2f4}kbd{color:#fff;background-color:#333;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:3px}.container,.container-fluid{margin-right:auto;margin-left:auto}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0}.container,.container-fluid{padding-left:15px;padding-right:15px}.pre-scrollable{overflow-y:scroll}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}caption{padding-top:8px;padding-bottom:8px;color:#e5e5e5}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset,legend{padding:0;border:0}fieldset{margin:0;min-width:0}legend{width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px}input[type=search]{box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{padding-top:7px}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #e5e5e5;border-radius:3px;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#c7c7c7;opacity:1}.form-control:-ms-input-placeholder{color:#c7c7c7}.form-control::-webkit-input-placeholder{color:#c7c7c7}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px}.input-sm{height:30px;line-height:1.5}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;line-height:1.5}.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;line-height:1.3333333}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;line-height:1.3333333}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.collapsing,.dropdown,.dropup{position:relative}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .form-control{border-color:#3c763d;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#bababa}@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block}.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#f49a17;text-decoration:none}.btn.active,.btn:active{outline:0}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#f49a17;background-color:#f7f7f7;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#f49a17;background-color:#dedede;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#f49a17;background-color:#dedede;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#f49a17;background-color:#ccc;border-color:#8c8c8c}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#f7f7f7;border-color:#ccc}.btn-default .badge{color:#f7f7f7;background-color:#f49a17}.btn-primary{color:#fff;background-color:#f49a17;border-color:#f49a17}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#ce7e0a;border-color:#855206}.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#ce7e0a;border-color:#c47809}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#ac6908;border-color:#855206}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#f49a17;border-color:#f49a17}.btn-primary .badge{color:#f49a17;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#f49a17;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#b66f09;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#e5e5e5;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{height:0;overflow:hidden;transition-property:height,visibility;transition-duration:.35s;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:3px;background-clip:padding-box}.dropdown-menu-right,.dropdown-menu.pull-right{left:auto;right:0}.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle,.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child,.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{clear:both;font-weight:400;color:#7a7a7a}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#6d6d6d;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#f49a17}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#e5e5e5}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{font-size:12px;color:#e5e5e5}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:992px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn .caret,.btn-group>.btn:first-child{margin-left:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.block,.btn-group.open .dropdown-toggle.btn-link,.btn.active,.btn:active{box-shadow:none}.btn-lg .caret{border-width:5px 5px 0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-radius:3px 3px 0 0}.btn-group-vertical>.btn:last-child:not(:first-child){border-radius:0 0 3px 3px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.nav>li,.nav>li>a{display:block;position:relative}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #e5e5e5;border-radius:3px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#e5e5e5}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#e5e5e5;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#f49a17}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px;margin-right:0;border-radius:3px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:3px 3px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-justified>li,.nav-stacked>li{float:none}.nav-pills>li>a{border-radius:3px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#f49a17}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:3px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:992px){.navbar{border-radius:3px}.navbar-header{float:left}.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.embed-responsive,.modal,.modal-open,.progress{overflow:hidden}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:992px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:3px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:991px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-danger,.progress-striped .progress-bar-info,.progress-striped .progress-bar-success,.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}@media (min-width:992px){.navbar-toggle{display:none}.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px}@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block}.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}.breadcrumb>li,.pagination{display:inline-block}.btn .badge,.btn .label{top:-1px;position:relative}@media (max-width:991px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:992px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;box-shadow:none}.navbar-text{float:left;margin-left:15px;margin-right:15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:3px 3px 0 0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:992px){.navbar-left{float:left!important;float:left}.navbar-right{float:right!important;float:right;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f5f5f5;border-color:#fff}.navbar-default .navbar-brand{color:#707070}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#575757;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#707070}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#fff;background-color:#f49a17}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#fff}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#f49a17;color:#fff}@media (max-width:991px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#707070}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:#f49a17}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#707070}.navbar-default .navbar-link:hover{color:#fff}.navbar-default .btn-link{color:#707070}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#fff}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{background-color:transparent;color:#fff}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:991px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .btn-link,.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover,.navbar-inverse .navbar-link,.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{margin-bottom:20px;list-style:none;background-color:#fff;border-radius:3px}.breadcrumb>li+li:before{padding:0 5px;color:#7a7a7a}.breadcrumb>.active{color:#7a7a7a}.pagination{padding-left:0;margin:20px 0;border-radius:3px}.pager li,.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;background-color:#f9f9f9;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#b66f09;background-color:transparent;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;background-color:#f49a17;border-color:#f49a17;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#e5e5e5;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.badge,.label{font-weight:700;line-height:1;white-space:nowrap;text-align:center}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#f7f7f7;border:1px solid #ccc;border-radius:0}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:transparent}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#e5e5e5;background-color:#f7f7f7;cursor:not-allowed}a.badge:focus,a.badge:hover,a.label:focus,a.label:hover{color:#fff;cursor:pointer;text-decoration:none}.label{display:inline;padding:.2em .6em .3em;font-size:75%;color:#fff;vertical-align:baseline;border-radius:.25em}.label:empty{display:none}.label-default{background-color:#e5e5e5}.label-default[href]:focus,.label-default[href]:hover{background-color:#ccc}.label-primary{background-color:#f49a17}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#ce7e0a}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;color:#fff;vertical-align:middle;background-color:#e5e5e5;border-radius:10px}.badge:empty{display:none}.media-object,.thumbnail{display:block}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#f49a17;background-color:#fff}.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.alert,.thumbnail{margin-bottom:20px}.alert .alert-link,.close{font-weight:700}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:3px;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#f49a17}.thumbnail .caption{padding:9px;color:#7a7a7a}.alert{padding:15px;border:1px solid transparent;border-radius:3px}.alert h4{margin-top:0;color:inherit}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:3px;box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#f49a17;box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-bar-info{background-color:#5bc0de}.progress-bar-warning{background-color:#f0ad4e}.progress-bar-danger{background-color:#d9534f}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#e5e5e5;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#e5e5e5}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#f49a17;border-color:#f49a17}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#fdefda}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:0;box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-title,.panel>.list-group,.panel>.panel-collapse>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:-1;border-top-left-radius:-1}.panel-title{margin-top:0;font-size:16px}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel-group .panel-heading,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive:last-child>.table:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:-1;border-bottom-right-radius:-1}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:-1;border-top-left-radius:-1}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-right-radius:-1;border-top-left-radius:-1}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:-1}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:-1}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:0}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#f5f5f5}.panel-default>.panel-heading{color:#7a7a7a;background-color:#f5f5f5;border-color:#f5f5f5}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f5f5f5}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#7a7a7a}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f5f5f5}.panel-primary{border-color:#f49a17}.panel-primary>.panel-heading{color:#fff;background-color:#f49a17;border-color:#f49a17}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f49a17}.panel-primary>.panel-heading .badge{color:#f49a17;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f49a17}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:3px;box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.popover,.tooltip{font-family:'Open Sans',sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;text-decoration:none}.modal-title,.popover,.tooltip{line-height:1.42857143}.carousel-caption,.carousel-caption .btn,.carousel-control,.popover,.product-price .price-label,.text-hide,.tooltip{text-shadow:none}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-content,.popover{background-clip:padding-box}.modal{display:none;position:fixed;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0}.modal-backdrop{position:fixed;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;text-align:left;text-align:start;font-size:12px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:3px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0}.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px}.tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px}.tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;text-align:start;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2)}.carousel-caption,.carousel-control,.carousel-indicators,.fa-fw,.fa-li{text-align:center}#categories.block-nav .block-title,#filters>h3,#product #product-tabs .nav-tabs li,.availability .in-stock,.availability .out-of-stock,.filter .filter-heading,.panel-heading,.table-cart thead th,.table-order thead th{text-transform:uppercase}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.carousel,.carousel-inner{position:relative}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.left>.arrow:after,.popover.right>.arrow:after{content:" ";bottom:-10px}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{left:1px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff}.carousel-inner{overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);left:0}}.cart-warning:before,.fa{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:10%;opacity:.5;filter:alpha(opacity=50);font-size:30px;color:#ccc;background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#ccc;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:45px;height:45px;margin-top:-15px;font-size:45px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.table-cart tbody td.product .name,.table-order tbody td.product .name,header .header .logo{margin-top:0}.block-thumbnail:after,.block-thumbnail:before,.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:" ";display:table}.block-thumbnail:after,.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0}.fa-inverse,.footer-container .footer-info a,.footer-container .footer-info a:focus,.footer-container .footer-info a:hover{color:#fff}.affix{position:fixed}@-ms-viewport{width:device-width}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}.hidden-lg{display:none!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}/*! + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */@import url(//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800);.label,audio,canvas,progress,sub,sup,video{vertical-align:baseline}.btn,.btn-group,.btn-group-vertical,.caret,.checkbox-inline,.input-group-addon,.input-group-btn,.radio-inline,img{vertical-align:middle}.collapsing,.dropdown-menu .divider,.nav .nav-divider,.sr-only,svg:not(:root){overflow:hidden}.popover,.tooltip,button,select{text-transform:none}hr,img{border:0}.cart-warning:before,.fa,.glyphicon{-moz-osx-font-smoothing:grayscale}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative}sup{top:-.5em}sub{bottom:-.25em}hr{box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}.glyphicon,.popover,.tooltip,address{font-style:normal}button{overflow:visible}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{blockquote,img,pre,tr{page-break-inside:avoid}*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}#product #product-gallery #product-thumbnails .carousel-control,.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-success,.open>.dropdown-toggle.btn-warning{background-image:none}.img-thumbnail,body{background-color:#fff}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/bootstrap/glyphicons-halflings-regular.eot);src:url(../fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/bootstrap/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/bootstrap/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/bootstrap/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/bootstrap/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased}#products-new .overlay:after,#products-offer .overlay:after,#products-upsell .overlay:after,.popover,.tooltip,body{font-family:'Open Sans',sans-serif}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before,.glyphicon-btc:before,.glyphicon-xbt:before{content:"\e227"}.glyphicon-jpy:before,.glyphicon-yen:before{content:"\00a5"}.glyphicon-rub:before,.glyphicon-ruble:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*,:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{margin:0;font-size:14px;line-height:1.42857143;color:#7a7a7a}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#f49a17;text-decoration:none}a:focus,a:hover{color:#b66f09;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}figure{margin:0}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:3px;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#e5e5e5}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,.label,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}dt,kbd kbd{font-weight:700}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{padding-left:0;list-style:none}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}#categories.block-nav .block-title,#filters>h3,#product #product-tabs .nav-tabs li,.availability .in-stock,.availability .out-of-stock,.filter .filter-heading,.initialism,.panel-heading,.table-cart tfoot th.total,.table-cart thead th,.table-order tfoot th.total,.table-order thead th{text-transform:uppercase}.text-muted{color:#e5e5e5}.text-primary{color:#f49a17}a.text-primary:focus,a.text-primary:hover{color:#ce7e0a}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#f49a17}a.bg-primary:focus,a.bg-primary:hover{background-color:#ce7e0a}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}pre code,table{background-color:transparent}.page-header{padding-bottom:9px;margin:40px 0 20px}dl,ol,ul{margin-top:0}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child,ol ol,ol ul,ul ol,ul ul{margin-bottom:0}ol,ul{margin-bottom:10px}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-bottom:20px}dd,dt{line-height:1.42857143}dd{margin-left:0}@media (min-width:992px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #e5e5e5}.initialism{font-size:90%}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#e5e5e5}legend,pre{color:#7a7a7a}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}code,kbd{padding:2px 4px;font-size:90%;border-radius:3px}.dropdown-menu,caption,th{text-align:left}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;line-height:1.42857143}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{color:#c7254e;background-color:#f9f2f4}kbd{color:#fff;background-color:#333;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:3px}.container,.container-fluid{margin-right:auto;margin-left:auto}#payment-success.panel .panel-heading .payment-method,pre code{font-size:inherit}.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle),.btn-link,pre code{border-radius:0}pre code{padding:0;color:inherit;white-space:pre-wrap}.pre-scrollable{overflow-y:scroll}.container{padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}caption{padding-top:8px;padding-bottom:8px;color:#e5e5e5}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset,legend{padding:0;border:0}fieldset{margin:0;min-width:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;border-bottom:1px solid transparent}label{display:inline-block;max-width:100%;margin-bottom:5px}input[type=search]{box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}.form-control,output{font-size:14px;line-height:1.42857143;display:block;color:#555}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{padding-top:7px}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #e5e5e5;border-radius:3px;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#c7c7c7;opacity:1}.form-control:-ms-input-placeholder{color:#c7c7c7}.form-control::-webkit-input-placeholder{color:#c7c7c7}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox-inline,.collapsing,.dropdown,.dropup,.has-feedback,.radio-inline{position:relative}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.btn-block+.btn-block,.help-block{margin-top:5px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px}.input-sm{height:30px;line-height:1.5}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;line-height:1.5}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.btn-group-lg>.btn,.btn-lg,.form-group-lg .form-control,.input-lg{padding:10px 16px;font-size:18px}.input-lg{height:46px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-bottom:10px;color:#bababa}@media (min-width:768px){.form-inline .form-control,.form-inline .form-control-static,.form-inline .form-group{display:inline-block}.form-inline .checkbox,.form-inline .control-label,.form-inline .form-group,.form-inline .radio{margin-bottom:0;vertical-align:middle}.form-inline .form-control{width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;-webkit-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#f49a17;text-decoration:none}.btn.active,.btn:active{outline:0}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#f49a17;background-color:#f7f7f7;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#f49a17;background-color:#dedede;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#f49a17;background-color:#dedede;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#f49a17;background-color:#ccc;border-color:#8c8c8c}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#f7f7f7;border-color:#ccc}.btn-default .badge{color:#f7f7f7;background-color:#f49a17}.btn-primary{color:#fff;background-color:#f49a17;border-color:#f49a17}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#ce7e0a;border-color:#855206}.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#ce7e0a;border-color:#c47809}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#ac6908;border-color:#855206}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#f49a17;border-color:#f49a17}.btn-primary .badge{color:#f49a17;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#f49a17}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#b66f09;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#e5e5e5;text-decoration:none}.btn-group-lg>.btn,.btn-lg{line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{height:0;transition-property:height,visibility;transition-duration:.35s;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:3px;background-clip:padding-box}.dropdown-menu-right,.dropdown-menu.pull-right{left:auto;right:0}.dropdown-header,.dropdown-menu>li>a{display:block;padding:3px 20px;line-height:1.42857143;white-space:nowrap}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child,.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.dropdown-menu .divider{height:1px;margin:9px 0;background-color:#e5e5e5}.dropdown-menu>li>a{clear:both;font-weight:400;color:#7a7a7a}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#6d6d6d;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#f49a17}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#e5e5e5}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{font-size:12px;color:#e5e5e5}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:992px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}#cart-address .panel,.block,.btn-group.open .dropdown-toggle.btn-link,.btn.active,.btn:active{box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.media-object.img-thumbnail,.nav>li>a>img{max-width:none}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-radius:3px 3px 0 0}.btn-group-vertical>.btn:last-child:not(:first-child){border-radius:0 0 3px 3px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group,.input-group .form-control,.input-group-btn,.input-group-btn>.btn,.nav>li,.nav>li>a,.navbar{position:relative}.input-group{display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #e5e5e5;border-radius:3px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{display:block}.nav>li>a{display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#e5e5e5}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#e5e5e5;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#f49a17}.nav .nav-divider{height:1px;margin:9px 0;background-color:#e5e5e5}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px;margin-right:0;border-radius:3px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:3px 3px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-justified>li,.nav-stacked>li{float:none}.nav-pills>li>a{border-radius:3px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#f49a17}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li>a{text-align:center;margin-bottom:5px}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.alert,.breadcrumb,.navbar,.progress,.thumbnail{margin-bottom:20px}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:3px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{min-height:50px;border:1px solid transparent}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:992px){.navbar{border-radius:3px}.navbar-header{float:left}.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-static-top{border-radius:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:992px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:3px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:991px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:992px){.navbar-toggle{display:none}.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px}@media (min-width:768px){.navbar-form .form-control,.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block}.navbar-form .checkbox,.navbar-form .control-label,.navbar-form .form-group,.navbar-form .radio{margin-bottom:0;vertical-align:middle}.navbar-form .form-control{width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}.breadcrumb>li,.pagination{display:inline-block}.btn .badge,.btn .label{top:-1px;position:relative}@media (max-width:991px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:992px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;box-shadow:none}.navbar-text{float:left;margin-left:15px;margin-right:15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:3px 3px 0 0}.breadcrumb,.pagination,.progress{border-radius:3px}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:992px){.navbar-left{float:left!important;float:left}.navbar-right{float:right!important;float:right;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f5f5f5;border-color:#fff}.navbar-default .navbar-brand{color:#707070}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#575757;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#707070}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#fff;background-color:#f49a17}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#fff}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#f49a17;color:#fff}@media (max-width:991px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#707070}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:#f49a17}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#707070}.navbar-default .navbar-link:hover{color:#fff}.navbar-default .btn-link{color:#707070}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#fff}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{background-color:transparent;color:#fff}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:991px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .btn-link,.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover,.navbar-inverse .navbar-link,.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{list-style:none;background-color:#fff}.breadcrumb>li+li:before{padding:0 5px;color:#7a7a7a}.breadcrumb>.active{color:#7a7a7a}.pagination{padding-left:0;margin:20px 0}.pager li,.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;background-color:#f9f9f9;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#b66f09;background-color:transparent;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;background-color:#f49a17;border-color:#f49a17;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#e5e5e5;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.badge,.label{font-weight:700;line-height:1;text-align:center;white-space:nowrap}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#f7f7f7;border:1px solid #ccc;border-radius:0}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:transparent}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.close,.list-group-item>.badge{float:right}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#e5e5e5;background-color:#f7f7f7;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;color:#fff;border-radius:.25em}.badge,.progress-bar,.tooltip{font-size:12px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#e5e5e5}.label-default[href]:focus,.label-default[href]:hover{background-color:#ccc}.label-primary{background-color:#f49a17}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#ce7e0a}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;color:#fff;vertical-align:middle;background-color:#e5e5e5;border-radius:10px}.badge:empty,.modal,.popover{display:none}.media-object,.thumbnail{display:block}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#f49a17;background-color:#fff}.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.alert .alert-link,.close{font-weight:700}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.list-group-item,.thumbnail{background-color:#fff;border:1px solid #ddd}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{padding:4px;line-height:1.42857143;border-radius:3px;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#f49a17}.thumbnail .caption{padding:9px;color:#7a7a7a}.alert,.panel-body{padding:15px}.alert{border:1px solid transparent;border-radius:3px}.alert h4{margin-top:0;color:inherit}.alert>p+p,.panel-group .panel+.panel{margin-top:5px}.alert>p,.alert>ul{margin-bottom:0}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;background-color:#f5f5f5;box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0%;height:100%;line-height:20px;color:#fff;text-align:center;background-color:#f49a17;box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px}.list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#e5e5e5;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#e5e5e5}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#f49a17;border-color:#f49a17}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#fdefda}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.panel-heading>.dropdown .dropdown-toggle,.panel-title,.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:0;box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-title,.panel>.list-group,.panel>.panel-collapse>.list-group,.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive,.panel>.table-responsive>.table{margin-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:-1;border-top-left-radius:-1}.panel-title{margin-top:0;font-size:16px}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:-1;border-top-left-radius:-1}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-right-radius:-1;border-top-left-radius:-1}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:-1}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:-1}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:-1;border-bottom-right-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:-1}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive{border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:0}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#f5f5f5}.panel-default>.panel-heading{color:#7a7a7a;background-color:#f5f5f5;border-color:#f5f5f5}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f5f5f5}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#7a7a7a}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f5f5f5}.panel-primary{border-color:#f49a17}.panel-primary>.panel-heading{color:#fff;background-color:#f49a17;border-color:#f49a17}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f49a17}.panel-primary>.panel-heading .badge{color:#f49a17;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f49a17}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.modal,.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:3px;box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.modal-title,.popover,.tooltip{line-height:1.42857143}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-content,.popover{background-clip:padding-box}.modal-open{overflow:hidden}.modal{overflow:hidden;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-ms-transform:translate(0,-25%);transform:translate(0,-25%);transition:transform .3s ease-out}.modal.in .modal-dialog{-ms-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0}.modal-backdrop{z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.carousel-control,.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-weight:400;letter-spacing:normal;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:3px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow,.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.top .tooltip-arrow{left:50%;margin-left:-5px}.tooltip.top-left .tooltip-arrow{right:5px;margin-bottom:-5px}.tooltip.top-right .tooltip-arrow{left:5px;margin-bottom:-5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow{border-width:0 5px 5px;border-bottom-color:#000;top:0}.tooltip.bottom .tooltip-arrow{left:50%;margin-left:-5px}.tooltip.bottom-left .tooltip-arrow{right:5px;margin-top:-5px}.tooltip.bottom-right .tooltip-arrow{left:5px;margin-top:-5px}.popover{position:absolute;top:0;left:0;z-index:1060;max-width:276px;padding:1px;font-weight:400;letter-spacing:normal;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.left>.arrow:after,.popover.right>.arrow:after{bottom:-10px;content:" "}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{left:1px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{transform:translate3d(0,0,0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:10%;font-size:30px;color:#ccc;text-align:center;text-shadow:none;background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#ccc;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:none}.affix,.loader{position:fixed}.product-price .price-label,.text-hide{color:transparent;border:0;text-shadow:none}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:45px;height:45px;margin-top:-15px;font-size:45px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.table-cart tbody td.product .name,.table-order tbody td.product .name,header .header .logo{margin-top:0}.block-thumbnail:after,.block-thumbnail:before,.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:" ";display:table}.block-thumbnail:after,.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;background-color:transparent}@-ms-viewport{width:device-width}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}.hidden-lg{display:none!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}/*! * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:FontAwesome;src:url(../fonts/fontawesome/fontawesome-webfont.eot?v=4.3.0);src:url(../fonts/fontawesome/fontawesome-webfont.eot?#iefix&v=4.3.0) format('embedded-opentype'),url(../fonts/fontawesome/fontawesome-webfont.woff2?v=4.3.0) format('woff2'),url(../fonts/fontawesome/fontawesome-webfont.woff?v=4.3.0) format('woff'),url(../fonts/fontawesome/fontawesome-webfont.ttf?v=4.3.0) format('truetype'),url(../fonts/fontawesome/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before,.fa-genderless:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}header .header{margin-bottom:20px}header .header .language-container .search-container{margin-bottom:10px}header .header .language-container .search-container .form-control{width:auto}header .header .language-container .currency-switch,header .header .language-container .language-switch{display:inline-block;position:relative;vertical-align:middle}header .header .language-container .currency-switch .dropdown-label,header .header .language-container .language-switch .dropdown-label{display:inline-block;float:left;margin-left:1em;margin-right:.4em}header .header .language-container .currency-switch .current,header .header .language-container .language-switch .current{display:inline-block;float:left;position:relative}#payment-method.panel .radio,.account-info .email,.account-info .mobile,.account-info .tel,.js .group-qty .form-inline .form-group{display:block}header .header .language-container .currency-switch .select,header .header .language-container .language-switch .select{left:auto;right:0;min-width:80px}.footer-container .footer-banner .banner .col{padding:10px 0}.footer-container .footer-block .blocks,.footer-container .footer-info .info{padding:20px 0}.footer-container .footer-info .info .nav-footer ul li+li:before{margin-right:10px}.account-info address{margin-bottom:0}.account-info li{margin-bottom:20px}.list-payment,.table-order tbody td.qty .group-qty{margin-bottom:0}.table-order-total td{width:50%}#delivery-address .panel-heading{position:relative}.checkout-progress{margin-bottom:20px;width:100%}.cart-warning,.table-cart tbody td.qty .group-qty,.table-cart-mini{margin-bottom:0}.cart-empty{margin:0;padding:40px}.table-cart-total td{width:50%}.cart-warning{clear:both}.pagination>li>a:focus,.pagination>li>span:focus{z-index:3}@media (min-width:992px){.navbar .navbar-cart .dropdown>a:after,.navbar .navbar-customer .dropdown>a:after{padding-left:.3em;display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);content:"\f078";float:none}}@media (min-width:992px) and (min-width:992px){.navbar .navbar-cart .dropdown>a:after,.navbar .navbar-customer .dropdown>a:after{float:none}}.navbar .navbar-cart .dropdown-menu,.navbar .navbar-customer .dropdown-menu{margin:0;padding:20px}@media (max-width:992px){.navbar .navbar-cart .dropdown-menu,.navbar .navbar-customer .dropdown-menu{display:none}}.navbar .navbar-cart .dropdown-menu.cart-content,.navbar .navbar-customer .dropdown-menu.cart-content{width:350px}.navbar .navbar-cart .dropdown-menu.cart-content>p,.navbar .navbar-customer .dropdown-menu.cart-content>p{margin:0}.navbar .navbar-cart .cart-not-empty .cart-content,.navbar .navbar-customer .cart-not-empty .cart-content{border-top:none;padding:0}.navbar .full-width{position:static}.navbar .full-width .dropdown-menu{width:100%;left:0;right:0}.navbar .full-width .dropdown-menu .dropdown-content .dropdown-subheading{display:block}.js .dropdown-toggle:after{float:right;padding-left:.3em}@media (min-width:992px){.navbar-collapse .navbar-nav.navbar-right:first-child{margin-right:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:0}.js .dropdown-toggle:after{float:none}}#form-forgotpassword,#form-login{padding:45px}#form-forgotpassword legend,#form-login legend{margin-bottom:10px}#filters,.filter{margin-bottom:20px}.filter{padding:0 15px}.grid .products-content>ul .item .product-price,.grid .products-content>ul .item>article .product-image{padding:0}.filter .filter-heading{margin:0 0 4px}.toolbar{margin-bottom:20px}.toolbar .sorter-container .amount{float:left}.grid .products-content>ul .item>article .product-image,.grid .products-content>ul .item>article .product-info,.grid .products-content>ul .item>article .product-price,.list .products-content>ul .item{width:100%;float:none}.toolbar .sorter-container .sort-by,.toolbar .sorter-container .view-mode{margin-left:40px}.toolbar .pagination-container>.pagination{margin:15px 0 0}.products-content>ul .item .product-info .short-description,.products-content>ul .item .product-price .price-container{display:block;margin-bottom:5px}.grid .products-content>ul .item{margin-bottom:20px}.grid .products-content>ul .item>article{margin:0}.grid .products-content>ul .item>article .name{margin:4px 0}.grid .products-content>ul .item .description{display:none!important}@media (max-width:767px){.grid .products-content>ul .item .description{display:block!important}table.grid .products-content>ul .item .description{display:table!important}tr.grid .products-content>ul .item .description{display:table-row!important}td.grid .products-content>ul .item .description,th.grid .products-content>ul .item .description{display:table-cell!important}}.list .products-content>ul .item+.item{padding-top:15px}.list .products-content>ul .item>article{margin-left:0}.list .products-content>ul .item>article .product-image{margin-bottom:15px;padding:0}.list .products-content>ul .item>article .product-info .name{margin-top:0}.option{margin-bottom:20px;padding:0}.option .option-heading{display:block;margin:0 0 5px}#product #product-gallery .product-image,#product>section{margin-bottom:20px}#product #product-gallery #product-thumbnails .carousel-inner{margin:0 auto;width:90%}#brands .brands>ul .item>article,#folder-contents .contents>ul .item>article,.contents-list .item>article{margin-left:0}#product #product-gallery #product-thumbnails .carousel-control{background-image:none;display:none;width:4%;margin-top:-4px}#brands .brands>ul .item>article .brand-info .name,#folder-contents .contents>ul .item>article .content-info .name,#product #product-details .name,.contents-list .item>article .content-info .name,.page-header,.table-address .radio,.table-delivery .radio{margin-top:0}#product #product-gallery #product-thumbnails ul{margin:0}#product #product-gallery #product-thumbnails ul>li{margin:0;padding:0;width:19%}#product #product-details .product-price,#product #product-tabs{margin-bottom:20px}#folder-contents .contents>ul .item>article .content-image>img,.contents-list .item>article .content-image>img{width:100%}#product #product-details .product-cart{margin-bottom:20px;padding:0}#product #product-tabs .nav-tabs{margin-bottom:-1px}.folder-description{margin-bottom:20px}.contents-list .item{padding-bottom:15px}.contents-list .item+.item{padding-top:15px}.contents-list .item>article .content-image{margin-bottom:15px;padding:0}.brand-description{margin-bottom:20px}#brands .brands>ul .item{padding-bottom:15px}#brands .brands>ul .item+.item{padding-top:15px}#brands .brands>ul .item>article .brand-image{margin-bottom:15px;padding:0}header .header .logo a{text-decoration:none}header .header .language-container{text-align:right}header .header .language-container .currency-switch .dropdown-label,header .header .language-container .language-switch .dropdown-label{font-size:1em;font-weight:300}.footer-container .footer-banner{background-color:#e8e8e8;font-size:19px}.footer-container .footer-banner .banner i{display:block;font-size:2em}.footer-container .footer-banner .banner small{font-size:.65em;display:block;font-style:italic;font-weight:400}.footer-container .footer-banner .banner .col{text-align:center}.footer-container .footer-banner .banner .col+.col{border-top:1px solid #d6d6d6}@media (min-width:768px){.footer-container .footer-banner .banner .col+.col{border-left:1px solid #d6d6d6;border-top:none}}.footer-container .footer-block{background-color:#f5f5f5}.footer-container .footer-info{background-color:#444;color:#fff;font-size:12px}.footer-container .footer-info .info .nav-footer ul li+li:before{content:'-'}.footer-container .footer-info .info .copyright{font-weight:300;text-align:right}#payment-method.panel .panel-body,.cart-warning{text-align:center}.footer-container .footer-info .info .copyright>a{font-weight:700}.cart-warning>a{color:inherit}.cart-warning:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f071";display:block;font-size:2.2em}.breadcrumb>li+li:before,.js .dropdown-toggle:after{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}#cart-address .panel{box-shadow:none;border:none}#payment-method.panel .radio label>img{border:1px solid #ddd;border-radius:3px;opacity:.4;filter:alpha(opacity=40)}#payment-method.panel .radio label>img:focus,#payment-method.panel .radio label>img:hover{opacity:1;filter:alpha(opacity=100);transition:opacity .2s ease-in-out}.btn,a{transition:all .3s ease-in-out}#payment-method .list-group-item{border:none}.js #payment-method .radio .active>img,.js #payment-method .radio input:checked+img{opacity:1;filter:alpha(opacity=100)}.checkout-progress .btn-step{padding:16px 24px;background:#eee;color:#555}.checkout-progress .btn-step+.btn-step{border-left:1px solid #555}.checkout-progress .btn-step .step-nb{border-right:1px solid #7a7a7a;font-size:30px;line-height:0;font-weight:600;padding-right:6px;vertical-align:middle}.checkout-progress .btn-step .step-label{font-size:20px;font-weight:100;min-width:250px;padding-left:6px;vertical-align:middle}.checkout-progress .btn-step.active,.checkout-progress .btn-step:active,.checkout-progress .btn-step:focus,.checkout-progress .btn-step:hover{color:#fff;background:#f49a17}.checkout-progress .btn-step.active .step-nb,.checkout-progress .btn-step:active .step-nb,.checkout-progress .btn-step:focus .step-nb,.checkout-progress .btn-step:hover .step-nb{border-right:1px solid #fff}.checkout-progress .btn-step.active{background:#f49a17;cursor:default;display:inherit;pointer-events:none}.price{color:#f49a17;font-size:20px;font-weight:700;font-style:italic;white-space:nowrap}.old-price .price{color:#7a7a7a;font-size:16px;font-weight:600;text-decoration:line-through}#folder-contents .contents>ul .item{padding-bottom:15px}#folder-contents .contents>ul .item+.item{padding-top:15px;border-top:1px solid #ededed}#folder-contents .contents>ul .item>article .content-image{margin-bottom:15px;padding:0}.contents-list .item+.item{border-top:1px solid #ededed}.breadcrumb{padding:0}.breadcrumb>li+li:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f105"}.btn{border-radius:0;text-align:left;font-weight:600}.btn-primary{font-style:italic;border-left:3px solid #f9c478}.btn-primary:focus,.btn-primary:hover{background-color:#f49a17;color:#b66f09}.btn-default{border-left:3px solid #ccc}.btn-default:focus,.btn-default:hover{background-color:#f7f7f7}.btn-default.active,.btn-default.active:hover,.btn-default:active,.btn-default:active:hover,.btn-primary.active,.btn-primary.active:hover,.btn-primary:active,.btn-primary:active:hover{background-color:#d5d5d5;border-color:#6f6f6f;color:#fff}.btn-link{font-weight:400}.form-control:focus::-moz-placeholder{color:#eee;opacity:1}.form-control:focus:-ms-input-placeholder{color:#eee}.form-control:focus::-webkit-input-placeholder{color:#eee}#form-login-mini{width:200px}#form-login-mini .mini-forgot-password{font-size:12px}#form-forgotpassword,#form-login{background:#f5f5f5}#form-forgotpassword legend,#form-login legend{font-size:14px;font-weight:700}.fn,.table-address .radio label,.table-delivery .radio label{font-weight:600}#form-forgotpassword .btn-login,#form-login .btn-login{display:block;width:100%}@media (min-width:768px){#form-forgotpassword .group-btn,#form-login .group-btn{text-align:right}#form-forgotpassword .group-btn .btn-login,#form-login .group-btn .btn-login{display:inline-block;width:auto}}@media (min-width:992px){.btn{padding:2px 15px 2px 5px}#form-forgotpassword,#form-login{width:45%}}.no-js .collapse{display:block!important}.loader,.no-js #carousel .carousel-control{display:none}.loader{position:fixed;background:url(../img/ajax-loader.gif) center center no-repeat #fff;background-color:rgba(255,255,255,.5);left:0;top:0;width:100%;height:100%;z-index:100}.oldie{position:absolute}.thumbnail.active{border-color:#7a7a7a}.main{margin-bottom:20px}.fn{display:block}.adr,.org{font-size:12px}.table-address .group-btn,.table-delivery .group-btn{text-align:right}.table-address tbody>tr>td,.table-address tbody>tr>th,.table-address tfoot>tr>td,.table-address tfoot>tr>th,.table-address thead>tr>td,.table-address thead>tr>th,.table-delivery tbody>tr>td,.table-delivery tbody>tr>th,.table-delivery tfoot>tr>td,.table-delivery tfoot>tr>th,.table-delivery thead>tr>td,.table-delivery thead>tr>th{border-color:#f5f5f5;padding:10px 10px 0}@media (min-width:768px){.table-address tbody>tr>td,.table-address tbody>tr>th,.table-address tfoot>tr>td,.table-address tfoot>tr>th,.table-address thead>tr>td,.table-address thead>tr>th,.table-delivery tbody>tr>td,.table-delivery tbody>tr>th,.table-delivery tfoot>tr>td,.table-delivery tfoot>tr>th,.table-delivery thead>tr>td,.table-delivery thead>tr>th{padding:30px 30px 0}}.modal-dialog td{vertical-align:middle}.modal-dialog .close{margin:10px;position:relative;z-index:10}.modal-dialog .btn{margin-left:10px}@media screen and (min-width:768px){.modal-dialog{width:800px}}.navbar.navbar-secondary{z-index:1001}@media (min-width:992px){.navbar .list-subnav{background-color:#f49a17;border:1px solid #f49a17;border-radius:0;box-shadow:none}.navbar .list-subnav>li>a{color:#fff;padding:3px 12px}.navbar .list-subnav>.active>a,.navbar .list-subnav>.active>a:focus,.navbar .list-subnav>.active>a:hover,.navbar .list-subnav>li>a:focus,.navbar .list-subnav>li>a:hover{background-color:#fff;color:#f49a17}}.table-cart tfoot td.empty,.table-cart-total td.empty,.table-order tfoot td.empty,.table-order-total td.empty{border-bottom-color:transparent;border-left-color:transparent}.navbar .full-width .dropdown-menu .dropdown-content{padding:20px}.navbar .full-width .dropdown-menu .dropdown-content .dropdown-subheading{font-weight:700}.js .dropdown-toggle:after{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f078"}.alert-warning:before,.block-default .block-content li:before{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}#account .panel-heading{padding:0}#account .panel-heading .panel-title>a{background:#f49a17;color:#fff;display:block;padding:12px 15px;text-decoration:none}#account .panel-heading .panel-title>a.collapsed{background:0 0;color:inherit}#account .panel-heading .panel-title>a.collapsed:focus,#account .panel-heading .panel-title>a.collapsed:hover{background:#f49a17;color:#fff}#account .panel-body{padding:25px}.table-cart tbody>tr>td,.table-cart tbody>tr>th,.table-cart tfoot>tr>td,.table-cart tfoot>tr>th,.table-cart thead>tr>td,.table-cart thead>tr>th,.table-order tbody>tr>td,.table-order tbody>tr>th,.table-order tfoot>tr>td,.table-order tfoot>tr>th,.table-order thead>tr>td,.table-order thead>tr>th{padding:14px;text-align:center;vertical-align:middle}.table-cart tbody>tr>td.product,.table-cart tbody>tr>th.product,.table-cart tfoot>tr>td.product,.table-cart tfoot>tr>th.product,.table-cart thead>tr>td.product,.table-cart thead>tr>th.product,.table-order tbody>tr>td.product,.table-order tbody>tr>th.product,.table-order tfoot>tr>td.product,.table-order tfoot>tr>th.product,.table-order thead>tr>td.product,.table-order thead>tr>th.product{text-align:left}.table-cart tbody>tr>td.image,.table-cart tbody>tr>th.image,.table-cart tfoot>tr>td.image,.table-cart tfoot>tr>th.image,.table-cart thead>tr>td.image,.table-cart thead>tr>th.image,.table-order tbody>tr>td.image,.table-order tbody>tr>th.image,.table-order tfoot>tr>td.image,.table-order tfoot>tr>th.image,.table-order thead>tr>td.image,.table-order thead>tr>th.image{border-right-color:transparent}.table-cart thead th,.table-order thead th{background-color:#f5f5f5;border-bottom-width:1px}.table-cart thead th.subprice,.table-order thead th.subprice{color:#f49a17}.table-cart tbody td.price,.table-cart tbody td.qty,.table-cart tbody td.subprice,.table-order tbody td.price,.table-order tbody td.qty,.table-order tbody td.subprice{padding:35px 10px}.table-cart tbody td.unitprice .price,.table-order tbody td.unitprice .price{color:#7a7a7a}.table-cart tbody td.unitprice .old-price .price,.table-order tbody td.unitprice .old-price .price{font-size:14px}.table-cart tbody td.unitprice .secondary-price .price,.table-order tbody td.unitprice .secondary-price .price{font-size:14px;font-weight:400}.table-cart tbody td.subprice .price,.table-order tbody td.subprice .price{color:#f49a17}.table-cart tfoot td,.table-cart tfoot th,.table-order tfoot td,.table-order tfoot th{background-color:#f5f5f5}.table-cart tfoot td.empty,.table-cart tfoot th.empty,.table-order tfoot td.empty,.table-order tfoot th.empty{background:0 0}.table-cart tfoot td.total,.table-cart tfoot th.total,.table-order tfoot td.total,.table-order tfoot th.total{background-color:#666;color:#fff}.table-cart tfoot td.total .price,.table-cart tfoot th.total .price,.table-order tfoot td.total .price,.table-order tfoot th.total .price{color:inherit}.table-cart tfoot td.shipping .price,.table-order tfoot td.shipping .price{color:#7a7a7a;font-size:19px}.table-cart tfoot td.total .price,.table-order tfoot td.total .price{font-size:19px}.table-cart tfoot th.total,.table-order tfoot th.total{text-transform:uppercase;font-weight:100;font-size:16px}.table-cart-total td.total .price,.table-order-total td.total .price{font-size:19px}.alert-warning{clear:both;margin-bottom:0;text-align:center}.alert-warning>a{color:inherit}.alert-warning:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f071";display:block;font-size:2.2em}.block{background:0 0;border:1px solid transparent;border-radius:0}.block .block-heading{background:0 0;border-bottom:1px solid #dfdfdf;color:#888;margin:0 0 6px;padding-bottom:6px}.block .block-title{font-size:21px;margin-top:0;margin-bottom:0}.block .block-title>a{color:inherit}.block .block-content{font-size:12px;margin-bottom:20px}.block .block-content ul{padding-left:0;list-style:none}.block .block-content .block-subtitle{color:#f49a17;font-size:16px;font-weight:300;margin:0 0 6px}.block-default .block-content li{margin-left:15px;padding-top:6px}.block-default .block-content li a{color:#747474}.block-default .block-content li a:focus,.block-default .block-content li a:hover{color:#b66f09}.block-default .block-content li:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f054";color:#f49a17;margin-left:-15px;margin-right:5px}.block-nav .block-content li a.accordion-toggle:after,.has-error .help-block:before{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}.block-links .block-content li a,.block-nav .block-content li a{color:#747474;display:block;font-weight:400;position:relative;font-size:12px}.block-links .block-content li+li a{border-top:1px solid #fff}.block-links .block-content li a{background-color:transparent;padding:10px 3px}.block-links .block-content li a:focus,.block-links .block-content li a:hover{text-decoration:none;background-color:#ebebeb}.block-links .block-content li a>p,.block-nav .block-heading{margin-bottom:0}.block-nav .block-content li a{background-color:transparent;padding:10px 60px 10px 3px}.block-nav .block-content li a:focus,.block-nav .block-content li a:hover{text-decoration:none;background-color:#f7f7f7}.block-nav .block-content li a.accordion-toggle:after{color:#f49a17;display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f068"}.block-nav .block-content li a.accordion-toggle.collapsed:after{content:"\f067"}.block-nav .block-content ul a{padding-left:15px}.block-nav .block-content ul ul a{padding-left:30px}.block-nav .block-content ul ul ul a{padding-left:45px}.block-thumbnail{margin-left:-15px;margin-right:-15px}.block-thumbnail.block-thumbnail-2 li{max-width:50%}.block-thumbnail.block-thumbnail-3 li{max-width:33.33333333%}.block-thumbnail.block-thumbnail-4 li{max-width:25%}.block-thumbnail .block-content li{float:left;padding-right:7.5px;padding-bottom:7.5px;position:relative;max-width:33.33333333%}.block-social .block-content li{display:inline-block;font-size:18px}.block-social .block-content li>a{color:#888}.block-social .block-content li>a:focus,.block-social .block-content li>a:hover{color:#b66f09}.block-newsletter .block-content form .btn-subscribe{padding:6px}.block-contact .block-content li{clear:both;margin-bottom:5px}.block-carousel{margin-bottom:30px}.block-carousel .carousel-indicators{bottom:auto}.block-carousel .block-carousel-control{float:right!important;float:right}.block-carousel .block-carousel-control .carousel-control{background:#efefef;color:#000;display:block;float:left;font-size:24px;margin-left:3px;position:relative;top:1px;left:auto;bottom:auto;width:28px;height:28px;transition:background-color .3s ease-in-out}.label-delivered,.label-new,.label-sale{padding:.2em .6em .3em;font-size:75%;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;color:#fff;font-weight:700}.btn .label-delivered,.btn .label-new,.btn .label-sale{top:-1px;position:relative}#brands .brands>ul .item>article .brand-image>img,.grid .item .product-image>img,.list .item>article .product-image>img{width:100%}.block-carousel .block-carousel-control .carousel-control:focus,.block-carousel .block-carousel-control .carousel-control:hover{background-color:#000;color:#fff}.label-new{display:inline;background-color:#5bc0de}a.label-new:focus,a.label-new:hover{color:#fff;text-decoration:none;cursor:pointer}.label-new:empty{display:none}.label-new[href]:focus,.label-new[href]:hover{background-color:#31b0d5}.label-sale{display:inline;background-color:#d9534f}a.label-sale:focus,a.label-sale:hover{color:#fff;text-decoration:none;cursor:pointer}.label-sale:empty{display:none}.label-sale[href]:focus,.label-sale[href]:hover{background-color:#c9302c}.label-delivered{display:inline;background-color:#5cb85c}a.label-delivered:focus,a.label-delivered:hover{color:#fff;text-decoration:none;cursor:pointer}.grid .btn-grid,.list .btn-list{cursor:default;pointer-events:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.label-delivered:empty{display:none}.label-delivered[href]:focus,.label-delivered[href]:hover{background-color:#449d44}.products-heading .btn-all{float:right}.products-heading h3{top:-14px!important;margin:0}.availability .in-stock{color:#5cb85c;font-style:italic;font-weight:700}.availability .in-stock .in{display:block}.availability .in-stock .out,.availability .out-of-stock .in{display:none}.availability .in-stock .quantity{font-style:italic}.availability .out-of-stock{color:#f0ad4e;font-style:italic;font-weight:700}.availability .out-of-stock .out{display:block}#brands .brands>ul .item>article .brand-image.overlay:after,.no-js .toolbar .limiter,.no-js .toolbar .sort-by{display:none}.option{background:#fff;border:1px solid transparent;border-radius:0}.option .option-heading{border-bottom:1px solid transparent;color:#7a7a7a;font-size:14px;font-weight:700}.option .option-content .checkbox label,.option .option-content .radio label{font-weight:100}#product #product-gallery{border-right:1px solid #f5f5f5;padding-right:20px}#product #product-details .name{font-size:21px;font-weight:400}#product #product-details .product-cart{background:#fff;border:1px solid transparent;border-radius:0}#product #product-tabs .nav-tabs{border-bottom:1px solid #ddd}#product #product-tabs .tab-content{border:1px solid #ddd;border-radius:0 0 3px 3px;padding:30px 15px;min-height:180px;height:auto!important;height:180px}.list .item+.item{border-top:1px solid #ededed}.list .item>article .product-price{text-align:right}.filter{background:#f5f5f5;border:1px solid #f5f5f5;border-radius:0}.filter .filter-heading{border-bottom:1px solid #dfdfdf;color:#888;font-size:19px;font-weight:100}.filter .filter-content .checkbox label,.filter .filter-content .radio label{font-weight:100}.toolbar{line-height:50px}.toolbar .pagination-container,.toolbar .sorter-container{overflow:hidden;height:50px}.toolbar .sorter-container{background-color:#fff;border-radius:0;padding:0;text-align:right}.overlay:after,.page-home #carousel .item,.toolbar .pagination-container{text-align:center}.toolbar .sorter-container .view-mode>.view-mode-btn{font-size:24px}.toolbar .sorter-container .view-mode>.view-mode-btn a{padding:0 6px;font-size:21px;text-decoration:none}#brands .brands>ul .item+.item{border-top:1px solid #ededed}.page-404 .main{padding:10px 0 100px}.page-404 #main-label{color:#f49a17;font-size:9em;font-weight:700;text-align:center}.page-404 #main-label span{color:#CCC;display:block;font-size:15px;font-weight:400}.page-home #carousel{margin-bottom:20px}@media screen and (min-width:768px){.page-home #carousel .carousel-control .fa-caret-left,.page-home #carousel .carousel-control .fa-caret-right{font-size:80px;margin-top:-40px;margin-left:-40px;width:80px;height:80px}}.page-header{border:none;font-weight:100;font-size:30px}.form-control{box-shadow:none}.form-control:invalid:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.dropdown-menu,.modal-content,.popover{box-shadow:none}.has-error .help-block:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f00d";margin-right:.3em}label{font-weight:600}.popover{border-radius:3px}.overlay{display:block;overflow:hidden;position:relative;font-size:40px}.overlay:after,.overlay:before{display:block;width:100%;height:100%;visibility:hidden;position:absolute;top:0;left:0;right:0;opacity:0;filter:alpha(opacity=0);transition:all .3s ease-in-out 50ms}.overlay:before{content:'';overflow:visible;background-color:#f49a17;background-color:rgba(244,154,23,.4)}.overlay:after{font-family:FontAwesome;content:"\f002";color:#fff;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);line-height:0}.overlay:focus:after,.overlay:focus:before,.overlay:hover:after,.overlay:hover:before{visibility:visible;opacity:1;filter:alpha(opacity=100)}.overlay:focus:after,.overlay:hover:after{-webkit-transform:translate(0,50%);-ms-transform:translate(0,50%);transform:translate(0,50%)}.navbar li>a.home:before,.navbar li>a.login:before{font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);margin-right:.5em;display:inline-block}.navbar li>a.home:before{-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f015";color:#c9c9c9;font-size:26px;line-height:0;position:relative;top:3px}.navbar li>a.login:before{-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f007";color:#f49a17;font-size:19px;line-height:0}#product-details .product-promo .sale-saving:before,.navbar li.cart-not-empty>a.cart:before{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);text-rendering:auto;-moz-osx-font-smoothing:grayscale}.navbar li>a.cart:focus>.badge,.navbar li>a.cart:hover>.badge{background-color:#fff;color:#f49a17}.navbar li.cart-not-empty>a.cart{background-color:#f49a17;color:#fff}.navbar li.cart-not-empty>a.cart>.badge{background-color:#fff;color:#f49a17}.navbar li.cart-not-empty>a.cart:focus,.navbar li.cart-not-empty>a.cart:hover{background-color:#f49a17;color:#fff}.navbar li.cart-not-empty>a.cart:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f07a";color:#fff;font-size:24px;line-height:0;margin-right:.4em}@media (min-width:992px){.navbar .navbar-nav .list-subnav>li+li{border-top:1px solid #e28a0b}.navbar .navbar-nav .list-subnav>li>a{font-weight:100}}.navbar .navbar-nav>li>a:focus:before,.navbar .navbar-nav>li>a:hover:before{color:#fff}.navbar .navbar-nav>.active>a:focus,.navbar .navbar-nav>.active>a:hover{background-color:#f49a17;color:#fff}.navbar .navbar-nav>.active:after{background:#f49a17;content:"";display:block;position:absolute;bottom:0;width:100%;height:2px;z-index:100}.navbar .navbar-nav>.open>a,.navbar .navbar-nav>.open>a:focus,.navbar .navbar-nav>.open>a:hover{background-color:#f49a17;color:#fff}.navbar .navbar-nav>.open>a:before,.navbar .navbar-nav>.open>a:focus:before,.navbar .navbar-nav>.open>a:hover:before{color:#fff}.container>.navbar-collapse{margin-left:-15px;margin-right:-15px}header .header .logo{float:none}.page-home #carousel .carousel-control{background-image:none}.products-heading h2{color:#7a7a7a;font-size:18px;font-weight:700}.products-heading .btn-all,.products-heading .btn-all:focus,.products-heading .btn-all:hover{color:#7a7a7a;font-size:16px;font-style:italic;font-weight:600}.products-heading .short-description{background-color:#f5f5f5;margin-bottom:10px;padding:10px}.product-options dl{font-size:.85em;margin-bottom:10px}.product-options dl>dt{text-align:left}.product-info .name,td.product .name{font-size:16px;font-weight:600}.product-info .name>a,td.product .name>a{color:#7a7a7a;text-decoration:none}.product-info .name>a:focus,.product-info .name>a:hover,td.product .name>a:focus,td.product .name>a:hover{color:#b66f09}.product-price .price-label{font:0/0 a;color:transparent;background-color:transparent;border:0;display:block}.product-price .regular-price .price,.product-price .special-price .price{display:block;font-size:14px;line-height:25px;font-style:normal;font-weight:400}.product-price .old-price .price{display:block;font-size:14px;line-height:25px;font-style:italic;font-weight:400;text-decoration:line-through}#products-new .products-grid .overlay:after{-webkit-transform:translate(0,40%);-ms-transform:translate(0,40%);transform:translate(0,40%)}#products-new .products-grid .item>article{border-bottom:4px solid #f49a17;border-bottom-right-radius:3px;border-bottom-left-radius:3px;overflow:hidden;position:relative}#products-new .products-grid .item>article .product-info{background-color:#f6af48;color:#fff;display:block;padding:6px 12px;position:relative;text-decoration:none!important}#products-new .products-grid .item>article .product-info:focus,#products-new .products-grid .item>article .product-info:hover{background-color:#f49a17}#products-new .products-grid .item>article .product-info .name{min-height:40px;height:auto!important;height:40px}#products-new .products-grid .item>article .product-info .name:after{content:'+';font-size:45px;line-height:0;font-style:normal;font-weight:100;position:absolute;top:16px;right:4px;-webkit-font-smoothing:antialiased}#products-new .products-grid .item>article .product-info .short-description{font-size:11px;line-height:1.1}#products-new .products-grid .item>article .product-price .price{color:#fff;font-size:22px;font-weight:700}@media (min-width:992px){#products-new .products-grid .item>article .product-image{padding-bottom:40px}#products-new .products-grid .item>article .product-info{transition:height .3s linear;position:absolute;bottom:0;width:100%;height:50px}#products-new .products-grid .item>article .product-info h3{margin-top:2px;padding-right:20px}#products-new .products-grid .item>article .product-info h3 span{height:2em;overflow:hidden;display:block}#products-new .products-grid .item>article .product-info:focus,#products-new .products-grid .item>article .product-info:hover{cursor:pointer;height:140px}}#products-upsell{margin-top:40px;position:relative}#products-upsell .products-heading{border-bottom:1px solid #e5e5e5;margin:20px 0}#products-upsell .products-heading h3{background:#fff;color:#f49a17;padding-right:15px;position:absolute;top:-24px}#products-offer .products-grid .item>article,#products-related .products-grid .item>article,#products-upsell .products-grid .item>article{border-radius:3px;transition:background-color .3s ease-in-out;padding:6px}#products-offer .products-grid .item>article .product-info,#products-related .products-grid .item>article .product-info,#products-upsell .products-grid .item>article .product-info{padding:0}#products-offer .products-grid .item>article .product-info .short-description,#products-related .products-grid .item>article .product-info .short-description,#products-upsell .products-grid .item>article .product-info .short-description{font-size:11px}@media (min-width:768px){#products-offer .products-grid .item:hover article,#products-related .products-grid .item:hover article,#products-upsell .products-grid .item:hover article{background-color:#f6f6f6}}#products-new .overlay:after,#products-offer .overlay:after,#products-upsell .overlay:after{content:'+';font-family:'Open Sans',sans-serif;font-size:80px;font-weight:100;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#products-new .overlay:before{border-radius:3px 3px 0 0}#category-products .item>article .product-info .description{font-size:.83em;line-height:1.3}#category-products .item>article .product-price .price-label{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:block}#category-products .item>article .product-price .price-container{margin-bottom:10px}#category-products .item>article .product-price .price-container .price{margin-left:4px}#category-products .item>article .product-price .product-btn{min-height:26px}.grid #category-products .item{border-right:1px solid #e8e8e8;margin:0;padding:10px}.grid #category-products .item>article .product-info{padding:3px}.grid #category-products .item>article .product-info .name{margin:4px;height:2em;overflow:hidden}.grid #category-products .item>article .product-info .description{margin-left:4px}.list #category-products .item>article .product-price .price-container{margin-bottom:20px}.list #category-products .item>article .product-price .price-container .old-price,.list #category-products .item>article .product-price .price-container .regular-price,.list #category-products .item>article .product-price .price-container .special-price{display:block;width:100%}#product-details .product-info{border-bottom:1px solid #e5e5e5;margin-bottom:15px}#product-details .product-info .sku{color:#e5e5e5;display:block;font-size:14px;margin-top:-8px;margin-bottom:20px}#product-details .product-info .pse-name{color:#555;font-size:14px}#product-details .product-options .option{margin-bottom:10px}#product-details .product-cart{background-color:#f5f5f5!important;margin-bottom:20px;padding:10px!important}#product-details .product-promo{background-color:#f5f5f5;margin-bottom:15px;padding:10px}#product-details .product-promo .sale-label{font-weight:300;line-height:1.4;font-size:21px}#product-details .product-promo .sale-saving{color:#f49a17}#product-details .product-promo .sale-saving:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f005"}#product-details .product-promo .sale-period{font-style:italic;font-size:90%}#product-thumbnails .carousel-control{width:17px!important}#product-thumbnails .carousel-control .fa{position:absolute;top:50%}#product-thumbnails .carousel-control.left{border-right:7px solid #ccc;color:#ccc;text-align:left}#product-thumbnails .carousel-control.left>.fa-caret-left{left:0;margin-left:0;margin-top:-15px}#product-thumbnails .carousel-control.left>.fa-caret-left:before{color:inherit}#product-thumbnails .carousel-control.right{border-left:7px solid #ccc;text-align:right}#product-thumbnails .carousel-control.right>.fa-caret-right{left:auto;right:0;margin-left:0;margin-top:-15px}@media (min-width:768px){#product #product-gallery{border-right:1px solid #eee;padding-right:20px}#product #product-details .group-qty .form-control{display:inline-block;margin-right:1em;margin-left:.4em;width:100px}}#product-gallery .product-image{margin-bottom:20px}#product-gallery .product-thumbnails li{width:20%}#filters{background:#f5f5f5}#filters>h3{background:#e5e5e5;box-shadow:inset 0 -4px 10px rgba(0,0,0,.125);margin:0 0 15px;padding:10px 15px;font-size:18px;font-weight:700}#filters>h3>span{display:block;font-size:.75em;font-weight:100;text-transform:lowercase}#filters>h3:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);content:"\f002";font-size:30px;float:left;margin-right:.5em}#filters .filter{margin-bottom:10px}.block.block-links .block-content ul>li+li a{border-top:none}.block.block-links .block-content ul>li+li:before{background:#fff;content:"";display:block;margin:0 auto;text-align:center;width:65%;height:2px}.block.block-contact .block-content ul>li.contact-address:before,.block.block-newsletter .block-content form .form-group:before{display:inline-block;text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}.block.block-newsletter .block-content form .form-group{position:relative}@media (min-width:1200px){.block.block-newsletter .block-content form .form-group{width:176px}}.block.block-newsletter .block-content form .form-group .form-control{background-color:#e6e6e6;font-size:12px;padding-left:35px;width:inherit;box-shadow:inset 1px 1px 1px rgba(0,0,0,.075)}.block.block-newsletter .block-content form .form-group .form-control::-moz-placeholder{color:#888;opacity:1}.block.block-newsletter .block-content form .form-group .form-control:-ms-input-placeholder{color:#888}.block.block-newsletter .block-content form .form-group .form-control::-webkit-input-placeholder{color:#888}.block.block-newsletter .block-content form .form-group .form-control:focus::-moz-placeholder{color:#c8c8c8;opacity:1}.block.block-newsletter .block-content form .form-group .form-control:focus:-ms-input-placeholder{color:#c8c8c8}.block.block-newsletter .block-content form .form-group .form-control:focus::-webkit-input-placeholder{color:#c8c8c8}.block.block-newsletter .block-content form .form-group:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f0e0";color:#8b8b8b;font-size:18px;position:absolute;top:8px;left:9px}.block.block-newsletter .block-content form .btn-subscribe{padding:6px}.block.block-social .block-content ul>li>a:hover.facebook{color:#3d5fa6}.block.block-social .block-content ul>li>a:hover.twitter{color:#53b1f0}.block.block-social .block-content ul>li>a:hover.rss{color:#fac200}.block.block-social .block-content ul>li>a:hover.instagram{color:#425E75}.block.block-social .block-content ul>li>a:hover.google-plus{color:#fac200}.block.block-social .block-content ul>li>a:hover.youtube{color:#e82a20}.block.block-contact .block-content ul>li{clear:both;margin-bottom:5px}.block.block-contact .block-content ul>li.contact-address:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f041";font-size:34px}.block.block-contact .block-content ul>li.contact-email:before,.block.block-contact .block-content ul>li.contact-phone:before{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);display:inline-block}.block.block-contact .block-content ul>li.contact-phone:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f10b";font-size:30px;margin-top:-8px;margin-left:3px}.block.block-contact .block-content ul>li.contact-email:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f0e0";font-size:17px;margin-left:2px}.block.block-contact .block-content ul>li.contact-contact:before,.js #payment-method .radio .active:after{text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}.block.block-contact .block-content ul>li:before{color:#f49a17;float:left;line-height:1;margin-right:.4em}.block.block-contact .block-content ul>li.contact-contact:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f1d8";font-size:17px}#categories.block-nav .block-content{border-top:1px solid #aeaeae}#categories.block-nav .block-content .amount{font-weight:700}#categories.block-nav .block-content li{border-top:1px solid #eee;position:relative}#categories.block-nav .block-content li .accordion-toggle{position:absolute;top:0;right:0;padding-right:10px;padding-left:5px}#categories.block-nav .block-content li .accordion-toggle:focus,#categories.block-nav .block-content li .accordion-toggle:hover{background:0 0}#categories.block-nav .block-content li .accordion-toggle:focus:after,#categories.block-nav .block-content li .accordion-toggle:hover:after{border-color:#b66f09;color:#b66f09}#categories.block-nav .block-content li .accordion-toggle:after{border:1px solid #f49a17;border-radius:10px;line-height:17px;text-align:center;width:19px;height:19px}.toolbar.toolbar-top{margin-top:-20px;border-bottom:1px solid #eee}.toolbar.toolbar-bottom .sorter-container,.toolbar.toolbar-top .pagination-container{display:none}.toolbar .amount{color:#f49a17;font-size:22px;font-weight:400}.toolbar .view-mode>.view-mode-btn a{background-color:#fff;border:0!important;color:#7a7a7a}.toolbar .view-mode>.view-mode-btn a:focus,.toolbar .view-mode>.view-mode-btn a:hover{background-color:#efefef;color:#474747}.toolbar .view-mode>.view-mode-btn a:active{color:#fff}.pagination>li>a,.pagination>li>span{box-shadow:2px 1px 1px rgba(0,0,0,.1);transition:all .2s ease-in-out;background-image:linear-gradient(to bottom,#fff 0,#f9f9f9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff9f9f9', GradientType=0);color:#7a7a7a;font-weight:700}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{background:0 0}.pagination>li>a:focus:active,.pagination>li>a:hover:active,.pagination>li>span:focus:active,.pagination>li>span:hover:active{background-color:#f49a17;border-color:#f49a17;color:#fff}.pagination>li:first-child>a,.pagination>li:first-child>span{border-bottom-left-radius:30px;border-top-left-radius:30px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:30px;border-top-right-radius:30px}.pagination>.active>a,.pagination>.active>span{background-image:none}#form-forgotpassword .group-email label,#form-forgotpassword legend,#form-login .group-email label,#form-login legend{font-size:16px;font-weight:600}#form-forgotpassword .radio-account1,#form-login .radio-account1{margin-top:10px}#form-forgotpassword .forgot-password,#form-login .forgot-password{color:#7a7a7a;font-size:12px;font-style:italic}@media (min-width:768px){#form-forgotpassword .radio-account1,#form-login .radio-account1{float:left}#form-forgotpassword .group-password,#form-login .group-password{float:right;margin-top:5px;width:50%}}#delivery-address.panel .panel-body,#delivery-method.panel .panel-body{padding:0}#delivery-method.panel .radio{display:block;margin-top:0}#delivery-method.panel .radio+.radio{border-top:1px solid #f5f5f5}#delivery-method.panel .price{text-align:right}#delivery-method.panel .image{text-align:center}#account .panel-title,#payment-success.panel .panel-heading{text-align:left}.js #payment-method .radio{padding-left:0;position:relative}.js #payment-method .radio .active:after{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f077";color:#f49a17;display:block;font-size:1.5em;line-height:0;position:absolute;bottom:-8px;left:40%}#account .panel-title>a:before,#account-info .list-info .mobile:before{display:inline-block;text-rendering:auto;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0)}#payment-success.panel .panel-heading .payment-method{font-size:inherit}#payment-success.panel .panel-body{padding:20px 40px}#account-address .panel-body,#account-orders .panel-body{padding-left:0;padding-right:0}#payment-success.panel .panel-body>h3{color:#f49a17}#account .panel{box-shadow:none;border-color:#fff}#account .panel-title>a:before{font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f078";float:left;width:20px}#account .panel-title>a.collapsed:before{content:"\f054"}#account-info .fn{font-size:16px;font-weight:600}#account-info .list-info .email:before,#account-info .list-info .mobile:before,#account-info .list-info .tel:before{color:#f49a17;line-height:1;margin-right:.4em;vertical-align:middle}#account-info .list-info .mobile:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f10b";font-size:30px}#account-info .list-info .email:before,#account-info .list-info .tel:before{display:inline-block;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);text-rendering:auto;-moz-osx-font-smoothing:grayscale}#account-info .list-info .tel:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f095";font-size:22px}#account-info .list-info .email:before{font:normal normal normal 14px/1 FontAwesome;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f0e0";font-size:18px}#account-info .group-btn a{color:#7a7a7a;margin-bottom:4px;padding:0}#account-info .group-btn a>i{color:#f49a17;font-size:20px;line-height:1;margin-right:.3em;vertical-align:middle}#account-info .group-btn a:focus,#account-info .group-btn a:hover{color:#b66f09}#account-address .panel-body{padding-top:10px}#account-address .table-address{border:1px solid #f5f5f5;margin-bottom:0}#account-orders .table-orders tbody>tr>td,#account-orders .table-orders tbody>tr>th,#account-orders .table-orders thead>tr>td,#account-orders .table-orders thead>tr>th{padding:14px;text-align:center}#account-orders .table-orders thead>tr>th{background-color:#f5f5f5;border-bottom-width:1px}#account-orders .table-order-products tbody>tr>td,#account-orders .table-order-products tbody>tr>th,#account-orders .table-order-products thead>tr>td,#account-orders .table-order-products thead>tr>th{padding:5px;text-align:center}.table-cart-mini tbody>tr>td,.table-cart-mini tbody>tr>th,.table-cart-mini tfoot>tr>td,.table-cart-mini tfoot>tr>th,.table-cart-mini thead>tr>td,.table-cart-mini thead>tr>th{vertical-align:middle}#google-map{border:none;display:block;margin-bottom:20px;width:100%;height:350px;-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%);-ms-filter:grayscale(100%);-o-filter:grayscale(100%);filter:grayscale(100%)}#sale-details .sale-discount-information{background-color:#f5f5f5;margin-bottom:10px;padding:10px}#sale-details .sale-discount-information .sale-saving{font-size:120%;color:#f49a17}#sale-details .sale-discount-information .sale-saving:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0);content:"\f005"}#sale-details .sale-discount-information .sale-period{font-style:italic;font-size:90%}#sale-details .sale-information{margin-bottom:30px}#sale-details .sale-information .chapo,#sale-details .sale-information .description{margin-bottom:10px} \ No newline at end of file + */@font-face{font-family:FontAwesome;src:url(../fonts/fontawesome/fontawesome-webfont.eot?v=4.3.0);src:url(../fonts/fontawesome/fontawesome-webfont.eot?#iefix&v=4.3.0) format('embedded-opentype'),url(../fonts/fontawesome/fontawesome-webfont.woff2?v=4.3.0) format('woff2'),url(../fonts/fontawesome/fontawesome-webfont.woff?v=4.3.0) format('woff'),url(../fonts/fontawesome/fontawesome-webfont.ttf?v=4.3.0) format('truetype'),url(../fonts/fontawesome/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before,.has-error .help-block:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.block-default .block-content li:before,.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.cart-warning:before,.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before,.fa-genderless:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}header .header{margin-bottom:20px}header .header .language-container .search-container{margin-bottom:10px}header .header .language-container .search-container .form-control{width:auto}header .header .language-container .currency-switch,header .header .language-container .language-switch{display:inline-block;position:relative;vertical-align:middle}header .header .language-container .currency-switch .dropdown-label,header .header .language-container .language-switch .dropdown-label{display:inline-block;float:left;margin-left:1em;margin-right:.4em}header .header .language-container .currency-switch .current,header .header .language-container .language-switch .current{display:inline-block;float:left;position:relative}#payment-method.panel .radio,.account-info .email,.account-info .mobile,.account-info .tel,.js .group-qty .form-inline .form-group{display:block}header .header .language-container .currency-switch .select,header .header .language-container .language-switch .select{left:auto;right:0;min-width:80px}.footer-container .footer-banner .banner .col{padding:10px 0}.footer-container .footer-block .blocks,.footer-container .footer-info .info{padding:20px 0}.footer-container .footer-info .info .nav-footer ul li+li:before{margin-right:10px}.account-info address{margin-bottom:0}.account-info li{margin-bottom:20px}.list-payment,.table-order tbody td.qty .group-qty{margin-bottom:0}.table-order-total td{width:50%}#delivery-address .panel-heading{position:relative}.checkout-progress{margin-bottom:20px;width:100%}.alert-warning,.cart-warning,.table-cart tbody td.qty .group-qty,.table-cart-mini{margin-bottom:0}.cart-empty{margin:0;padding:40px}.table-cart-total td{width:50%}.cart-warning{clear:both}.pagination>li>a:focus,.pagination>li>span:focus{z-index:3}@media (min-width:992px){.navbar .navbar-cart .dropdown>a:after,.navbar .navbar-customer .dropdown>a:after{padding-left:.3em;display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f078";float:none}}@media (min-width:992px) and (min-width:992px){.navbar .navbar-cart .dropdown>a:after,.navbar .navbar-customer .dropdown>a:after{float:none}}.navbar .navbar-cart .dropdown-menu,.navbar .navbar-customer .dropdown-menu{margin:0;padding:20px}@media (max-width:992px){.navbar .navbar-cart .dropdown-menu,.navbar .navbar-customer .dropdown-menu{display:none}}.navbar .navbar-cart .dropdown-menu.cart-content,.navbar .navbar-customer .dropdown-menu.cart-content{width:350px}.grid .products-content>ul .item>article .product-image,.grid .products-content>ul .item>article .product-info,.grid .products-content>ul .item>article .product-price,.list .products-content>ul .item{width:100%;float:none}.navbar .navbar-cart .dropdown-menu.cart-content>p,.navbar .navbar-customer .dropdown-menu.cart-content>p{margin:0}.navbar .navbar-cart .cart-not-empty .cart-content,.navbar .navbar-customer .cart-not-empty .cart-content{border-top:none;padding:0}.navbar .full-width{position:static}.navbar .full-width .dropdown-menu{width:100%;left:0;right:0}.navbar .full-width .dropdown-menu .dropdown-content .dropdown-subheading{display:block}.js .dropdown-toggle:after{float:right;padding-left:.3em}@media (min-width:992px){.navbar-collapse .navbar-nav.navbar-right:first-child{margin-right:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:0}.js .dropdown-toggle:after{float:none}}#form-forgotpassword,#form-login{padding:45px}#form-forgotpassword legend,#form-login legend{margin-bottom:10px}#filters,.filter{margin-bottom:20px}.filter{padding:0 15px}.filter .filter-heading{margin:0 0 4px}.toolbar{margin-bottom:20px}.toolbar .sorter-container .amount{float:left}.toolbar .sorter-container .sort-by,.toolbar .sorter-container .view-mode{margin-left:40px}.toolbar .pagination-container>.pagination{margin:15px 0 0}.products-content>ul .item .product-info .short-description,.products-content>ul .item .product-price .price-container{display:block;margin-bottom:5px}.grid .products-content>ul .item{margin-bottom:20px}.grid .products-content>ul .item>article{margin:0}.grid .products-content>ul .item>article .product-image{padding:0}.grid .products-content>ul .item>article .name{margin:4px 0}.grid .products-content>ul .item .description{display:none!important}@media (max-width:767px){.grid .products-content>ul .item .description{display:block!important}table.grid .products-content>ul .item .description{display:table!important}tr.grid .products-content>ul .item .description{display:table-row!important}td.grid .products-content>ul .item .description,th.grid .products-content>ul .item .description{display:table-cell!important}}.grid .products-content>ul .item .product-price{padding:0}.list .products-content>ul .item+.item{padding-top:15px}.list .products-content>ul .item>article{margin-left:0}.list .products-content>ul .item>article .product-image{margin-bottom:15px;padding:0}.list .products-content>ul .item>article .product-info .name{margin-top:0}.option{margin-bottom:20px;padding:0}.option .option-heading{display:block;margin:0 0 5px}#product #product-gallery .product-image,#product>section{margin-bottom:20px}#product #product-gallery #product-thumbnails .carousel-inner{margin:0 auto;width:90%}#brands .brands>ul .item>article,#folder-contents .contents>ul .item>article,.contents-list .item>article{margin-left:0}#product #product-gallery #product-thumbnails .carousel-control{display:none;width:4%;margin-top:-4px}#brands .brands>ul .item>article .brand-info .name,#folder-contents .contents>ul .item>article .content-info .name,#product #product-details .name,.contents-list .item>article .content-info .name,.page-header,.table-address .radio,.table-delivery .radio{margin-top:0}#product #product-gallery #product-thumbnails ul{margin:0}#product #product-gallery #product-thumbnails ul>li{margin:0;padding:0;width:19%}#folder-contents .contents>ul .item>article .content-image>img,.contents-list .item>article .content-image>img{width:100%}#product #product-details .product-price{margin-bottom:20px}#product #product-details .product-cart{margin-bottom:20px;padding:0}#product #product-tabs{margin-bottom:20px}#product #product-tabs .nav-tabs{margin-bottom:-1px}.folder-description{margin-bottom:20px}.contents-list .item{padding-bottom:15px}.contents-list .item+.item{padding-top:15px}.contents-list .item>article .content-image{margin-bottom:15px;padding:0}.brand-description,.main{margin-bottom:20px}#brands .brands>ul .item{padding-bottom:15px}#brands .brands>ul .item+.item{padding-top:15px}#brands .brands>ul .item>article .brand-image{margin-bottom:15px;padding:0}header .header .logo a{text-decoration:none}header .header .language-container{text-align:right}header .header .language-container .currency-switch .dropdown-label,header .header .language-container .language-switch .dropdown-label{font-size:1em;font-weight:300}.footer-container .footer-banner{background-color:#e8e8e8;font-size:19px}.footer-container .footer-banner .banner i{display:block;font-size:2em}.footer-container .footer-banner .banner small{font-size:.65em;display:block;font-style:italic;font-weight:400}.footer-container .footer-banner .banner .col{text-align:center}.footer-container .footer-banner .banner .col+.col{border-top:1px solid #d6d6d6}@media (min-width:768px){.footer-container .footer-banner .banner .col+.col{border-left:1px solid #d6d6d6;border-top:none}}.footer-container .footer-block{background-color:#f5f5f5}.footer-container .footer-info{background-color:#444;color:#fff;font-size:12px}.footer-container .footer-info a,.footer-container .footer-info a:focus,.footer-container .footer-info a:hover{color:#fff}.footer-container .footer-info .info .nav-footer ul li+li:before{content:'-'}.footer-container .footer-info .info .copyright{font-weight:300;text-align:right}#payment-method.panel .panel-body,.cart-warning{text-align:center}.footer-container .footer-info .info .copyright>a{font-weight:700}.alert-warning:before,.breadcrumb>li+li:before,.cart-warning:before,.js .dropdown-toggle:after{font:normal normal normal 14px/1 FontAwesome}.cart-warning>a{color:inherit}.cart-warning:before{text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);display:block;font-size:2.2em}.breadcrumb>li+li:before,.js .dropdown-toggle:after{-ms-transform:translate(0,0);text-rendering:auto;-moz-osx-font-smoothing:grayscale}#cart-address .panel{border:none}#payment-method.panel .radio label>img{border:1px solid #ddd;border-radius:3px;opacity:.4;filter:alpha(opacity=40)}#payment-method.panel .radio label>img:focus,#payment-method.panel .radio label>img:hover{opacity:1;filter:alpha(opacity=100);transition:opacity .2s ease-in-out}.btn,a{transition:all .3s ease-in-out}#payment-method .list-group-item{border:none}.js #payment-method .radio .active>img,.js #payment-method .radio input:checked+img{opacity:1;filter:alpha(opacity=100)}.checkout-progress .btn-step{padding:16px 24px;background:#eee;color:#555}.checkout-progress .btn-step+.btn-step{border-left:1px solid #555}.checkout-progress .btn-step .step-nb{border-right:1px solid #7a7a7a;font-size:30px;line-height:0;font-weight:600;padding-right:6px;vertical-align:middle}.checkout-progress .btn-step .step-label{font-size:20px;font-weight:100;min-width:250px;padding-left:6px;vertical-align:middle}.checkout-progress .btn-step.active,.checkout-progress .btn-step:active,.checkout-progress .btn-step:focus,.checkout-progress .btn-step:hover{color:#fff;background:#f49a17}.checkout-progress .btn-step.active .step-nb,.checkout-progress .btn-step:active .step-nb,.checkout-progress .btn-step:focus .step-nb,.checkout-progress .btn-step:hover .step-nb{border-right:1px solid #fff}.checkout-progress .btn-step.active{background:#f49a17;cursor:default;display:inherit;pointer-events:none}.price{color:#f49a17;font-size:20px;font-weight:700;font-style:italic;white-space:nowrap}.old-price .price{color:#7a7a7a;font-size:16px;font-weight:600;text-decoration:line-through}#folder-contents .contents>ul .item{padding-bottom:15px}#folder-contents .contents>ul .item+.item{padding-top:15px;border-top:1px solid #ededed}#folder-contents .contents>ul .item>article .content-image{margin-bottom:15px;padding:0}.contents-list .item+.item{border-top:1px solid #ededed}.breadcrumb{padding:0}.breadcrumb>li+li:before{display:inline-block;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f105"}.btn{border-radius:0;text-align:left;font-weight:600}.btn-primary{font-style:italic;border-left:3px solid #f9c478}.btn-primary:focus,.btn-primary:hover{background-color:#f49a17;color:#b66f09}.btn-default{border-left:3px solid #ccc}.btn-default:focus,.btn-default:hover{background-color:#f7f7f7}.btn-default.active,.btn-default.active:hover,.btn-default:active,.btn-default:active:hover,.btn-primary.active,.btn-primary.active:hover,.btn-primary:active,.btn-primary:active:hover{background-color:#d5d5d5;border-color:#6f6f6f;color:#fff}.btn-link{font-weight:400}.form-control:focus::-moz-placeholder{color:#eee;opacity:1}.form-control:focus:-ms-input-placeholder{color:#eee}.form-control:focus::-webkit-input-placeholder{color:#eee}#form-login-mini{width:200px}#form-login-mini .mini-forgot-password{font-size:12px}#form-forgotpassword,#form-login{background:#f5f5f5}#form-forgotpassword legend,#form-login legend{font-size:14px;font-weight:700}.fn,.table-address .radio label,.table-delivery .radio label{font-weight:600}#form-forgotpassword .btn-login,#form-login .btn-login{display:block;width:100%}@media (min-width:768px){#form-forgotpassword .group-btn,#form-login .group-btn{text-align:right}#form-forgotpassword .group-btn .btn-login,#form-login .group-btn .btn-login{display:inline-block;width:auto}}@media (min-width:992px){.btn{padding:2px 15px 2px 5px}#form-forgotpassword,#form-login{width:45%}}#brands .brands>ul .item>article .brand-image>img,.grid .item .product-image>img,.list .item>article .product-image>img,.loader{width:100%}.no-js .collapse{display:block!important}.loader,.no-js #carousel .carousel-control{display:none}.loader{background:url(../img/ajax-loader.gif) center center no-repeat #fff;background-color:rgba(255,255,255,.5);left:0;top:0;height:100%;z-index:100}.oldie{position:absolute}.thumbnail.active{border-color:#7a7a7a}.fn{display:block}.adr,.org{font-size:12px}.table-address .group-btn,.table-delivery .group-btn{text-align:right}.table-address tbody>tr>td,.table-address tbody>tr>th,.table-address tfoot>tr>td,.table-address tfoot>tr>th,.table-address thead>tr>td,.table-address thead>tr>th,.table-delivery tbody>tr>td,.table-delivery tbody>tr>th,.table-delivery tfoot>tr>td,.table-delivery tfoot>tr>th,.table-delivery thead>tr>td,.table-delivery thead>tr>th{border-color:#f5f5f5;padding:10px 10px 0}@media (min-width:768px){.table-address tbody>tr>td,.table-address tbody>tr>th,.table-address tfoot>tr>td,.table-address tfoot>tr>th,.table-address thead>tr>td,.table-address thead>tr>th,.table-delivery tbody>tr>td,.table-delivery tbody>tr>th,.table-delivery tfoot>tr>td,.table-delivery tfoot>tr>th,.table-delivery thead>tr>td,.table-delivery thead>tr>th{padding:30px 30px 0}}.modal-dialog td{vertical-align:middle}.modal-dialog .close{margin:10px;position:relative;z-index:10}.modal-dialog .btn{margin-left:10px}@media screen and (min-width:768px){.modal-dialog{width:800px}}.navbar.navbar-secondary{z-index:1001}@media (min-width:992px){.navbar .list-subnav{background-color:#f49a17;border:1px solid #f49a17;border-radius:0;box-shadow:none}.navbar .list-subnav>li>a{color:#fff;padding:3px 12px}.navbar .list-subnav>.active>a,.navbar .list-subnav>.active>a:focus,.navbar .list-subnav>.active>a:hover,.navbar .list-subnav>li>a:focus,.navbar .list-subnav>li>a:hover{background-color:#fff;color:#f49a17}}.navbar .full-width .dropdown-menu .dropdown-content{padding:20px}.navbar .full-width .dropdown-menu .dropdown-content .dropdown-subheading{font-weight:700}.js .dropdown-toggle:after{display:inline-block;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f078"}#account .panel-heading{padding:0}#account .panel-heading .panel-title>a{background:#f49a17;color:#fff;display:block;padding:12px 15px;text-decoration:none}#account .panel-heading .panel-title>a.collapsed{background:0 0;color:inherit}#account .panel-heading .panel-title>a.collapsed:focus,#account .panel-heading .panel-title>a.collapsed:hover{background:#f49a17;color:#fff}#account .panel-body{padding:25px}.table-cart tbody>tr>td,.table-cart tbody>tr>th,.table-cart tfoot>tr>td,.table-cart tfoot>tr>th,.table-cart thead>tr>td,.table-cart thead>tr>th,.table-order tbody>tr>td,.table-order tbody>tr>th,.table-order tfoot>tr>td,.table-order tfoot>tr>th,.table-order thead>tr>td,.table-order thead>tr>th{padding:14px;text-align:center;vertical-align:middle}.table-cart tbody>tr>td.product,.table-cart tbody>tr>th.product,.table-cart tfoot>tr>td.product,.table-cart tfoot>tr>th.product,.table-cart thead>tr>td.product,.table-cart thead>tr>th.product,.table-order tbody>tr>td.product,.table-order tbody>tr>th.product,.table-order tfoot>tr>td.product,.table-order tfoot>tr>th.product,.table-order thead>tr>td.product,.table-order thead>tr>th.product{text-align:left}.table-cart tbody>tr>td.image,.table-cart tbody>tr>th.image,.table-cart tfoot>tr>td.image,.table-cart tfoot>tr>th.image,.table-cart thead>tr>td.image,.table-cart thead>tr>th.image,.table-order tbody>tr>td.image,.table-order tbody>tr>th.image,.table-order tfoot>tr>td.image,.table-order tfoot>tr>th.image,.table-order thead>tr>td.image,.table-order thead>tr>th.image{border-right-color:transparent}.table-cart thead th,.table-order thead th{background-color:#f5f5f5;border-bottom-width:1px}.table-cart thead th.subprice,.table-order thead th.subprice{color:#f49a17}.table-cart tbody td.price,.table-cart tbody td.qty,.table-cart tbody td.subprice,.table-order tbody td.price,.table-order tbody td.qty,.table-order tbody td.subprice{padding:35px 10px}.table-cart tbody td.unitprice .price,.table-order tbody td.unitprice .price{color:#7a7a7a}.table-cart tbody td.unitprice .old-price .price,.table-order tbody td.unitprice .old-price .price{font-size:14px}.table-cart tbody td.unitprice .secondary-price .price,.table-order tbody td.unitprice .secondary-price .price{font-size:14px;font-weight:400}.table-cart tbody td.subprice .price,.table-order tbody td.subprice .price{color:#f49a17}.table-cart tfoot td,.table-cart tfoot th,.table-order tfoot td,.table-order tfoot th{background-color:#f5f5f5}.table-cart tfoot td.empty,.table-cart tfoot th.empty,.table-order tfoot td.empty,.table-order tfoot th.empty{background:0 0}.table-cart tfoot td.total,.table-cart tfoot th.total,.table-order tfoot td.total,.table-order tfoot th.total{background-color:#666;color:#fff}.table-cart tfoot td.total .price,.table-cart tfoot th.total .price,.table-order tfoot td.total .price,.table-order tfoot th.total .price{color:inherit}.table-cart tfoot td.shipping .price,.table-order tfoot td.shipping .price{color:#7a7a7a;font-size:19px}.table-cart tfoot td.total .price,.table-order tfoot td.total .price{font-size:19px}.table-cart tfoot td.empty,.table-order tfoot td.empty{border-bottom-color:transparent;border-left-color:transparent}.table-cart tfoot th.total,.table-order tfoot th.total{font-weight:100;font-size:16px}.table-cart-total td.total .price,.table-order-total td.total .price{font-size:19px}.table-cart-total td.empty,.table-order-total td.empty{border-bottom-color:transparent;border-left-color:transparent}.alert-warning{clear:both;text-align:center}.alert-warning>a{color:inherit}.alert-warning:before{text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f071";display:block;font-size:2.2em}.block{background:0 0;border:1px solid transparent;border-radius:0}.block .block-heading{background:0 0;border-bottom:1px solid #dfdfdf;color:#888;margin:0 0 6px;padding-bottom:6px}.block .block-title{font-size:21px;margin-top:0;margin-bottom:0}.block .block-title>a{color:inherit}.block .block-content{font-size:12px;margin-bottom:20px}.block .block-content ul{padding-left:0;list-style:none}.block .block-content .block-subtitle{color:#f49a17;font-size:16px;font-weight:300;margin:0 0 6px}.block-default .block-content li:before,.block-nav .block-content li a.accordion-toggle:after{font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-moz-osx-font-smoothing:grayscale}.block-default .block-content li{margin-left:15px;padding-top:6px}.block-default .block-content li a{color:#747474}.block-default .block-content li a:focus,.block-default .block-content li a:hover{color:#b66f09}.block-default .block-content li:before{display:inline-block;font-size:inherit;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);color:#f49a17;margin-left:-15px;margin-right:5px}.block-links .block-content li a,.block-nav .block-content li a{color:#747474;display:block;font-weight:400;position:relative;font-size:12px}.block-links .block-content li+li a{border-top:1px solid #fff}.block-links .block-content li a{background-color:transparent;padding:10px 3px}.block-links .block-content li a:focus,.block-links .block-content li a:hover{text-decoration:none;background-color:#ebebeb}.block-links .block-content li a>p,.block-nav .block-heading{margin-bottom:0}.block-nav .block-content li a{background-color:transparent;padding:10px 60px 10px 3px}.block-nav .block-content li a:focus,.block-nav .block-content li a:hover{text-decoration:none;background-color:#f7f7f7}.block-nav .block-content li a.accordion-toggle:after{color:#f49a17;display:inline-block;font-size:inherit;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f068"}.block-nav .block-content li a.accordion-toggle.collapsed:after{content:"\f067"}.block-nav .block-content ul a{padding-left:15px}.block-nav .block-content ul ul a{padding-left:30px}.block-nav .block-content ul ul ul a{padding-left:45px}.block-thumbnail{margin-left:-15px;margin-right:-15px}.block-thumbnail.block-thumbnail-2 li{max-width:50%}.block-thumbnail.block-thumbnail-3 li{max-width:33.33333333%}.block-thumbnail.block-thumbnail-4 li{max-width:25%}.block-thumbnail .block-content li{float:left;padding-right:7.5px;padding-bottom:7.5px;position:relative;max-width:33.33333333%}.block-social .block-content li{display:inline-block;font-size:18px}.block-social .block-content li>a{color:#888}.block-social .block-content li>a:focus,.block-social .block-content li>a:hover{color:#b66f09}.block-newsletter .block-content form .btn-subscribe{padding:6px}.block-contact .block-content li{clear:both;margin-bottom:5px}.block-carousel{margin-bottom:30px}.block-carousel .carousel-indicators{bottom:auto}.block-carousel .block-carousel-control{float:right!important;float:right}.block-carousel .block-carousel-control .carousel-control{background:#efefef;color:#000;display:block;float:left;font-size:24px;margin-left:3px;position:relative;top:1px;left:auto;bottom:auto;width:28px;height:28px;transition:background-color .3s ease-in-out}.label-delivered,.label-new,.label-sale{padding:.2em .6em .3em;font-size:75%;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;color:#fff}.btn .label-delivered,.btn .label-new,.btn .label-sale{top:-1px;position:relative}.block-carousel .block-carousel-control .carousel-control:focus,.block-carousel .block-carousel-control .carousel-control:hover{background-color:#000;color:#fff}.label-new{display:inline;font-weight:700;background-color:#5bc0de}a.label-new:focus,a.label-new:hover{color:#fff;text-decoration:none;cursor:pointer}.label-new:empty{display:none}.label-new[href]:focus,.label-new[href]:hover{background-color:#31b0d5}.label-sale{display:inline;font-weight:700;background-color:#d9534f}a.label-sale:focus,a.label-sale:hover{color:#fff;text-decoration:none;cursor:pointer}.label-sale:empty{display:none}.label-sale[href]:focus,.label-sale[href]:hover{background-color:#c9302c}.label-delivered{display:inline;font-weight:700;background-color:#5cb85c}a.label-delivered:focus,a.label-delivered:hover{color:#fff;text-decoration:none;cursor:pointer}.grid .btn-grid,.list .btn-list{cursor:default;pointer-events:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.label-delivered:empty{display:none}.label-delivered[href]:focus,.label-delivered[href]:hover{background-color:#449d44}.products-heading .btn-all{float:right}.products-heading h3{top:-14px!important;margin:0}.availability .in-stock{color:#5cb85c;font-style:italic;font-weight:700}.availability .in-stock .in{display:block}.availability .in-stock .out,.availability .out-of-stock .in{display:none}.availability .in-stock .quantity{font-style:italic}.availability .out-of-stock{color:#f0ad4e;font-style:italic;font-weight:700}.availability .out-of-stock .out{display:block}#brands .brands>ul .item>article .brand-image.overlay:after,.no-js .toolbar .limiter,.no-js .toolbar .sort-by{display:none}.option{background:#fff;border:1px solid transparent;border-radius:0}.option .option-heading{border-bottom:1px solid transparent;color:#7a7a7a;font-size:14px;font-weight:700}.option .option-content .checkbox label,.option .option-content .radio label{font-weight:100}#product #product-gallery{border-right:1px solid #f5f5f5;padding-right:20px}#product #product-details .name{font-size:21px;font-weight:400}#product #product-details .product-cart{background:#fff;border:1px solid transparent;border-radius:0}#product #product-tabs .nav-tabs{border-bottom:1px solid #ddd}#product #product-tabs .tab-content{border:1px solid #ddd;border-radius:0 0 3px 3px;padding:30px 15px;min-height:180px;height:auto!important;height:180px}.list .item+.item{border-top:1px solid #ededed}.list .item>article .product-price{text-align:right}.filter{background:#f5f5f5;border:1px solid #f5f5f5;border-radius:0}.filter .filter-heading{border-bottom:1px solid #dfdfdf;color:#888;font-size:19px;font-weight:100}.filter .filter-content .checkbox label,.filter .filter-content .radio label{font-weight:100}.toolbar{line-height:50px}.toolbar .pagination-container,.toolbar .sorter-container{overflow:hidden;height:50px}.toolbar .sorter-container{background-color:#fff;border-radius:0;padding:0;text-align:right}.toolbar .sorter-container .view-mode>.view-mode-btn{font-size:24px}.toolbar .sorter-container .view-mode>.view-mode-btn a{padding:0 6px;font-size:21px;text-decoration:none}.toolbar .pagination-container{text-align:center}#brands .brands>ul .item+.item{border-top:1px solid #ededed}.page-404 .main{padding:10px 0 100px}.page-404 #main-label{color:#f49a17;font-size:9em;font-weight:700;text-align:center}.page-404 #main-label span{color:#CCC;display:block;font-size:15px;font-weight:400}.page-home #carousel{margin-bottom:20px}.page-home #carousel .item{text-align:center}@media screen and (min-width:768px){.page-home #carousel .carousel-control .fa-caret-left,.page-home #carousel .carousel-control .fa-caret-right{font-size:80px;margin-top:-40px;margin-left:-40px;width:80px;height:80px}}.page-header{border:none;font-weight:100;font-size:30px}.has-error .help-block:before,.navbar li.cart-not-empty>a.cart:before,.navbar li>a.home:before,.navbar li>a.login:before{font:normal normal normal 14px/1 FontAwesome}.form-control{box-shadow:none}.form-control:invalid:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}#account .panel,.dropdown-menu,.modal-content,.popover{box-shadow:none}.has-error .help-block:before{display:inline-block;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);margin-right:.3em}label{font-weight:600}.popover{border-radius:3px}.overlay{display:block;overflow:hidden;position:relative;font-size:40px}.overlay:after,.overlay:before{display:block;width:100%;height:100%;visibility:hidden;position:absolute;top:0;left:0;right:0;opacity:0;filter:alpha(opacity=0);transition:all .3s ease-in-out 50ms}.overlay:before{content:'';overflow:visible;background-color:#f49a17;background-color:rgba(244,154,23,.4)}#filters>h3:before,.overlay:after{content:"\f002"}.overlay:after{font-family:FontAwesome;color:#fff;text-align:center;-ms-transform:translate(0,0);transform:translate(0,0);line-height:0}.overlay:focus:after,.overlay:focus:before,.overlay:hover:after,.overlay:hover:before{visibility:visible;opacity:1;filter:alpha(opacity=100)}.overlay:focus:after,.overlay:hover:after{-ms-transform:translate(0,50%);transform:translate(0,50%)}.navbar li>a.home:before{display:inline-block;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f015";color:#c9c9c9;font-size:26px;line-height:0;margin-right:.5em;position:relative;top:3px}#product-details .product-promo .sale-saving:before,.navbar li.cart-not-empty>a.cart:before,.navbar li>a.login:before{display:inline-block;text-rendering:auto;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0)}.navbar li>a.login:before{-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f007";color:#f49a17;font-size:19px;line-height:0;margin-right:.5em}.navbar li>a.cart:focus>.badge,.navbar li>a.cart:hover>.badge{background-color:#fff;color:#f49a17}.navbar li.cart-not-empty>a.cart{background-color:#f49a17;color:#fff}.navbar li.cart-not-empty>a.cart>.badge{background-color:#fff;color:#f49a17}.navbar li.cart-not-empty>a.cart:focus,.navbar li.cart-not-empty>a.cart:hover{background-color:#f49a17;color:#fff}.navbar li.cart-not-empty>a.cart:before{-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f07a";color:#fff;font-size:24px;line-height:0;margin-right:.4em}@media (min-width:992px){.navbar .navbar-nav .list-subnav>li+li{border-top:1px solid #e28a0b}.navbar .navbar-nav .list-subnav>li>a{font-weight:100}}.navbar .navbar-nav>li>a:focus:before,.navbar .navbar-nav>li>a:hover:before{color:#fff}.navbar .navbar-nav>.active>a:focus,.navbar .navbar-nav>.active>a:hover{background-color:#f49a17;color:#fff}.navbar .navbar-nav>.active:after{background:#f49a17;content:"";display:block;position:absolute;bottom:0;width:100%;height:2px;z-index:100}.navbar .navbar-nav>.open>a,.navbar .navbar-nav>.open>a:focus,.navbar .navbar-nav>.open>a:hover{background-color:#f49a17;color:#fff}.navbar .navbar-nav>.open>a:before,.navbar .navbar-nav>.open>a:focus:before,.navbar .navbar-nav>.open>a:hover:before{color:#fff}.container>.navbar-collapse{margin-left:-15px;margin-right:-15px}header .header .logo{float:none}.page-home #carousel .carousel-control{background-image:none}.products-heading h2{color:#7a7a7a;font-size:18px;font-weight:700}.products-heading .btn-all,.products-heading .btn-all:focus,.products-heading .btn-all:hover{color:#7a7a7a;font-size:16px;font-style:italic;font-weight:600}.products-heading .short-description{background-color:#f5f5f5;margin-bottom:10px;padding:10px}.product-options dl{font-size:.85em;margin-bottom:10px}.product-options dl>dt{text-align:left}.product-info .name,td.product .name{font-size:16px;font-weight:600}.product-info .name>a,td.product .name>a{color:#7a7a7a;text-decoration:none}.product-info .name>a:focus,.product-info .name>a:hover,td.product .name>a:focus,td.product .name>a:hover{color:#b66f09}.product-price .price-label{font:0/0 a;background-color:transparent;display:block}.product-price .regular-price .price,.product-price .special-price .price{display:block;font-size:14px;line-height:25px;font-style:normal;font-weight:400}.product-price .old-price .price{display:block;font-size:14px;line-height:25px;font-style:italic;font-weight:400;text-decoration:line-through}#products-new .products-grid .overlay:after{-ms-transform:translate(0,40%);transform:translate(0,40%)}#products-new .products-grid .item>article{border-bottom:4px solid #f49a17;border-bottom-right-radius:3px;border-bottom-left-radius:3px;overflow:hidden;position:relative}#products-new .products-grid .item>article .product-info{background-color:#f6af48;color:#fff;display:block;padding:6px 12px;position:relative;text-decoration:none!important}#products-new .products-grid .item>article .product-info:focus,#products-new .products-grid .item>article .product-info:hover{background-color:#f49a17}#products-new .products-grid .item>article .product-info .name{min-height:40px;height:auto!important;height:40px}#products-new .products-grid .item>article .product-info .name:after{content:'+';font-size:45px;line-height:0;font-style:normal;font-weight:100;position:absolute;top:16px;right:4px;-webkit-font-smoothing:antialiased}#products-new .products-grid .item>article .product-info .short-description{font-size:11px;line-height:1.1}#products-new .products-grid .item>article .product-price .price{color:#fff;font-size:22px;font-weight:700}@media (min-width:992px){#products-new .products-grid .item>article .product-image{padding-bottom:40px}#products-new .products-grid .item>article .product-info{transition:height .3s linear;position:absolute;bottom:0;width:100%;height:50px}#products-new .products-grid .item>article .product-info h3{margin-top:2px;padding-right:20px}#products-new .products-grid .item>article .product-info h3 span{height:2em;overflow:hidden;display:block}#products-new .products-grid .item>article .product-info:focus,#products-new .products-grid .item>article .product-info:hover{cursor:pointer;height:140px}}#products-upsell{margin-top:40px;position:relative}#products-upsell .products-heading{border-bottom:1px solid #e5e5e5;margin:20px 0}#products-upsell .products-heading h3{background:#fff;color:#f49a17;padding-right:15px;position:absolute;top:-24px}#products-offer .products-grid .item>article,#products-related .products-grid .item>article,#products-upsell .products-grid .item>article{border-radius:3px;transition:background-color .3s ease-in-out;padding:6px}#delivery-address.panel .panel-body,#delivery-method.panel .panel-body,#products-offer .products-grid .item>article .product-info,#products-related .products-grid .item>article .product-info,#products-upsell .products-grid .item>article .product-info{padding:0}#products-offer .products-grid .item>article .product-info .short-description,#products-related .products-grid .item>article .product-info .short-description,#products-upsell .products-grid .item>article .product-info .short-description{font-size:11px}@media (min-width:768px){#products-offer .products-grid .item:hover article,#products-related .products-grid .item:hover article,#products-upsell .products-grid .item:hover article{background-color:#f6f6f6}}#products-new .overlay:after,#products-offer .overlay:after,#products-upsell .overlay:after{content:'+';font-size:80px;font-weight:100;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#products-new .overlay:before{border-radius:3px 3px 0 0}#category-products .item>article .product-info .description{font-size:.83em;line-height:1.3}#category-products .item>article .product-price .price-label{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:block}#category-products .item>article .product-price .price-container{margin-bottom:10px}#category-products .item>article .product-price .price-container .price{margin-left:4px}#category-products .item>article .product-price .product-btn{min-height:26px}.grid #category-products .item{border-right:1px solid #e8e8e8;margin:0;padding:10px}.grid #category-products .item>article .product-info{padding:3px}.grid #category-products .item>article .product-info .name{margin:4px;height:2em;overflow:hidden}.grid #category-products .item>article .product-info .description{margin-left:4px}.list #category-products .item>article .product-price .price-container{margin-bottom:20px}.list #category-products .item>article .product-price .price-container .old-price,.list #category-products .item>article .product-price .price-container .regular-price,.list #category-products .item>article .product-price .price-container .special-price{display:block;width:100%}#product-details .product-info{border-bottom:1px solid #e5e5e5;margin-bottom:15px}#product-details .product-info .sku{color:#e5e5e5;display:block;font-size:14px;margin-top:-8px;margin-bottom:20px}#product-details .product-info .pse-name{color:#555;font-size:14px}#product-details .product-options .option{margin-bottom:10px}#product-details .product-cart{background-color:#f5f5f5!important;margin-bottom:20px;padding:10px!important}#product-details .product-promo{background-color:#f5f5f5;margin-bottom:15px;padding:10px}#product-details .product-promo .sale-label{font-weight:300;line-height:1.4;font-size:21px}#product-details .product-promo .sale-saving{color:#f49a17}#product-details .product-promo .sale-saving:before{font:normal normal normal 14px/1 FontAwesome;font-size:inherit;-webkit-font-smoothing:antialiased;transform:translate(0,0);content:"\f005"}#product-details .product-promo .sale-period{font-style:italic;font-size:90%}#product-thumbnails .carousel-control{width:17px!important}#product-thumbnails .carousel-control .fa{position:absolute;top:50%}#product-thumbnails .carousel-control.left{border-right:7px solid #ccc;color:#ccc;text-align:left}#product-thumbnails .carousel-control.left>.fa-caret-left{left:0;margin-left:0;margin-top:-15px}#product-thumbnails .carousel-control.left>.fa-caret-left:before{color:inherit}#product-thumbnails .carousel-control.right{border-left:7px solid #ccc;text-align:right}#product-thumbnails .carousel-control.right>.fa-caret-right{left:auto;right:0;margin-left:0;margin-top:-15px}@media (min-width:768px){#product #product-gallery{border-right:1px solid #eee;padding-right:20px}#product #product-details .group-qty .form-control{display:inline-block;margin-right:1em;margin-left:.4em;width:100px}}#product-gallery .product-image{margin-bottom:20px}#product-gallery .product-thumbnails li{width:20%}#filters{background:#f5f5f5}#filters>h3{background:#e5e5e5;box-shadow:inset 0 -4px 10px rgba(0,0,0,.125);margin:0 0 15px;padding:10px 15px;font-size:18px;font-weight:700}#filters>h3>span{display:block;font-size:.75em;font-weight:100;text-transform:lowercase}#filters>h3:before,.block.block-newsletter .block-content form .form-group:before{font:normal normal normal 14px/1 FontAwesome;-moz-osx-font-smoothing:grayscale;text-rendering:auto}#filters>h3:before{display:inline-block;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);font-size:30px;float:left;margin-right:.5em}#filters .filter{margin-bottom:10px}.block.block-links .block-content ul>li+li a{border-top:none}.block.block-links .block-content ul>li+li:before{background:#fff;content:"";display:block;margin:0 auto;text-align:center;width:65%;height:2px}.block.block-newsletter .block-content form .form-group{position:relative}@media (min-width:1200px){.block.block-newsletter .block-content form .form-group{width:176px}}.block.block-newsletter .block-content form .form-group .form-control{background-color:#e6e6e6;font-size:12px;padding-left:35px;width:inherit;box-shadow:inset 1px 1px 1px rgba(0,0,0,.075)}.block.block-newsletter .block-content form .form-group .form-control::-moz-placeholder{color:#888;opacity:1}.block.block-newsletter .block-content form .form-group .form-control:-ms-input-placeholder{color:#888}.block.block-newsletter .block-content form .form-group .form-control::-webkit-input-placeholder{color:#888}.block.block-newsletter .block-content form .form-group .form-control:focus::-moz-placeholder{color:#c8c8c8;opacity:1}.block.block-newsletter .block-content form .form-group .form-control:focus:-ms-input-placeholder{color:#c8c8c8}.block.block-newsletter .block-content form .form-group .form-control:focus::-webkit-input-placeholder{color:#c8c8c8}.block.block-newsletter .block-content form .form-group:before{display:inline-block;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f0e0";color:#8b8b8b;font-size:18px;position:absolute;top:8px;left:9px}.block.block-newsletter .block-content form .btn-subscribe{padding:6px}.block.block-social .block-content ul>li>a:hover.facebook{color:#3d5fa6}.block.block-social .block-content ul>li>a:hover.twitter{color:#53b1f0}.block.block-social .block-content ul>li>a:hover.rss{color:#fac200}.block.block-social .block-content ul>li>a:hover.instagram{color:#425E75}.block.block-social .block-content ul>li>a:hover.google-plus{color:#fac200}.block.block-social .block-content ul>li>a:hover.youtube{color:#e82a20}.block.block-contact .block-content ul>li{clear:both;margin-bottom:5px}.block.block-contact .block-content ul>li.contact-address:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f041";font-size:34px}.block.block-contact .block-content ul>li.contact-phone:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f10b";font-size:30px;margin-top:-8px;margin-left:3px}.block.block-contact .block-content ul>li.contact-email:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f0e0";font-size:17px;margin-left:2px}.block.block-contact .block-content ul>li:before{color:#f49a17;float:left;line-height:1;margin-right:.4em}.block.block-contact .block-content ul>li.contact-contact:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f1d8";font-size:17px}#categories.block-nav .block-content{border-top:1px solid #aeaeae}#categories.block-nav .block-content .amount{font-weight:700}#categories.block-nav .block-content li{border-top:1px solid #eee;position:relative}#categories.block-nav .block-content li .accordion-toggle{position:absolute;top:0;right:0;padding-right:10px;padding-left:5px}#categories.block-nav .block-content li .accordion-toggle:focus,#categories.block-nav .block-content li .accordion-toggle:hover{background:0 0}#categories.block-nav .block-content li .accordion-toggle:focus:after,#categories.block-nav .block-content li .accordion-toggle:hover:after{border-color:#b66f09;color:#b66f09}#categories.block-nav .block-content li .accordion-toggle:after{border:1px solid #f49a17;border-radius:10px;line-height:17px;text-align:center;width:19px;height:19px}.toolbar.toolbar-top{margin-top:-20px;border-bottom:1px solid #eee}.toolbar.toolbar-bottom .sorter-container,.toolbar.toolbar-top .pagination-container{display:none}.toolbar .amount{color:#f49a17;font-size:22px;font-weight:400}.toolbar .view-mode>.view-mode-btn a{background-color:#fff;border:0!important;color:#7a7a7a}.toolbar .view-mode>.view-mode-btn a:focus,.toolbar .view-mode>.view-mode-btn a:hover{background-color:#efefef;color:#474747}.toolbar .view-mode>.view-mode-btn a:active{color:#fff}.pagination>li>a,.pagination>li>span{box-shadow:2px 1px 1px rgba(0,0,0,.1);transition:all .2s ease-in-out;background-image:linear-gradient(to bottom,#fff 0,#f9f9f9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff9f9f9', GradientType=0);color:#7a7a7a;font-weight:700}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{background:0 0}.pagination>li>a:focus:active,.pagination>li>a:hover:active,.pagination>li>span:focus:active,.pagination>li>span:hover:active{background-color:#f49a17;border-color:#f49a17;color:#fff}.pagination>li:first-child>a,.pagination>li:first-child>span{border-bottom-left-radius:30px;border-top-left-radius:30px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:30px;border-top-right-radius:30px}.pagination>.active>a,.pagination>.active>span{background-image:none}#form-forgotpassword .group-email label,#form-forgotpassword legend,#form-login .group-email label,#form-login legend{font-size:16px;font-weight:600}#form-forgotpassword .radio-account1,#form-login .radio-account1{margin-top:10px}#form-forgotpassword .forgot-password,#form-login .forgot-password{color:#7a7a7a;font-size:12px;font-style:italic}@media (min-width:768px){#form-forgotpassword .radio-account1,#form-login .radio-account1{float:left}#form-forgotpassword .group-password,#form-login .group-password{float:right;margin-top:5px;width:50%}}#delivery-method.panel .radio{display:block;margin-top:0}#delivery-method.panel .radio+.radio{border-top:1px solid #f5f5f5}#delivery-method.panel .price{text-align:right}#delivery-method.panel .image{text-align:center}#account .panel-title,#payment-success.panel .panel-heading{text-align:left}.js #payment-method .radio{padding-left:0;position:relative}.js #payment-method .radio .active:after{font:normal normal normal 14px/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f077";color:#f49a17;display:block;font-size:1.5em;line-height:0;position:absolute;bottom:-8px;left:40%}#account .panel-title>a:before,#account-info .list-info .email:before,#account-info .list-info .mobile:before,#account-info .list-info .tel:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;-moz-osx-font-smoothing:grayscale}#payment-success.panel .panel-body{padding:20px 40px}#payment-success.panel .panel-body>h3{color:#f49a17}#account .panel{border-color:#fff}#account .panel-title>a:before{font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f078";float:left;width:20px}#account .panel-title>a.collapsed:before{content:"\f054"}#account-info .fn{font-size:16px;font-weight:600}#account-info .list-info .email:before,#account-info .list-info .mobile:before,#account-info .list-info .tel:before{color:#f49a17;line-height:1;margin-right:.4em;vertical-align:middle}#account-info .list-info .mobile:before{text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f10b";font-size:30px}#account-info .list-info .tel:before{text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f095";font-size:22px}#account-info .list-info .email:before{text-rendering:auto;-webkit-font-smoothing:antialiased;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f0e0";font-size:18px}#account-info .group-btn a{color:#7a7a7a;margin-bottom:4px;padding:0}#account-info .group-btn a>i{color:#f49a17;font-size:20px;line-height:1;margin-right:.3em;vertical-align:middle}#account-info .group-btn a:focus,#account-info .group-btn a:hover{color:#b66f09}#account-address .panel-body{padding-left:0;padding-right:0;padding-top:10px}#account-address .table-address{border:1px solid #f5f5f5;margin-bottom:0}#account-orders .panel-body{padding-left:0;padding-right:0}#account-orders .table-orders tbody>tr>td,#account-orders .table-orders tbody>tr>th,#account-orders .table-orders thead>tr>td,#account-orders .table-orders thead>tr>th{padding:14px;text-align:center}#account-orders .table-orders thead>tr>th{background-color:#f5f5f5;border-bottom-width:1px}#account-orders .table-order-products tbody>tr>td,#account-orders .table-order-products tbody>tr>th,#account-orders .table-order-products thead>tr>td,#account-orders .table-order-products thead>tr>th{padding:5px;text-align:center}.table-cart-mini tbody>tr>td,.table-cart-mini tbody>tr>th,.table-cart-mini tfoot>tr>td,.table-cart-mini tfoot>tr>th,.table-cart-mini thead>tr>td,.table-cart-mini thead>tr>th{vertical-align:middle}#google-map{border:none;display:block;margin-bottom:20px;width:100%;height:350px;-moz-filter:grayscale(100%);-ms-filter:grayscale(100%);-o-filter:grayscale(100%);filter:grayscale(100%)}#sale-details .sale-discount-information{background-color:#f5f5f5;margin-bottom:10px;padding:10px}#sale-details .sale-discount-information .sale-saving{font-size:120%;color:#f49a17}#sale-details .sale-discount-information .sale-saving:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-transform:translate(0,0);transform:translate(0,0);content:"\f005"}#sale-details .sale-discount-information .sale-period{font-style:italic;font-size:90%}#sale-details .sale-information{margin-bottom:30px}#sale-details .sale-information .chapo,#sale-details .sale-information .description{margin-bottom:10px} \ No newline at end of file diff --git a/domokits/templates/frontOffice/custom/assets/src/css/custom.css b/domokits/templates/frontOffice/custom/assets/src/css/custom.css new file mode 100644 index 0000000..72e83e9 --- /dev/null +++ b/domokits/templates/frontOffice/custom/assets/src/css/custom.css @@ -0,0 +1,11 @@ +div.container { + width: 90% !important; +} + +.container { + width: 95% +} + +header .header .logo { + background-color: #EC8C39; +} diff --git a/domokits/templates/frontOffice/custom/assets/src/css/thelia.css b/domokits/templates/frontOffice/custom/assets/src/css/thelia.css index 6bfb3b7..7c46b4c 100644 --- a/domokits/templates/frontOffice/custom/assets/src/css/thelia.css +++ b/domokits/templates/frontOffice/custom/assets/src/css/thelia.css @@ -2989,7 +2989,6 @@ select[multiple].input-lg { line-height: 1.42857143; border-radius: 3px; -webkit-user-select: none; - -moz-user-select: none; -ms-user-select: none; user-select: none; } @@ -5052,14 +5051,6 @@ a.thumbnail.active { .alert-danger .alert-link { color: #843534; } -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} @keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5095,7 +5086,6 @@ a.thumbnail.active { } .progress.active .progress-bar, .progress-bar.active { - -webkit-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-bar-success { @@ -5806,14 +5796,11 @@ button.close { outline: 0; } .modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); -ms-transform: translate(0, -25%); transform: translate(0, -25%); - transition: -webkit-transform 0.3s ease-out; transition: transform 0.3s ease-out; } .modal.in .modal-dialog { - -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); transform: translate(0, 0); } @@ -6170,29 +6157,23 @@ button.close { } @media all and (transform-3d), (-webkit-transform-3d) { .carousel-inner > .item { - transition: -webkit-transform 0.6s ease-in-out; transition: transform 0.6s ease-in-out; - -webkit-backface-visibility: hidden; backface-visibility: hidden; - -webkit-perspective: 1000px; perspective: 1000px; } .carousel-inner > .item.next, .carousel-inner > .item.active.right { - -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); left: 0; } .carousel-inner > .item.prev, .carousel-inner > .item.active.left { - -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); left: 0; } .carousel-inner > .item.next.left, .carousel-inner > .item.prev.right, .carousel-inner > .item.active { - -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); left: 0; } @@ -6684,9 +6665,8 @@ button.close { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); } /* makes the font 33% larger relative to the icon container */ .fa-lg { @@ -6746,60 +6726,41 @@ button.close { margin-left: .3em; } .fa-spin { - -webkit-animation: fa-spin 2s infinite linear; animation: fa-spin 2s infinite linear; } .fa-pulse { - -webkit-animation: fa-spin 1s infinite steps(8); animation: fa-spin 1s infinite steps(8); } -@-webkit-keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} @keyframes fa-spin { 0% { - -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { - -webkit-transform: rotate(359deg); transform: rotate(359deg); } } .fa-rotate-90 { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); - -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); } .fa-rotate-180 { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); - -webkit-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg); } .fa-rotate-270 { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); - -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); } .fa-flip-horizontal { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); - -webkit-transform: scale(-1, 1); -ms-transform: scale(-1, 1); transform: scale(-1, 1); } .fa-flip-vertical { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); - -webkit-transform: scale(1, -1); -ms-transform: scale(1, -1); transform: scale(1, -1); } @@ -6808,8 +6769,7 @@ button.close { :root .fa-rotate-270, :root .fa-flip-horizontal, :root .fa-flip-vertical { - -webkit-filter: none; - filter: none; + filter: none; } .fa-stack { position: relative; @@ -8595,9 +8555,8 @@ header .header .language-container .currency-switch .select { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f078"; } .navbar .navbar-cart .dropdown > a:after, @@ -8957,9 +8916,8 @@ header .header .language-container .currency-switch .select { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f071"; display: block; font-size: 2.2em; @@ -9087,9 +9045,8 @@ a { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f105"; } .btn { @@ -9320,9 +9277,8 @@ a { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f078"; } .panel-heading { @@ -9498,9 +9454,8 @@ a { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f071"; display: block; font-size: 2.2em; @@ -9558,9 +9513,8 @@ a { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f054"; color: #f49a17; margin-left: -15px; @@ -9613,9 +9567,8 @@ a { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f068"; } .block-nav .block-content li a.accordion-toggle.collapsed:after { @@ -9998,9 +9951,8 @@ a.label-delivered:focus { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f00d"; margin-right: .3em; } @@ -10048,7 +10000,6 @@ label { content: "\f002"; color: #fff; text-align: center; - -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); transform: translate(0, 0); line-height: 0; @@ -10063,7 +10014,6 @@ label { } .overlay:hover:after, .overlay:focus:after { - -webkit-transform: translate(0, 50%); -ms-transform: translate(0, 50%); transform: translate(0, 50%); } @@ -10074,9 +10024,8 @@ label { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f015"; color: #c9c9c9; font-size: 26px; @@ -10092,9 +10041,8 @@ label { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f007"; color: #f49a17; font-size: 19px; @@ -10126,9 +10074,8 @@ label { text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f07a"; color: #fff; font-size: 24px; @@ -10249,7 +10196,6 @@ td.product .name > a:focus, text-decoration: line-through; } #products-new .products-grid .overlay:after { - -webkit-transform: translate(0, 40%); -ms-transform: translate(0, 40%); transform: translate(0, 40%); } @@ -10465,9 +10411,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f005"; } #product-details .product-promo .sale-period { @@ -10547,9 +10492,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f002"; font-size: 30px; float: left; @@ -10617,9 +10561,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f0e0"; color: #8b8b8b; font-size: 18px; @@ -10659,9 +10602,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f041"; font-size: 34px; } @@ -10672,9 +10614,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f10b"; font-size: 30px; margin-top: -8px; @@ -10687,9 +10628,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f0e0"; font-size: 17px; margin-left: 2px; @@ -10707,9 +10647,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f1d8"; font-size: 17px; } @@ -10875,9 +10814,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f077"; color: #f49a17; display: block; @@ -10913,9 +10851,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f078"; float: left; width: 20px; @@ -10942,9 +10879,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f10b"; font-size: 30px; } @@ -10955,9 +10891,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f095"; font-size: 22px; } @@ -10968,9 +10903,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f0e0"; font-size: 18px; } @@ -11035,7 +10969,6 @@ td.product .name > a:focus, margin-bottom: 20px; width: 100%; height: 350px; - -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); @@ -11057,9 +10990,8 @@ td.product .name > a:focus, text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); content: "\f005"; } #sale-details .sale-discount-information .sale-period { diff --git a/domokits/templates/frontOffice/custom/category.html b/domokits/templates/frontOffice/custom/category.html index 1872542..5a8c4a6 100644 --- a/domokits/templates/frontOffice/custom/category.html +++ b/domokits/templates/frontOffice/custom/category.html @@ -56,7 +56,8 @@ {hook name="category.main-top" category="$category_id"} -
+ +
{hook name="category.content-top" category="$category_id"} @@ -125,9 +126,11 @@ {hook name="category.content-bottom" category="$category_id"}
+ {hook name="category.main-bottom" category="$category_id"} diff --git a/domokits/templates/frontOffice/custom/layout.tpl b/domokits/templates/frontOffice/custom/layout.tpl index 2be3627..c6a3473 100644 --- a/domokits/templates/frontOffice/custom/layout.tpl +++ b/domokits/templates/frontOffice/custom/layout.tpl @@ -20,7 +20,7 @@ GNU General Public License : http://www.gnu.org/licenses/ {* Declare assets directory, relative to template base directory *} {declare_assets directory='assets/dist'} {* Set the default translation domain, that will be used by {intl} when the 'd' parameter is not set *} -{default_translation_domain domain='fo.default'} +{default_translation_domain domain='fo.custom'} {* -- Define some stuff for Smarty ------------------------------------------ *} {config_load file='variables.conf'} @@ -73,6 +73,9 @@ GNU General Public License : http://www.gnu.org/licenses/ {stylesheets file='assets/dist/css/thelia.min.css'} {/stylesheets} + {stylesheets file='assets/dist/css/custom.min.css'} + + {/stylesheets} {* If you want to generate the CSS assets on the fly, just replace the stylesheet inclusion above by the following. Then, in your back-office, go to Configuration -> System Variables and set process_assets to 1.