Repository: Nikoms/clean-architecture-example Branch: master Commit: e04845939a38 Files: 268 Total size: 859.4 KB Directory structure: gitextract_n2l1_zf6/ ├── .gitignore ├── bin/ │ ├── console │ └── phpunit ├── composer.json ├── config/ │ ├── bootstrap.php │ ├── bundles.php │ ├── packages/ │ │ ├── assets.yaml │ │ ├── dev/ │ │ │ ├── debug.yaml │ │ │ ├── monolog.yaml │ │ │ ├── routing.yaml │ │ │ ├── security_checker.yaml │ │ │ ├── swiftmailer.yaml │ │ │ └── web_profiler.yaml │ │ ├── doctrine.yaml │ │ ├── doctrine_migrations.yaml │ │ ├── easy_admin.yaml │ │ ├── fos_ck_editor.yaml │ │ ├── framework.yaml │ │ ├── html_sanitizer.yaml │ │ ├── prod/ │ │ │ ├── doctrine.yaml │ │ │ ├── monolog.yaml │ │ │ └── webpack_encore.yaml │ │ ├── routing.yaml │ │ ├── security.yaml │ │ ├── security_checker.yaml │ │ ├── sensio_framework_extra.yaml │ │ ├── sentry.yml │ │ ├── swiftmailer.yaml │ │ ├── test/ │ │ │ ├── dama_doctrine_test_bundle.yaml │ │ │ ├── framework.yaml │ │ │ ├── monolog.yaml │ │ │ ├── routing.yaml │ │ │ ├── security.yaml │ │ │ ├── swiftmailer.yaml │ │ │ └── web_profiler.yaml │ │ ├── translation.yaml │ │ ├── twig.yaml │ │ ├── twig_extensions.yaml │ │ ├── validator.yaml │ │ ├── vich_uploader.yaml │ │ └── webpack_encore.yaml │ ├── routes/ │ │ ├── annotations.yaml │ │ ├── dev/ │ │ │ ├── twig.yaml │ │ │ └── web_profiler.yaml │ │ └── easy_admin.yaml │ └── services.yaml ├── package.json ├── phpunit.xml.dist ├── public/ │ ├── .htaccess │ ├── build/ │ │ ├── app.css │ │ ├── app.js │ │ ├── entrypoints.json │ │ ├── manifest.json │ │ └── runtime.js │ ├── css/ │ │ ├── materialize.css │ │ ├── seat-base.css │ │ └── seat.css │ ├── ico/ │ │ ├── browserconfig.xml │ │ └── manifest.json │ ├── index.php │ └── js/ │ └── materialize.js ├── resources/ │ ├── assets/ │ │ ├── css/ │ │ │ └── app.css │ │ └── js/ │ │ └── app.js │ ├── templates/ │ │ ├── admin/ │ │ │ └── command/ │ │ │ └── list.twig │ │ ├── base_resto.html.twig │ │ ├── bundles/ │ │ │ └── EasyAdminBundle/ │ │ │ └── default/ │ │ │ └── layout.html.twig │ │ ├── component/ │ │ │ └── download.html.twig │ │ ├── default/ │ │ │ └── registration_complete.html.twig │ │ ├── form/ │ │ │ ├── field-new.html.twig │ │ │ └── field.html.twig │ │ ├── order/ │ │ │ ├── confirm-basket.html.twig │ │ │ ├── go-to-confirm-basket.html.twig │ │ │ ├── summary.html.twig │ │ │ └── the-menu.html.twig │ │ └── page/ │ │ ├── basket.html.twig │ │ ├── business-lunch.html.twig │ │ ├── contact.html.twig │ │ ├── home.html.twig │ │ ├── login.html.twig │ │ ├── menu-salle.html.twig │ │ ├── order-done.html.twig │ │ ├── register-complete.html.twig │ │ ├── register.html.twig │ │ ├── take-away.html.twig │ │ └── update-client.html.twig │ └── translations/ │ ├── EasyAdminBundle.fr.xlf │ └── messages.fr.yaml ├── src/ │ └── Seat/ │ ├── Domain/ │ │ ├── Basket/ │ │ │ ├── Entity/ │ │ │ │ ├── Basket.php │ │ │ │ └── BasketRepository.php │ │ │ ├── Model/ │ │ │ │ ├── BasketProduct.php │ │ │ │ ├── BasketProductOption.php │ │ │ │ ├── BasketProductSupplement.php │ │ │ │ ├── OrderType.php │ │ │ │ ├── OrderTypeName.php │ │ │ │ └── PossibleOrderType.php │ │ │ ├── Service/ │ │ │ │ ├── Error/ │ │ │ │ │ ├── DeliveryNotAvailable.php │ │ │ │ │ ├── OrderTooLate.php │ │ │ │ │ ├── TakeAwayNotAvailable.php │ │ │ │ │ └── TakeAwayTooLate.php │ │ │ │ └── OrderTypeChecker.php │ │ │ └── UseCase/ │ │ │ ├── AddProductToBasket/ │ │ │ │ ├── AddProductToBasket.php │ │ │ │ ├── AddProductToBasketPresenter.php │ │ │ │ ├── AddProductToBasketRequest.php │ │ │ │ └── AddProductToBasketResponse.php │ │ │ ├── RemoveFromBasket/ │ │ │ │ ├── RemoveFromBasket.php │ │ │ │ ├── RemoveFromBasketPresenter.php │ │ │ │ ├── RemoveFromBasketRequest.php │ │ │ │ └── RemoveFromBasketResponse.php │ │ │ └── ShowBasket/ │ │ │ ├── ShowBasket.php │ │ │ ├── ShowBasketPresenter.php │ │ │ ├── ShowBasketRequest.php │ │ │ └── ShowBasketResponse.php │ │ ├── Client/ │ │ │ ├── Entity/ │ │ │ │ ├── Client.php │ │ │ │ ├── ClientRepository.php │ │ │ │ ├── Company.php │ │ │ │ ├── CompanyRepository.php │ │ │ │ ├── Role.php │ │ │ │ └── Store.php │ │ │ └── UseCase/ │ │ │ ├── GetClient/ │ │ │ │ ├── GetClient.php │ │ │ │ ├── GetClientPresenter.php │ │ │ │ ├── GetClientRequest.php │ │ │ │ └── GetClientResponse.php │ │ │ ├── Login/ │ │ │ │ ├── Login.php │ │ │ │ ├── LoginPresenter.php │ │ │ │ ├── LoginRequest.php │ │ │ │ └── LoginResponse.php │ │ │ ├── Register/ │ │ │ │ ├── Register.php │ │ │ │ ├── RegisterPresenter.php │ │ │ │ ├── RegisterRequest.php │ │ │ │ └── RegisterResponse.php │ │ │ └── UpdateClient/ │ │ │ ├── UpdateClient.php │ │ │ ├── UpdateClientPresenter.php │ │ │ ├── UpdateClientRequest.php │ │ │ └── UpdateClientResponse.php │ │ ├── Cms/ │ │ │ └── Entity/ │ │ │ ├── HtmlContent.php │ │ │ └── HtmlContentRepository.php │ │ ├── Menu/ │ │ │ ├── Entity/ │ │ │ │ ├── Category.php │ │ │ │ ├── CategoryRepository.php │ │ │ │ ├── Product.php │ │ │ │ ├── ProductOption.php │ │ │ │ ├── ProductOptionRepository.php │ │ │ │ ├── ProductRepository.php │ │ │ │ ├── ProductSupplement.php │ │ │ │ └── ProductSupplementRepository.php │ │ │ ├── Model/ │ │ │ │ ├── MenuLine.php │ │ │ │ ├── MenuOption.php │ │ │ │ ├── MenuProduct.php │ │ │ │ └── MenuSupplement.php │ │ │ └── UseCase/ │ │ │ └── GetMenu/ │ │ │ ├── GetMenu.php │ │ │ ├── GetMenuPresenter.php │ │ │ └── GetMenuResponse.php │ │ └── Order/ │ │ ├── Entity/ │ │ │ ├── Command.php │ │ │ └── CommandRepository.php │ │ └── UseCase/ │ │ └── ConfirmBasket/ │ │ ├── ConfirmBasket.php │ │ ├── ConfirmBasketPresenter.php │ │ ├── ConfirmBasketRequest.php │ │ └── ConfirmBasketResponse.php │ ├── Infrastructure/ │ │ └── Symfony4/ │ │ ├── Controller/ │ │ │ ├── AddToBasketController.php │ │ │ ├── AdminController.php │ │ │ ├── BusinessLunchController.php │ │ │ ├── ContactController.php │ │ │ ├── HomeController.php │ │ │ ├── LoginCheckController.php │ │ │ ├── LoginController.php │ │ │ ├── LogoutController.php │ │ │ ├── MenuSalleController.php │ │ │ ├── RegisterCompleteController.php │ │ │ ├── RegisterController.php │ │ │ ├── RemoveFromBasketController.php │ │ │ ├── ShowBasketController.php │ │ │ ├── ShowOrderMenuController.php │ │ │ └── UpdateClientController.php │ │ ├── DependencyInjection/ │ │ │ └── Compiler/ │ │ │ ├── AdminFilterRolePass.php │ │ │ └── AutowireSeatPass.php │ │ ├── Doctrine/ │ │ │ ├── Basket.php │ │ │ ├── BasketProductJson.php │ │ │ ├── Category.php │ │ │ ├── CategoryOption.php │ │ │ ├── CategorySupplement.php │ │ │ ├── Command.php │ │ │ ├── Company.php │ │ │ ├── DoctrineBasketRepository.php │ │ │ ├── DoctrineCategoryRepository.php │ │ │ ├── DoctrineClientRepository.php │ │ │ ├── DoctrineCommandRepository.php │ │ │ ├── DoctrineCompanyRepository.php │ │ │ ├── DoctrineHtmlContentRepository.php │ │ │ ├── DoctrineProductOptionRepository.php │ │ │ ├── DoctrineProductRepository.php │ │ │ ├── DoctrineProductSupplementRepository.php │ │ │ ├── HtmlContent.php │ │ │ ├── Pdf.php │ │ │ ├── Product.php │ │ │ ├── Tournee.php │ │ │ └── User.php │ │ ├── Form/ │ │ │ ├── BasketConfirmationType.php │ │ │ ├── BasketType.php │ │ │ ├── FormHelper.php │ │ │ ├── RegisterType.php │ │ │ └── UpdateClientType.php │ │ ├── Kernel.php │ │ ├── ParamConverter/ │ │ │ ├── FormToNullableRequestConverter.php │ │ │ └── FormToRequestConverter.php │ │ ├── Security/ │ │ │ ├── Service/ │ │ │ │ ├── ClientUserProvider.php │ │ │ │ └── FormAuthenticator.php │ │ │ └── User.php │ │ ├── Twig/ │ │ │ ├── ContentExtension.php │ │ │ └── DownloadExtension.php │ │ └── View/ │ │ ├── AddProductToBasketView.php │ │ ├── ConfirmBasketView.php │ │ ├── GetMenuView.php │ │ ├── RegisterView.php │ │ ├── RemoveFromBasketView.php │ │ ├── ShowBasketView.php │ │ └── UpdateClientView.php │ ├── Presentation/ │ │ ├── Basket/ │ │ │ ├── AddProductToBasketHtmlPresenter.php │ │ │ ├── AddProductToBasketHtmlViewModel.php │ │ │ ├── Model/ │ │ │ │ └── BasketViewModel.php │ │ │ ├── RemoveFromBasketHtmlPresenter.php │ │ │ ├── RemoveFromBasketHtmlViewModel.php │ │ │ ├── ShowBasketHtmlPresenter.php │ │ │ └── ShowBasketHtmlViewModel.php │ │ ├── Client/ │ │ │ ├── EditableClient.php │ │ │ ├── GetClientHtmlPresenter.php │ │ │ ├── GetClientHtmlViewModel.php │ │ │ ├── RegisterHtmlPresenter.php │ │ │ ├── RegisterHtmlViewModel.php │ │ │ ├── UpdateClientHtmlPresenter.php │ │ │ └── UpdateClientHtmlViewModel.php │ │ ├── Menu/ │ │ │ ├── GetMenuHtmlPresenter.php │ │ │ ├── GetMenuHtmlViewModel.php │ │ │ └── Model/ │ │ │ └── MenuViewModel.php │ │ └── Order/ │ │ ├── ConfirmBasketHtmlPresenter.php │ │ └── ConfirmBasketHtmlViewModel.php │ └── SharedKernel/ │ ├── Error/ │ │ ├── Error.php │ │ └── Notification.php │ ├── Model/ │ │ └── TimeRange.php │ └── Service/ │ ├── Base64PasswordHasher.php │ ├── Clock.php │ ├── IdGenerator.php │ ├── NativePasswordHasher.php │ └── PasswordHasher.php ├── tests/ │ └── unit/ │ └── Seat/ │ ├── Domain/ │ │ ├── Basket/ │ │ │ ├── Entity/ │ │ │ │ └── ProductBuilder.php │ │ │ ├── Service/ │ │ │ │ └── OrderTypeCheckerTest.php │ │ │ └── UseCase/ │ │ │ ├── AddProductToBasket/ │ │ │ │ └── AddProductToBasketTest.php │ │ │ └── RemoveFromBasket/ │ │ │ └── RemoveFromBasketTest.php │ │ ├── Client/ │ │ │ ├── Entity/ │ │ │ │ ├── ClientBuilder.php │ │ │ │ └── CompanyBuilder.php │ │ │ └── UseCase/ │ │ │ ├── GetClient/ │ │ │ │ └── GetClientTest.php │ │ │ ├── Login/ │ │ │ │ └── LoginTest.php │ │ │ ├── Register/ │ │ │ │ ├── RegisterRequestBuilder.php │ │ │ │ └── RegisterTest.php │ │ │ └── UpdateClient/ │ │ │ ├── UpdateClientRequestBuilder.php │ │ │ └── UpdateClientTest.php │ │ ├── Menu/ │ │ │ └── UseCase/ │ │ │ └── GetMenu/ │ │ │ └── GetMenuTest.php │ │ └── Order/ │ │ └── UseCase/ │ │ └── ConfirmBasket/ │ │ ├── ConfirmBasketRequestBuilder.php │ │ └── ConfirmBasketTest.php │ ├── SharedKernel/ │ │ └── Model/ │ │ └── TimeRangeTest.php │ └── _Mock/ │ ├── Domain/ │ │ ├── Basket/ │ │ │ └── Entity/ │ │ │ └── InMemoryBasketRepository.php │ │ ├── Client/ │ │ │ └── Entity/ │ │ │ ├── InMemoryClientRepository.php │ │ │ └── InMemoryCompanyRepository.php │ │ ├── Menu/ │ │ │ └── Entity/ │ │ │ ├── InMemoryCategoryRepository.php │ │ │ ├── InMemoryProductOptionRepository.php │ │ │ ├── InMemoryProductRepository.php │ │ │ └── InMemoryProductSupplementRepository.php │ │ └── Order/ │ │ └── Entity/ │ │ └── InMemoryCommandRepository.php │ └── Seat/ │ └── SharedKernel/ │ └── Service/ │ └── IdGeneratorMock.php └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /var/cache/* !var/log/.gitkeep .idea/* /public/build/fonts/glyphicons-* /public/build/images/glyphicons-* ###> symfony/framework-bundle ### /.env /.env.local /.env.*.local /public/bundles/ /var/ /vendor/ ###< symfony/framework-bundle ### ###> symfony/phpunit-bridge ### .phpunit /phpunit.xml ###< symfony/phpunit-bridge ### ###> symfony/web-server-bundle ### /.web-server-pid ###< symfony/web-server-bundle ### ###> friendsofphp/php-cs-fixer ### /.php_cs /.php_cs.cache ###< friendsofphp/php-cs-fixer ### ###> symfony/webpack-encore-bundle ### /node_modules/ npm-debug.log yarn-error.log ###< symfony/webpack-encore-bundle ### # Our app public/share ================================================ FILE: bin/console ================================================ #!/usr/bin/env php getParameterOption(['--env', '-e'], null, true)) { putenv('APP_ENV='.$_ENV['APP_ENV']); // force loading .env files when --env is defined $_SERVER['APP_ENV'] = null; } if ($input->hasParameterOption('--no-debug', true)) { putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } require dirname(__DIR__).'/config/bootstrap.php'; if ($_SERVER['APP_DEBUG']) { umask(0000); if (class_exists(Debug::class)) { Debug::enable(); } } $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $application = new Application($kernel); $application->run($input); ================================================ FILE: bin/phpunit ================================================ #!/usr/bin/env php =7.2.0", "ext-json": "*", "symfony/symfony": "^4.0", "twig/twig": "^2.7", "doctrine/doctrine-bundle": "^1.6", "doctrine/orm": "^2.5", "doctrine/doctrine-migrations-bundle": "^1.2", "symfony/swiftmailer-bundle": "^3.2", "symfony/monolog-bundle": "^3.3", "twig/extensions": "^1.4", "ramsey/uuid": "^3.8", "beberlei/assert": "^3.2", "symfony/flex": "^1.2", "sensio/framework-extra-bundle": "^5.3", "symfony/webpack-encore-bundle": "^1.5", "easycorp/easyadmin-bundle": "^2.1", "friendsofsymfony/ckeditor-bundle": "^2.0", "vich/uploader-bundle": "^1.9", "oro/doctrine-extensions": "^1.2", "sentry/sentry-symfony": "^2.3", "symfony/twig-bundle": "^4.2" }, "require-dev": { "phpunit/phpunit": "^7.5", "symfony/phpunit-bridge": "*" }, "scripts": { "auto-scripts": { "bin/console cache:clear": "script", "bin/console ckeditor:install --clear=drop": "symfony-cmd", "bin/console assets:install --symlink --relative %PUBLIC_DIR%": "script" }, "post-install-cmd": [ "@auto-scripts" ], "post-update-cmd": [ "@auto-scripts" ] } } ================================================ FILE: config/bootstrap.php ================================================ loadEnv(dirname(__DIR__).'/.env'); } $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $_SERVER['APP_ENV'] ?: $_ENV['APP_ENV'] ?: 'dev'; $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int)$_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; ================================================ FILE: config/bundles.php ================================================ ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true], FOS\CKEditorBundle\FOSCKEditorBundle::class => ['all' => true], Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true], Sentry\SentryBundle\SentryBundle::class => ['all' => true], ]; ================================================ FILE: config/packages/assets.yaml ================================================ framework: assets: json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' ================================================ FILE: config/packages/dev/debug.yaml ================================================ debug: # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. # See the "server:dump" command to start a new server. dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" ================================================ FILE: config/packages/dev/monolog.yaml ================================================ monolog: handlers: main: type: stream path: '%kernel.logs_dir%/%kernel.environment%.log' level: debug channels: ['!event'] # uncomment to get logging in your browser # you may have to allow bigger header sizes in your Web server configuration #firephp: # type: firephp # level: info #chromephp: # type: chromephp # level: info console: type: console process_psr_3_messages: false channels: ['!event', '!doctrine', '!console'] ================================================ FILE: config/packages/dev/routing.yaml ================================================ framework: router: strict_requirements: true ================================================ FILE: config/packages/dev/security_checker.yaml ================================================ #services: # SensioLabs\Security\SecurityChecker: # public: false # # SensioLabs\Security\Command\SecurityCheckerCommand: # arguments: ['@SensioLabs\Security\SecurityChecker'] # tags: # - { name: console.command } ================================================ FILE: config/packages/dev/swiftmailer.yaml ================================================ # See https://symfony.com/doc/current/email/dev_environment.html swiftmailer: # send all emails to a specific address #delivery_addresses: ['me@example.com'] ================================================ FILE: config/packages/dev/web_profiler.yaml ================================================ web_profiler: toolbar: true intercept_redirects: false framework: profiler: { only_exceptions: false } ================================================ FILE: config/packages/doctrine.yaml ================================================ parameters: # Adds a fallback DATABASE_URL if the env var is not set. This allows you # to run cache:warmup even if your environment variables are not available # yet. You should not need to change this value. env(DATABASE_URL): '' doctrine: dbal: url: '%env(resolve:DATABASE_URL)%' orm: auto_generate_proxy_classes: '%kernel.debug%' naming_strategy: doctrine.orm.naming_strategy.underscore auto_mapping: true mappings: App: is_bundle: false type: annotation dir: '%kernel.project_dir%/src/Seat/Infrastructure/Symfony4/Doctrine' prefix: 'Symfony4\Doctrine' dql: string_functions: cast: Oro\ORM\Query\AST\Functions\Cast ================================================ FILE: config/packages/doctrine_migrations.yaml ================================================ doctrine_migrations: dir_name: '%kernel.project_dir%/src/Migrations' # namespace is arbitrary but should be different from App\Migrations # as migrations classes should NOT be autoloaded namespace: DoctrineMigrations ================================================ FILE: config/packages/easy_admin.yaml ================================================ easy_admin: user: name_property_path: 'fullName' site_name: "S'eat" entities: CommandLaHulpe: label: 'Commandes La Hulpe' role: 'ROLE_SANDWICH' disabled_actions: ['new','edit','delete','search'] class: Symfony4\Doctrine\Command templates: list: 'admin/command/list.twig' list: title: "Les commandes du jour à La Hulpe" dql_filter: 'SUBSTRING(CAST(entity.date as string),1,10) = SUBSTRING(CAST(CURRENT_DATE() as string),1,10)' sort: ['date', 'ASC'] sortable: false max_results: 9999999999 fields: - { property: 'date', format: 'H\hi', sortable: false } - orderTypeString - quantity - name - option - supplements - comment - { property: 'comment', type: 'id' } - { property: 'id', fsortable: false } CommandWaterloo: label: 'Commandes Waterloo' role: 'ROLE_SANDWICH' disabled_actions: ['new','edit','delete','search'] class: Symfony4\Doctrine\Command templates: list: 'admin/command/list.twig' list: title: "Les commandes du jour à Waterloo" dql_filter: 'SUBSTRING(CAST(entity.date as string),1,10) = SUBSTRING(CAST(CURRENT_DATE() as string),1,10)' sort: ['date', 'ASC'] max_results: 9999999999 fields: - { property: 'date', format: 'H\hi', sortable: false } - orderTypeString - quantity - name - option - supplements - { property: 'comment', type: 'id' } - { property: 'id', fsortable: false } Category: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\Category list: fields: - 'name' - 'description' - 'order' sort: ['order', 'ASC'] Option: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\CategoryOption list: fields: - 'category' - 'name' - { property: 'price', format: '%01.2f €' } - 'order' sort: ['order', 'ASC'] form: fields: - 'category' - 'name' - { property: 'price', type: 'money', type_options: { currency: 'EUR' } } - 'order' Supplement: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\CategorySupplement list: fields: - 'category' - 'name' - { property: 'price', format: '%01.2f €' } - 'order' sort: ['order', 'ASC'] form: fields: - 'category' - 'name' - { property: 'price', type: 'money', type_options: { currency: 'EUR' } } - 'order' Company: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\Company list: fields: - 'id' - 'name' - 'isEnabled' - 'canBeDelivered' - 'orderDeliveryDeadLine' - 'tournee' - store form: fields: - { type: 'section', label: 'Basic information' } - isEnabled - hasInvoice - name - slug - vat - comment - { property: 'store', type: 'choice', type_options: { choices:{'La hulpe':'la-hulpe','Waterloo':'waterloo'} } } - { type: 'section', label: 'Contact information' } - streetNumber - street - zipCode - city - phoneNumber - contactEmail - { type: 'section', label: 'Delivery' } - 'canBeDelivered' - { property: 'adminCommandBefore', label: 'Commander avant', type: 'time', type_options: { minutes:['10','25','40','55'] } } - tournee Content: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\HtmlContent new: fields: - 'name' - { property: 'html', type: 'fos_ckeditor' } edit: fields: - { property: 'html', type: 'fos_ckeditor' } Product: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\Product list: fields: - category - name - { property: 'price', format: '%01.2f €' } - isEnabled - order form: fields: - category - name - description - { property: 'price', type: 'money', type_options: { currency: 'EUR' } } - isEnabled - order sort: ['category', 'ASC'] Tournee: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\Tournee Pdf: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\Pdf new: fields: - id - text - { property: 'pdfFile', type: 'file' } edit: fields: - text - { property: 'pdfFile', type: 'file' } User: role: 'ROLE_ADMIN' class: Symfony4\Doctrine\User list: fields: - firstName - lastName - company - phoneNumber - email - store - isEnabled form: fields: - isEnabled - firstName - lastName - company - phoneNumber - email - { property: 'store', type: 'choice', type_options: { choices:{'La hulpe':'la-hulpe','Waterloo':'waterloo'} } } - { property: 'role', type: 'choice', type_options: { choices:{'admin':'admin','sandwich':'sandwich','client':'client'} } } ================================================ FILE: config/packages/fos_ck_editor.yaml ================================================ fos_ck_editor: default_config: my_custom_config configs: my_custom_config: language: "fr" toolbar: [ [ 'Bold','Italic','Underline','Strike','-','RemoveFormat'], [ 'NumberedList','BulletedList','-','Outdent','Indent','-','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock' ], [ 'Link','Unlink'],[ 'Preview' ], [ 'Source' ], "/", [ 'Styles', 'Format','Font','FontSize' ], [ 'TextColor'] ] stylesSet: - { name: "Important", element: "span", attributes: { class: "important" }} - { name: "Ecriture rouge", element: "span", attributes: { class: "red-text lighten-2" }} - { name: "Encart rouge", element: "div", attributes: { class: "card-panel red lighten-2"}} - { name: "Encart vert", element: "div", attributes: { class: "card-panel light-green"}} - { name: "Encart vert 2", element: "div", attributes: { class: "card-panel light-green lighten-2"}} - { name: "Encart vert 3", element: "div", attributes: { class: "card-panel light-green lighten-3"}} - { name: "Encart vert 4", element: "div", attributes: { class: "card-panel light-green darken-1"}} - { name: "Encart vert 5", element: "div", attributes: { class: "card-panel light-green darken-2"}} # Chargement des styles personnalisables my_styles (voir plus bas) uiColor: "#FCFCFC" # Couleur de fond de l'interface height: "600px" # Hauteur par défaut contentsCss: ['/css/seat-base.css','/css/materialize.min.css'] # Charge les styles dans l'éditeur (permet de voir en temps réel le résultat) ================================================ FILE: config/packages/framework.yaml ================================================ framework: secret: '%env(APP_SECRET)%' csrf_protection: true http_method_override: true trusted_hosts: ~ session: # With this config, PHP's native session handling is used handler_id: ~ cookie_secure: auto cookie_samesite: lax php_errors: log: true assets: json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' cache: # this value is used as part of the "namespace" generated for the cache item keys # to avoid collisions when multiple apps share the same cache backend (e.g. a Redis server) # See https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed prefix_seed: restaurant-seat # The 'ide' option turns all of the file paths in an exception page # into clickable links that open the given file using your favorite IDE. # When 'ide' is set to null the file is opened in your web browser. # See https://symfony.com/doc/current/reference/configuration/framework.html#ide ide: phpstorm validation: email_validation_mode: 'html5' enable_annotations: true form: ~ ================================================ FILE: config/packages/html_sanitizer.yaml ================================================ #html_sanitizer: # default_sanitizer: 'default' # sanitizers: # default: # # Read https://github.com/tgalopin/html-sanitizer/blob/master/docs/1-getting-started.md#extensions # # to learn more about which extensions you would like to enable. # extensions: # - 'basic' # - 'list' # - 'table' # - 'image' # - 'code' # # # Read https://github.com/tgalopin/html-sanitizer/blob/master/docs/3-configuration-reference.md # # to discover all the available options for each extension. ================================================ FILE: config/packages/prod/doctrine.yaml ================================================ doctrine: dbal: driver: 'pdo_postgresql' url: '%env(resolve:DATABASE_URL)%' server_version: '11' charset: utf8 default_table_options: charset: utf8 collate: utf8_unicode_ci orm: metadata_cache_driver: type: service id: doctrine.system_cache_provider query_cache_driver: type: service id: doctrine.system_cache_provider result_cache_driver: type: service id: doctrine.result_cache_provider services: doctrine.result_cache_provider: class: Symfony\Component\Cache\DoctrineProvider public: false arguments: - '@doctrine.result_cache_pool' doctrine.system_cache_provider: class: Symfony\Component\Cache\DoctrineProvider public: false arguments: - '@doctrine.system_cache_pool' framework: cache: pools: doctrine.result_cache_pool: adapter: cache.app doctrine.system_cache_pool: adapter: cache.system ================================================ FILE: config/packages/prod/monolog.yaml ================================================ monolog: handlers: filter_for_errors: type: fingers_crossed action_level: error handler: error_log_handler excluded_404s: # regex: exclude all 404 errors from the logs - ^/ error_log_handler: type: error_log level: info ================================================ FILE: config/packages/prod/webpack_encore.yaml ================================================ #webpack_encore: # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) # Available in version 1.2 #cache: true ================================================ FILE: config/packages/routing.yaml ================================================ framework: router: strict_requirements: ~ utf8: true ================================================ FILE: config/packages/security.yaml ================================================ security: encoders: # Our user class and the algorithm we'll use to encode passwords # https://symfony.com/doc/current/security.html#c-encoding-the-user-s-password Symfony4\Security\User: bcrypt providers: # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded # In this example, users are stored via Doctrine in the database # To see the users at src/App/DataFixtures/ORM/LoadFixtures.php # To load users from somewhere else: https://symfony.com/doc/current/security/custom_provider.html client_user_provider: id: Symfony4\Security\Service\ClientUserProvider # https://symfony.com/doc/current/security.html#initial-security-yml-setup-authentication firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: # this firewall applies to all URLs pattern: ^/ # but the firewall does not require login on every page # denying access is done in access_control or in your controllers anonymous: true # This allows the user to login by submitting a username and password # Reference: https://symfony.com/doc/current/security/form_login_setup.html form_login: # The route name that the login form submits to check_path: login_check # The name of the route where the login form lives # When the user tries to access a protected page, they are redirected here login_path: login # Secure the login form against CSRF # Reference: https://symfony.com/doc/current/security/csrf_in_login_form.html csrf_token_generator: security.csrf.token_manager # The page users are redirect to when there is no previous page stored in the # session (for example when the users access directly to the login page). default_target_path: home logout: invalidate_session: false # The route name the user can go to in order to logout path: logout # The name of the route to redirect to after logging out target: home guard: authenticators: - Symfony4\Security\Service\FormAuthenticator remember_me: secret: "%kernel.secret%" lifetime: 315360000 # 10 years :) path: / always_remember_me: true access_control: # this is a catch-all for the admin area # additional security lives in the controllers - { path: '^/work', roles: ROLE_SANDWICH } role_hierarchy: ROLE_SANDWICH: ROLE_CLIENT ROLE_ADMIN: ROLE_SANDWICH ================================================ FILE: config/packages/security_checker.yaml ================================================ #services: # SensioLabs\Security\SecurityChecker: # public: false # # SensioLabs\Security\Command\SecurityCheckerCommand: # arguments: ['@SensioLabs\Security\SecurityChecker'] # public: false # tags: # - { name: console.command, command: 'security:check' } ================================================ FILE: config/packages/sensio_framework_extra.yaml ================================================ sensio_framework_extra: router: annotations: false ================================================ FILE: config/packages/sentry.yml ================================================ sentry: dsn: "https://your@sentry.io/url" ================================================ FILE: config/packages/swiftmailer.yaml ================================================ swiftmailer: url: '%env(MAILER_URL)%' spool: { type: 'memory' } ================================================ FILE: config/packages/test/dama_doctrine_test_bundle.yaml ================================================ dama_doctrine_test: enable_static_connection: true enable_static_meta_data_cache: true enable_static_query_cache: true ================================================ FILE: config/packages/test/framework.yaml ================================================ framework: test: true session: storage_id: session.storage.mock_file ================================================ FILE: config/packages/test/monolog.yaml ================================================ monolog: handlers: main: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug channels: ["!event"] ================================================ FILE: config/packages/test/routing.yaml ================================================ framework: router: strict_requirements: true ================================================ FILE: config/packages/test/security.yaml ================================================ # this configuration simplifies testing URLs protected by the security mechanism # See https://symfony.com/doc/current/cookbook/testing/http_authentication.html security: encoders: # to make tests much faster, BCrypt cost is changed to its minimum allowed value (4) # See https://symfony.com/doc/current/reference/configuration/security.html#using-the-bcrypt-password-encoder Symfony4\Security\User: { algorithm: bcrypt, cost: 4 } firewalls: main: http_basic: ~ ================================================ FILE: config/packages/test/swiftmailer.yaml ================================================ swiftmailer: disable_delivery: true ================================================ FILE: config/packages/test/web_profiler.yaml ================================================ web_profiler: toolbar: false intercept_redirects: false framework: profiler: { collect: false } ================================================ FILE: config/packages/translation.yaml ================================================ framework: default_locale: '%locale%' translator: default_path: '%kernel.project_dir%/resources/translations' fallbacks: - '%locale%' ================================================ FILE: config/packages/twig.yaml ================================================ twig: debug: '%kernel.debug%' default_path: '%kernel.project_dir%/resources/templates' strict_variables: '%kernel.debug%' form_themes: - '@FOSCKEditor/Form/ckeditor_widget.html.twig' globals: pdf_path: '%app.path.download_pdf%' ================================================ FILE: config/packages/twig_extensions.yaml ================================================ services: _defaults: public: false autowire: true autoconfigure: true #Twig\Extensions\ArrayExtension: ~ #Twig\Extensions\DateExtension: ~ Twig\Extensions\IntlExtension: ~ # needed for the 'localizeddate' filter #Twig\Extensions\TextExtension: ~ ================================================ FILE: config/packages/validator.yaml ================================================ framework: validation: email_validation_mode: html5 ================================================ FILE: config/packages/vich_uploader.yaml ================================================ vich_uploader: db_driver: orm mappings: pdf: uri_prefix: '%app.path.download_pdf%' upload_destination: '%kernel.project_dir%/public%app.path.download_pdf%' ================================================ FILE: config/packages/webpack_encore.yaml ================================================ webpack_encore: # The path where Encore is building the assets. # This should match Encore.setOutputPath() in webpack.config.js. output_path: '%kernel.project_dir%/public/build' ================================================ FILE: config/routes/annotations.yaml ================================================ controllers: resource: '../../src/Seat/Infrastructure/Symfony4/Controller/' type: annotation requirements: _locale: '%app_locales%' defaults: _locale: '%locale%' ================================================ FILE: config/routes/dev/twig.yaml ================================================ _errors: resource: '@TwigBundle/Resources/config/routing/errors.xml' prefix: /_error ================================================ FILE: config/routes/dev/web_profiler.yaml ================================================ web_profiler_wdt: resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' prefix: /_wdt web_profiler_profiler: resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' prefix: /_profiler ================================================ FILE: config/routes/easy_admin.yaml ================================================ easy_admin_bundle: resource: 'Symfony4\Controller\AdminController' prefix: /work type: annotation ================================================ FILE: config/services.yaml ================================================ # Learn more about services, parameters and containers at # http://symfony.com/doc/current/book/service_container.html parameters: locale: fr seat_email: commande@seat.be app_locales: fr app.path.download_pdf: /share/download/pdf services: # default configuration for services in *this* file _defaults: # automatically injects dependencies in your services autowire: true # automatically registers your services as commands, event subscribers, etc. autoconfigure: true # this means you cannot fetch services directly from the container via $container->get() # if you need to do this, you can override this setting on individual services public: false Symfony4\Doctrine\: resource: '../src/Seat/Infrastructure/Symfony4/Doctrine/*' tags: ['seat.autowire'] Symfony4\: resource: '../src/Seat/Infrastructure/Symfony4/*' exclude: '../src/Seat/Infrastructure/Symfony4/{Doctrine,Kernel.php}' Symfony4\Twig\: resource: '../src/Seat/Infrastructure/Symfony4/Twig' tags: ['twig.extension'] Seat\Domain\: resource: '../src/Seat/Domain/*' exclude: '../src/Seat/Domain/{**/Entity,**/Error,**/Model}' Seat\Presentation\: resource: '../src/Seat/Presentation/*' exclude: '../src/Seat/Presentation/{**/Entity,**/Error,**/Model}' Seat\SharedKernel\: resource: '../src/Seat/SharedKernel' Seat\SharedKernel\Service\PasswordHasher: alias: Seat\SharedKernel\Service\NativePasswordHasher Symfony\Component\HttpFoundation\Session\Session: alias: 'session' Symfony4\Controller\: resource: '../src/Seat/Infrastructure/Symfony4/Controller' tags: ['controller.service_arguments'] Symfony4\DependencyInjection\Compiler\AdminFilterRolePass: tags: - name: "easyadmin.config_pass" priority: 75 # before menu ================================================ FILE: package.json ================================================ { "devDependencies": { "@symfony/webpack-encore": "^0.27.0", "core-js": "^3.0.0", "webpack-notifier": "^1.6.0" }, "license": "UNLICENSED", "private": true, "scripts": { "dev-server": "encore dev-server", "dev": "encore dev", "watch": "encore dev --watch", "build": "encore production --progress" }, "dependencies": {} } ================================================ FILE: phpunit.xml.dist ================================================ tests/unit ================================================ FILE: public/.htaccess ================================================ Options -MultiViews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php [QSA,L] RedirectMatch 302 ^/$ /index.php/ ================================================ FILE: public/build/app.css ================================================ body { background-color: lightgray; } /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vYXBwLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtJQUNJLDJCQUEyQjtBQUMvQiIsImZpbGUiOiJhcHAuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYm9keSB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5O1xufVxuIl0sInNvdXJjZVJvb3QiOiIifQ==*/ ================================================ FILE: public/build/app.js ================================================ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([["app"],{ /***/ "./resources/assets/css/app.css": /*!**************************************!*\ !*** ./resources/assets/css/app.css ***! \**************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "./resources/assets/js/app.js": /*!************************************!*\ !*** ./resources/assets/js/app.js ***! \************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* * Welcome to your app's main JavaScript file! * * We recommend including the built version of this JavaScript file * (and its CSS file) in your base layout (base.html.twig). */ // any CSS you require will output into a single css file (app.css in this case) __webpack_require__(/*! ../css/app.css */ "./resources/assets/css/app.css"); // Need jQuery? Install it with "yarn add jquery", then uncomment to require it. // const $ = require('jquery'); console.log('Hello Webpack Encore! Edit me in assets/js/app.js'); /***/ }) },[["./resources/assets/js/app.js","runtime"]]]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvYXNzZXRzL2Nzcy9hcHAuY3NzIiwid2VicGFjazovLy8uL3Jlc291cmNlcy9hc3NldHMvanMvYXBwLmpzIl0sIm5hbWVzIjpbInJlcXVpcmUiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSx1Qzs7Ozs7Ozs7Ozs7QUNBQTs7Ozs7O0FBT0E7QUFDQUEsbUJBQU8sQ0FBQyxzREFBRCxDQUFQLEMsQ0FFQTtBQUNBOzs7QUFFQUMsT0FBTyxDQUFDQyxHQUFSLENBQVksbURBQVosRSIsImZpbGUiOiJhcHAuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBleHRyYWN0ZWQgYnkgbWluaS1jc3MtZXh0cmFjdC1wbHVnaW4iLCIvKlxuICogV2VsY29tZSB0byB5b3VyIGFwcCdzIG1haW4gSmF2YVNjcmlwdCBmaWxlIVxuICpcbiAqIFdlIHJlY29tbWVuZCBpbmNsdWRpbmcgdGhlIGJ1aWx0IHZlcnNpb24gb2YgdGhpcyBKYXZhU2NyaXB0IGZpbGVcbiAqIChhbmQgaXRzIENTUyBmaWxlKSBpbiB5b3VyIGJhc2UgbGF5b3V0IChiYXNlLmh0bWwudHdpZykuXG4gKi9cblxuLy8gYW55IENTUyB5b3UgcmVxdWlyZSB3aWxsIG91dHB1dCBpbnRvIGEgc2luZ2xlIGNzcyBmaWxlIChhcHAuY3NzIGluIHRoaXMgY2FzZSlcbnJlcXVpcmUoJy4uL2Nzcy9hcHAuY3NzJyk7XG5cbi8vIE5lZWQgalF1ZXJ5PyBJbnN0YWxsIGl0IHdpdGggXCJ5YXJuIGFkZCBqcXVlcnlcIiwgdGhlbiB1bmNvbW1lbnQgdG8gcmVxdWlyZSBpdC5cbi8vIGNvbnN0ICQgPSByZXF1aXJlKCdqcXVlcnknKTtcblxuY29uc29sZS5sb2coJ0hlbGxvIFdlYnBhY2sgRW5jb3JlISBFZGl0IG1lIGluIGFzc2V0cy9qcy9hcHAuanMnKTtcbiJdLCJzb3VyY2VSb290IjoiIn0= ================================================ FILE: public/build/entrypoints.json ================================================ { "entrypoints": { "app": { "js": [ "/build/runtime.js", "/build/app.js" ], "css": [ "/build/app.css" ] } } } ================================================ FILE: public/build/manifest.json ================================================ { "build/app.css": "/build/app.css", "build/app.js": "/build/app.js", "build/runtime.js": "/build/runtime.js" } ================================================ FILE: public/build/runtime.js ================================================ /******/ (function(modules) { // webpackBootstrap /******/ // install a JSONP callback for chunk loading /******/ function webpackJsonpCallback(data) { /******/ var chunkIds = data[0]; /******/ var moreModules = data[1]; /******/ var executeModules = data[2]; /******/ /******/ // add "moreModules" to the modules object, /******/ // then flag all "chunkIds" as loaded and fire callback /******/ var moduleId, chunkId, i = 0, resolves = []; /******/ for(;i < chunkIds.length; i++) { /******/ chunkId = chunkIds[i]; /******/ if(installedChunks[chunkId]) { /******/ resolves.push(installedChunks[chunkId][0]); /******/ } /******/ installedChunks[chunkId] = 0; /******/ } /******/ for(moduleId in moreModules) { /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { /******/ modules[moduleId] = moreModules[moduleId]; /******/ } /******/ } /******/ if(parentJsonpFunction) parentJsonpFunction(data); /******/ /******/ while(resolves.length) { /******/ resolves.shift()(); /******/ } /******/ /******/ // add entry modules from loaded chunk to deferred list /******/ deferredModules.push.apply(deferredModules, executeModules || []); /******/ /******/ // run deferred modules when all chunks ready /******/ return checkDeferredModules(); /******/ }; /******/ function checkDeferredModules() { /******/ var result; /******/ for(var i = 0; i < deferredModules.length; i++) { /******/ var deferredModule = deferredModules[i]; /******/ var fulfilled = true; /******/ for(var j = 1; j < deferredModule.length; j++) { /******/ var depId = deferredModule[j]; /******/ if(installedChunks[depId] !== 0) fulfilled = false; /******/ } /******/ if(fulfilled) { /******/ deferredModules.splice(i--, 1); /******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); /******/ } /******/ } /******/ return result; /******/ } /******/ /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // object to store loaded and loading chunks /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched /******/ // Promise = chunk loading, 0 = chunk loaded /******/ var installedChunks = { /******/ "runtime": 0 /******/ }; /******/ /******/ var deferredModules = []; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/build/"; /******/ /******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; /******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); /******/ jsonpArray.push = webpackJsonpCallback; /******/ jsonpArray = jsonpArray.slice(); /******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); /******/ var parentJsonpFunction = oldJsonpFunction; /******/ /******/ /******/ // run deferred modules from other chunks /******/ checkDeferredModules(); /******/ }) /************************************************************************/ /******/ ([]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQVEsb0JBQW9CO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQWlCLDRCQUE0QjtBQUM3QztBQUNBO0FBQ0EsMEJBQWtCLDJCQUEyQjtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxrREFBMEMsZ0NBQWdDO0FBQzFFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0VBQXdELGtCQUFrQjtBQUMxRTtBQUNBLHlEQUFpRCxjQUFjO0FBQy9EOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBeUMsaUNBQWlDO0FBQzFFLHdIQUFnSCxtQkFBbUIsRUFBRTtBQUNySTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1DQUEyQiwwQkFBMEIsRUFBRTtBQUN2RCx5Q0FBaUMsZUFBZTtBQUNoRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw4REFBc0QsK0RBQStEOztBQUVySDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQWdCLHVCQUF1QjtBQUN2Qzs7O0FBR0E7QUFDQSIsImZpbGUiOiJydW50aW1lLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gaW5zdGFsbCBhIEpTT05QIGNhbGxiYWNrIGZvciBjaHVuayBsb2FkaW5nXG4gXHRmdW5jdGlvbiB3ZWJwYWNrSnNvbnBDYWxsYmFjayhkYXRhKSB7XG4gXHRcdHZhciBjaHVua0lkcyA9IGRhdGFbMF07XG4gXHRcdHZhciBtb3JlTW9kdWxlcyA9IGRhdGFbMV07XG4gXHRcdHZhciBleGVjdXRlTW9kdWxlcyA9IGRhdGFbMl07XG5cbiBcdFx0Ly8gYWRkIFwibW9yZU1vZHVsZXNcIiB0byB0aGUgbW9kdWxlcyBvYmplY3QsXG4gXHRcdC8vIHRoZW4gZmxhZyBhbGwgXCJjaHVua0lkc1wiIGFzIGxvYWRlZCBhbmQgZmlyZSBjYWxsYmFja1xuIFx0XHR2YXIgbW9kdWxlSWQsIGNodW5rSWQsIGkgPSAwLCByZXNvbHZlcyA9IFtdO1xuIFx0XHRmb3IoO2kgPCBjaHVua0lkcy5sZW5ndGg7IGkrKykge1xuIFx0XHRcdGNodW5rSWQgPSBjaHVua0lkc1tpXTtcbiBcdFx0XHRpZihpbnN0YWxsZWRDaHVua3NbY2h1bmtJZF0pIHtcbiBcdFx0XHRcdHJlc29sdmVzLnB1c2goaW5zdGFsbGVkQ2h1bmtzW2NodW5rSWRdWzBdKTtcbiBcdFx0XHR9XG4gXHRcdFx0aW5zdGFsbGVkQ2h1bmtzW2NodW5rSWRdID0gMDtcbiBcdFx0fVxuIFx0XHRmb3IobW9kdWxlSWQgaW4gbW9yZU1vZHVsZXMpIHtcbiBcdFx0XHRpZihPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobW9yZU1vZHVsZXMsIG1vZHVsZUlkKSkge1xuIFx0XHRcdFx0bW9kdWxlc1ttb2R1bGVJZF0gPSBtb3JlTW9kdWxlc1ttb2R1bGVJZF07XG4gXHRcdFx0fVxuIFx0XHR9XG4gXHRcdGlmKHBhcmVudEpzb25wRnVuY3Rpb24pIHBhcmVudEpzb25wRnVuY3Rpb24oZGF0YSk7XG5cbiBcdFx0d2hpbGUocmVzb2x2ZXMubGVuZ3RoKSB7XG4gXHRcdFx0cmVzb2x2ZXMuc2hpZnQoKSgpO1xuIFx0XHR9XG5cbiBcdFx0Ly8gYWRkIGVudHJ5IG1vZHVsZXMgZnJvbSBsb2FkZWQgY2h1bmsgdG8gZGVmZXJyZWQgbGlzdFxuIFx0XHRkZWZlcnJlZE1vZHVsZXMucHVzaC5hcHBseShkZWZlcnJlZE1vZHVsZXMsIGV4ZWN1dGVNb2R1bGVzIHx8IFtdKTtcblxuIFx0XHQvLyBydW4gZGVmZXJyZWQgbW9kdWxlcyB3aGVuIGFsbCBjaHVua3MgcmVhZHlcbiBcdFx0cmV0dXJuIGNoZWNrRGVmZXJyZWRNb2R1bGVzKCk7XG4gXHR9O1xuIFx0ZnVuY3Rpb24gY2hlY2tEZWZlcnJlZE1vZHVsZXMoKSB7XG4gXHRcdHZhciByZXN1bHQ7XG4gXHRcdGZvcih2YXIgaSA9IDA7IGkgPCBkZWZlcnJlZE1vZHVsZXMubGVuZ3RoOyBpKyspIHtcbiBcdFx0XHR2YXIgZGVmZXJyZWRNb2R1bGUgPSBkZWZlcnJlZE1vZHVsZXNbaV07XG4gXHRcdFx0dmFyIGZ1bGZpbGxlZCA9IHRydWU7XG4gXHRcdFx0Zm9yKHZhciBqID0gMTsgaiA8IGRlZmVycmVkTW9kdWxlLmxlbmd0aDsgaisrKSB7XG4gXHRcdFx0XHR2YXIgZGVwSWQgPSBkZWZlcnJlZE1vZHVsZVtqXTtcbiBcdFx0XHRcdGlmKGluc3RhbGxlZENodW5rc1tkZXBJZF0gIT09IDApIGZ1bGZpbGxlZCA9IGZhbHNlO1xuIFx0XHRcdH1cbiBcdFx0XHRpZihmdWxmaWxsZWQpIHtcbiBcdFx0XHRcdGRlZmVycmVkTW9kdWxlcy5zcGxpY2UoaS0tLCAxKTtcbiBcdFx0XHRcdHJlc3VsdCA9IF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gZGVmZXJyZWRNb2R1bGVbMF0pO1xuIFx0XHRcdH1cbiBcdFx0fVxuIFx0XHRyZXR1cm4gcmVzdWx0O1xuIFx0fVxuXG4gXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBvYmplY3QgdG8gc3RvcmUgbG9hZGVkIGFuZCBsb2FkaW5nIGNodW5rc1xuIFx0Ly8gdW5kZWZpbmVkID0gY2h1bmsgbm90IGxvYWRlZCwgbnVsbCA9IGNodW5rIHByZWxvYWRlZC9wcmVmZXRjaGVkXG4gXHQvLyBQcm9taXNlID0gY2h1bmsgbG9hZGluZywgMCA9IGNodW5rIGxvYWRlZFxuIFx0dmFyIGluc3RhbGxlZENodW5rcyA9IHtcbiBcdFx0XCJydW50aW1lXCI6IDBcbiBcdH07XG5cbiBcdHZhciBkZWZlcnJlZE1vZHVsZXMgPSBbXTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCIvYnVpbGQvXCI7XG5cbiBcdHZhciBqc29ucEFycmF5ID0gd2luZG93W1wid2VicGFja0pzb25wXCJdID0gd2luZG93W1wid2VicGFja0pzb25wXCJdIHx8IFtdO1xuIFx0dmFyIG9sZEpzb25wRnVuY3Rpb24gPSBqc29ucEFycmF5LnB1c2guYmluZChqc29ucEFycmF5KTtcbiBcdGpzb25wQXJyYXkucHVzaCA9IHdlYnBhY2tKc29ucENhbGxiYWNrO1xuIFx0anNvbnBBcnJheSA9IGpzb25wQXJyYXkuc2xpY2UoKTtcbiBcdGZvcih2YXIgaSA9IDA7IGkgPCBqc29ucEFycmF5Lmxlbmd0aDsgaSsrKSB3ZWJwYWNrSnNvbnBDYWxsYmFjayhqc29ucEFycmF5W2ldKTtcbiBcdHZhciBwYXJlbnRKc29ucEZ1bmN0aW9uID0gb2xkSnNvbnBGdW5jdGlvbjtcblxuXG4gXHQvLyBydW4gZGVmZXJyZWQgbW9kdWxlcyBmcm9tIG90aGVyIGNodW5rc1xuIFx0Y2hlY2tEZWZlcnJlZE1vZHVsZXMoKTtcbiJdLCJzb3VyY2VSb290IjoiIn0= ================================================ FILE: public/css/materialize.css ================================================ /*! * Materialize v1.0.0 (http://materializecss.com) * Copyright 2014-2017 Materialize * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) */ .materialize-red { background-color: #e51c23 !important; } .materialize-red-text { color: #e51c23 !important; } .materialize-red.lighten-5 { background-color: #fdeaeb !important; } .materialize-red-text.text-lighten-5 { color: #fdeaeb !important; } .materialize-red.lighten-4 { background-color: #f8c1c3 !important; } .materialize-red-text.text-lighten-4 { color: #f8c1c3 !important; } .materialize-red.lighten-3 { background-color: #f3989b !important; } .materialize-red-text.text-lighten-3 { color: #f3989b !important; } .materialize-red.lighten-2 { background-color: #ee6e73 !important; } .materialize-red-text.text-lighten-2 { color: #ee6e73 !important; } .materialize-red.lighten-1 { background-color: #ea454b !important; } .materialize-red-text.text-lighten-1 { color: #ea454b !important; } .materialize-red.darken-1 { background-color: #d0181e !important; } .materialize-red-text.text-darken-1 { color: #d0181e !important; } .materialize-red.darken-2 { background-color: #b9151b !important; } .materialize-red-text.text-darken-2 { color: #b9151b !important; } .materialize-red.darken-3 { background-color: #a21318 !important; } .materialize-red-text.text-darken-3 { color: #a21318 !important; } .materialize-red.darken-4 { background-color: #8b1014 !important; } .materialize-red-text.text-darken-4 { color: #8b1014 !important; } .red { background-color: #F44336 !important; } .red-text { color: #F44336 !important; } .red.lighten-5 { background-color: #FFEBEE !important; } .red-text.text-lighten-5 { color: #FFEBEE !important; } .red.lighten-4 { background-color: #FFCDD2 !important; } .red-text.text-lighten-4 { color: #FFCDD2 !important; } .red.lighten-3 { background-color: #EF9A9A !important; } .red-text.text-lighten-3 { color: #EF9A9A !important; } .red.lighten-2 { background-color: #E57373 !important; } .red-text.text-lighten-2 { color: #E57373 !important; } .red.lighten-1 { background-color: #EF5350 !important; } .red-text.text-lighten-1 { color: #EF5350 !important; } .red.darken-1 { background-color: #E53935 !important; } .red-text.text-darken-1 { color: #E53935 !important; } .red.darken-2 { background-color: #D32F2F !important; } .red-text.text-darken-2 { color: #D32F2F !important; } .red.darken-3 { background-color: #C62828 !important; } .red-text.text-darken-3 { color: #C62828 !important; } .red.darken-4 { background-color: #B71C1C !important; } .red-text.text-darken-4 { color: #B71C1C !important; } .red.accent-1 { background-color: #FF8A80 !important; } .red-text.text-accent-1 { color: #FF8A80 !important; } .red.accent-2 { background-color: #FF5252 !important; } .red-text.text-accent-2 { color: #FF5252 !important; } .red.accent-3 { background-color: #FF1744 !important; } .red-text.text-accent-3 { color: #FF1744 !important; } .red.accent-4 { background-color: #D50000 !important; } .red-text.text-accent-4 { color: #D50000 !important; } .pink { background-color: #e91e63 !important; } .pink-text { color: #e91e63 !important; } .pink.lighten-5 { background-color: #fce4ec !important; } .pink-text.text-lighten-5 { color: #fce4ec !important; } .pink.lighten-4 { background-color: #f8bbd0 !important; } .pink-text.text-lighten-4 { color: #f8bbd0 !important; } .pink.lighten-3 { background-color: #f48fb1 !important; } .pink-text.text-lighten-3 { color: #f48fb1 !important; } .pink.lighten-2 { background-color: #f06292 !important; } .pink-text.text-lighten-2 { color: #f06292 !important; } .pink.lighten-1 { background-color: #ec407a !important; } .pink-text.text-lighten-1 { color: #ec407a !important; } .pink.darken-1 { background-color: #d81b60 !important; } .pink-text.text-darken-1 { color: #d81b60 !important; } .pink.darken-2 { background-color: #c2185b !important; } .pink-text.text-darken-2 { color: #c2185b !important; } .pink.darken-3 { background-color: #ad1457 !important; } .pink-text.text-darken-3 { color: #ad1457 !important; } .pink.darken-4 { background-color: #880e4f !important; } .pink-text.text-darken-4 { color: #880e4f !important; } .pink.accent-1 { background-color: #ff80ab !important; } .pink-text.text-accent-1 { color: #ff80ab !important; } .pink.accent-2 { background-color: #ff4081 !important; } .pink-text.text-accent-2 { color: #ff4081 !important; } .pink.accent-3 { background-color: #f50057 !important; } .pink-text.text-accent-3 { color: #f50057 !important; } .pink.accent-4 { background-color: #c51162 !important; } .pink-text.text-accent-4 { color: #c51162 !important; } .purple { background-color: #9c27b0 !important; } .purple-text { color: #9c27b0 !important; } .purple.lighten-5 { background-color: #f3e5f5 !important; } .purple-text.text-lighten-5 { color: #f3e5f5 !important; } .purple.lighten-4 { background-color: #e1bee7 !important; } .purple-text.text-lighten-4 { color: #e1bee7 !important; } .purple.lighten-3 { background-color: #ce93d8 !important; } .purple-text.text-lighten-3 { color: #ce93d8 !important; } .purple.lighten-2 { background-color: #ba68c8 !important; } .purple-text.text-lighten-2 { color: #ba68c8 !important; } .purple.lighten-1 { background-color: #ab47bc !important; } .purple-text.text-lighten-1 { color: #ab47bc !important; } .purple.darken-1 { background-color: #8e24aa !important; } .purple-text.text-darken-1 { color: #8e24aa !important; } .purple.darken-2 { background-color: #7b1fa2 !important; } .purple-text.text-darken-2 { color: #7b1fa2 !important; } .purple.darken-3 { background-color: #6a1b9a !important; } .purple-text.text-darken-3 { color: #6a1b9a !important; } .purple.darken-4 { background-color: #4a148c !important; } .purple-text.text-darken-4 { color: #4a148c !important; } .purple.accent-1 { background-color: #ea80fc !important; } .purple-text.text-accent-1 { color: #ea80fc !important; } .purple.accent-2 { background-color: #e040fb !important; } .purple-text.text-accent-2 { color: #e040fb !important; } .purple.accent-3 { background-color: #d500f9 !important; } .purple-text.text-accent-3 { color: #d500f9 !important; } .purple.accent-4 { background-color: #aa00ff !important; } .purple-text.text-accent-4 { color: #aa00ff !important; } .deep-purple { background-color: #673ab7 !important; } .deep-purple-text { color: #673ab7 !important; } .deep-purple.lighten-5 { background-color: #ede7f6 !important; } .deep-purple-text.text-lighten-5 { color: #ede7f6 !important; } .deep-purple.lighten-4 { background-color: #d1c4e9 !important; } .deep-purple-text.text-lighten-4 { color: #d1c4e9 !important; } .deep-purple.lighten-3 { background-color: #b39ddb !important; } .deep-purple-text.text-lighten-3 { color: #b39ddb !important; } .deep-purple.lighten-2 { background-color: #9575cd !important; } .deep-purple-text.text-lighten-2 { color: #9575cd !important; } .deep-purple.lighten-1 { background-color: #7e57c2 !important; } .deep-purple-text.text-lighten-1 { color: #7e57c2 !important; } .deep-purple.darken-1 { background-color: #5e35b1 !important; } .deep-purple-text.text-darken-1 { color: #5e35b1 !important; } .deep-purple.darken-2 { background-color: #512da8 !important; } .deep-purple-text.text-darken-2 { color: #512da8 !important; } .deep-purple.darken-3 { background-color: #4527a0 !important; } .deep-purple-text.text-darken-3 { color: #4527a0 !important; } .deep-purple.darken-4 { background-color: #311b92 !important; } .deep-purple-text.text-darken-4 { color: #311b92 !important; } .deep-purple.accent-1 { background-color: #b388ff !important; } .deep-purple-text.text-accent-1 { color: #b388ff !important; } .deep-purple.accent-2 { background-color: #7c4dff !important; } .deep-purple-text.text-accent-2 { color: #7c4dff !important; } .deep-purple.accent-3 { background-color: #651fff !important; } .deep-purple-text.text-accent-3 { color: #651fff !important; } .deep-purple.accent-4 { background-color: #6200ea !important; } .deep-purple-text.text-accent-4 { color: #6200ea !important; } .indigo { background-color: #3f51b5 !important; } .indigo-text { color: #3f51b5 !important; } .indigo.lighten-5 { background-color: #e8eaf6 !important; } .indigo-text.text-lighten-5 { color: #e8eaf6 !important; } .indigo.lighten-4 { background-color: #c5cae9 !important; } .indigo-text.text-lighten-4 { color: #c5cae9 !important; } .indigo.lighten-3 { background-color: #9fa8da !important; } .indigo-text.text-lighten-3 { color: #9fa8da !important; } .indigo.lighten-2 { background-color: #7986cb !important; } .indigo-text.text-lighten-2 { color: #7986cb !important; } .indigo.lighten-1 { background-color: #5c6bc0 !important; } .indigo-text.text-lighten-1 { color: #5c6bc0 !important; } .indigo.darken-1 { background-color: #3949ab !important; } .indigo-text.text-darken-1 { color: #3949ab !important; } .indigo.darken-2 { background-color: #303f9f !important; } .indigo-text.text-darken-2 { color: #303f9f !important; } .indigo.darken-3 { background-color: #283593 !important; } .indigo-text.text-darken-3 { color: #283593 !important; } .indigo.darken-4 { background-color: #1a237e !important; } .indigo-text.text-darken-4 { color: #1a237e !important; } .indigo.accent-1 { background-color: #8c9eff !important; } .indigo-text.text-accent-1 { color: #8c9eff !important; } .indigo.accent-2 { background-color: #536dfe !important; } .indigo-text.text-accent-2 { color: #536dfe !important; } .indigo.accent-3 { background-color: #3d5afe !important; } .indigo-text.text-accent-3 { color: #3d5afe !important; } .indigo.accent-4 { background-color: #304ffe !important; } .indigo-text.text-accent-4 { color: #304ffe !important; } .blue { background-color: #2196F3 !important; } .blue-text { color: #2196F3 !important; } .blue.lighten-5 { background-color: #E3F2FD !important; } .blue-text.text-lighten-5 { color: #E3F2FD !important; } .blue.lighten-4 { background-color: #BBDEFB !important; } .blue-text.text-lighten-4 { color: #BBDEFB !important; } .blue.lighten-3 { background-color: #90CAF9 !important; } .blue-text.text-lighten-3 { color: #90CAF9 !important; } .blue.lighten-2 { background-color: #64B5F6 !important; } .blue-text.text-lighten-2 { color: #64B5F6 !important; } .blue.lighten-1 { background-color: #42A5F5 !important; } .blue-text.text-lighten-1 { color: #42A5F5 !important; } .blue.darken-1 { background-color: #1E88E5 !important; } .blue-text.text-darken-1 { color: #1E88E5 !important; } .blue.darken-2 { background-color: #1976D2 !important; } .blue-text.text-darken-2 { color: #1976D2 !important; } .blue.darken-3 { background-color: #1565C0 !important; } .blue-text.text-darken-3 { color: #1565C0 !important; } .blue.darken-4 { background-color: #0D47A1 !important; } .blue-text.text-darken-4 { color: #0D47A1 !important; } .blue.accent-1 { background-color: #82B1FF !important; } .blue-text.text-accent-1 { color: #82B1FF !important; } .blue.accent-2 { background-color: #448AFF !important; } .blue-text.text-accent-2 { color: #448AFF !important; } .blue.accent-3 { background-color: #2979FF !important; } .blue-text.text-accent-3 { color: #2979FF !important; } .blue.accent-4 { background-color: #2962FF !important; } .blue-text.text-accent-4 { color: #2962FF !important; } .light-blue { background-color: #03a9f4 !important; } .light-blue-text { color: #03a9f4 !important; } .light-blue.lighten-5 { background-color: #e1f5fe !important; } .light-blue-text.text-lighten-5 { color: #e1f5fe !important; } .light-blue.lighten-4 { background-color: #b3e5fc !important; } .light-blue-text.text-lighten-4 { color: #b3e5fc !important; } .light-blue.lighten-3 { background-color: #81d4fa !important; } .light-blue-text.text-lighten-3 { color: #81d4fa !important; } .light-blue.lighten-2 { background-color: #4fc3f7 !important; } .light-blue-text.text-lighten-2 { color: #4fc3f7 !important; } .light-blue.lighten-1 { background-color: #29b6f6 !important; } .light-blue-text.text-lighten-1 { color: #29b6f6 !important; } .light-blue.darken-1 { background-color: #039be5 !important; } .light-blue-text.text-darken-1 { color: #039be5 !important; } .light-blue.darken-2 { background-color: #0288d1 !important; } .light-blue-text.text-darken-2 { color: #0288d1 !important; } .light-blue.darken-3 { background-color: #0277bd !important; } .light-blue-text.text-darken-3 { color: #0277bd !important; } .light-blue.darken-4 { background-color: #01579b !important; } .light-blue-text.text-darken-4 { color: #01579b !important; } .light-blue.accent-1 { background-color: #80d8ff !important; } .light-blue-text.text-accent-1 { color: #80d8ff !important; } .light-blue.accent-2 { background-color: #40c4ff !important; } .light-blue-text.text-accent-2 { color: #40c4ff !important; } .light-blue.accent-3 { background-color: #00b0ff !important; } .light-blue-text.text-accent-3 { color: #00b0ff !important; } .light-blue.accent-4 { background-color: #0091ea !important; } .light-blue-text.text-accent-4 { color: #0091ea !important; } .cyan { background-color: #00bcd4 !important; } .cyan-text { color: #00bcd4 !important; } .cyan.lighten-5 { background-color: #e0f7fa !important; } .cyan-text.text-lighten-5 { color: #e0f7fa !important; } .cyan.lighten-4 { background-color: #b2ebf2 !important; } .cyan-text.text-lighten-4 { color: #b2ebf2 !important; } .cyan.lighten-3 { background-color: #80deea !important; } .cyan-text.text-lighten-3 { color: #80deea !important; } .cyan.lighten-2 { background-color: #4dd0e1 !important; } .cyan-text.text-lighten-2 { color: #4dd0e1 !important; } .cyan.lighten-1 { background-color: #26c6da !important; } .cyan-text.text-lighten-1 { color: #26c6da !important; } .cyan.darken-1 { background-color: #00acc1 !important; } .cyan-text.text-darken-1 { color: #00acc1 !important; } .cyan.darken-2 { background-color: #0097a7 !important; } .cyan-text.text-darken-2 { color: #0097a7 !important; } .cyan.darken-3 { background-color: #00838f !important; } .cyan-text.text-darken-3 { color: #00838f !important; } .cyan.darken-4 { background-color: #006064 !important; } .cyan-text.text-darken-4 { color: #006064 !important; } .cyan.accent-1 { background-color: #84ffff !important; } .cyan-text.text-accent-1 { color: #84ffff !important; } .cyan.accent-2 { background-color: #18ffff !important; } .cyan-text.text-accent-2 { color: #18ffff !important; } .cyan.accent-3 { background-color: #00e5ff !important; } .cyan-text.text-accent-3 { color: #00e5ff !important; } .cyan.accent-4 { background-color: #00b8d4 !important; } .cyan-text.text-accent-4 { color: #00b8d4 !important; } .teal { background-color: #009688 !important; } .teal-text { color: #009688 !important; } .teal.lighten-5 { background-color: #e0f2f1 !important; } .teal-text.text-lighten-5 { color: #e0f2f1 !important; } .teal.lighten-4 { background-color: #b2dfdb !important; } .teal-text.text-lighten-4 { color: #b2dfdb !important; } .teal.lighten-3 { background-color: #80cbc4 !important; } .teal-text.text-lighten-3 { color: #80cbc4 !important; } .teal.lighten-2 { background-color: #4db6ac !important; } .teal-text.text-lighten-2 { color: #4db6ac !important; } .teal.lighten-1 { background-color: #26a69a !important; } .teal-text.text-lighten-1 { color: #26a69a !important; } .teal.darken-1 { background-color: #00897b !important; } .teal-text.text-darken-1 { color: #00897b !important; } .teal.darken-2 { background-color: #00796b !important; } .teal-text.text-darken-2 { color: #00796b !important; } .teal.darken-3 { background-color: #00695c !important; } .teal-text.text-darken-3 { color: #00695c !important; } .teal.darken-4 { background-color: #004d40 !important; } .teal-text.text-darken-4 { color: #004d40 !important; } .teal.accent-1 { background-color: #a7ffeb !important; } .teal-text.text-accent-1 { color: #a7ffeb !important; } .teal.accent-2 { background-color: #64ffda !important; } .teal-text.text-accent-2 { color: #64ffda !important; } .teal.accent-3 { background-color: #1de9b6 !important; } .teal-text.text-accent-3 { color: #1de9b6 !important; } .teal.accent-4 { background-color: #00bfa5 !important; } .teal-text.text-accent-4 { color: #00bfa5 !important; } .green { background-color: #4CAF50 !important; } .green-text { color: #4CAF50 !important; } .green.lighten-5 { background-color: #E8F5E9 !important; } .green-text.text-lighten-5 { color: #E8F5E9 !important; } .green.lighten-4 { background-color: #C8E6C9 !important; } .green-text.text-lighten-4 { color: #C8E6C9 !important; } .green.lighten-3 { background-color: #A5D6A7 !important; } .green-text.text-lighten-3 { color: #A5D6A7 !important; } .green.lighten-2 { background-color: #81C784 !important; } .green-text.text-lighten-2 { color: #81C784 !important; } .green.lighten-1 { background-color: #66BB6A !important; } .green-text.text-lighten-1 { color: #66BB6A !important; } .green.darken-1 { background-color: #43A047 !important; } .green-text.text-darken-1 { color: #43A047 !important; } .green.darken-2 { background-color: #388E3C !important; } .green-text.text-darken-2 { color: #388E3C !important; } .green.darken-3 { background-color: #2E7D32 !important; } .green-text.text-darken-3 { color: #2E7D32 !important; } .green.darken-4 { background-color: #1B5E20 !important; } .green-text.text-darken-4 { color: #1B5E20 !important; } .green.accent-1 { background-color: #B9F6CA !important; } .green-text.text-accent-1 { color: #B9F6CA !important; } .green.accent-2 { background-color: #69F0AE !important; } .green-text.text-accent-2 { color: #69F0AE !important; } .green.accent-3 { background-color: #00E676 !important; } .green-text.text-accent-3 { color: #00E676 !important; } .green.accent-4 { background-color: #00C853 !important; } .green-text.text-accent-4 { color: #00C853 !important; } .light-green { background-color: #8bc34a !important; } .light-green-text { color: #8bc34a !important; } .light-green.lighten-5 { background-color: #f1f8e9 !important; } .light-green-text.text-lighten-5 { color: #f1f8e9 !important; } .light-green.lighten-4 { background-color: #dcedc8 !important; } .light-green-text.text-lighten-4 { color: #dcedc8 !important; } .light-green.lighten-3 { background-color: #c5e1a5 !important; } .light-green-text.text-lighten-3 { color: #c5e1a5 !important; } .light-green.lighten-2 { background-color: #aed581 !important; } .light-green-text.text-lighten-2 { color: #aed581 !important; } .light-green.lighten-1 { background-color: #9ccc65 !important; } .light-green-text.text-lighten-1 { color: #9ccc65 !important; } .light-green.darken-1 { background-color: #7cb342 !important; } .light-green-text.text-darken-1 { color: #7cb342 !important; } .light-green.darken-2 { background-color: #689f38 !important; } .light-green-text.text-darken-2 { color: #689f38 !important; } .light-green.darken-3 { background-color: #558b2f !important; } .light-green-text.text-darken-3 { color: #558b2f !important; } .light-green.darken-4 { background-color: #33691e !important; } .light-green-text.text-darken-4 { color: #33691e !important; } .light-green.accent-1 { background-color: #ccff90 !important; } .light-green-text.text-accent-1 { color: #ccff90 !important; } .light-green.accent-2 { background-color: #b2ff59 !important; } .light-green-text.text-accent-2 { color: #b2ff59 !important; } .light-green.accent-3 { background-color: #76ff03 !important; } .light-green-text.text-accent-3 { color: #76ff03 !important; } .light-green.accent-4 { background-color: #64dd17 !important; } .light-green-text.text-accent-4 { color: #64dd17 !important; } .lime { background-color: #cddc39 !important; } .lime-text { color: #cddc39 !important; } .lime.lighten-5 { background-color: #f9fbe7 !important; } .lime-text.text-lighten-5 { color: #f9fbe7 !important; } .lime.lighten-4 { background-color: #f0f4c3 !important; } .lime-text.text-lighten-4 { color: #f0f4c3 !important; } .lime.lighten-3 { background-color: #e6ee9c !important; } .lime-text.text-lighten-3 { color: #e6ee9c !important; } .lime.lighten-2 { background-color: #dce775 !important; } .lime-text.text-lighten-2 { color: #dce775 !important; } .lime.lighten-1 { background-color: #d4e157 !important; } .lime-text.text-lighten-1 { color: #d4e157 !important; } .lime.darken-1 { background-color: #c0ca33 !important; } .lime-text.text-darken-1 { color: #c0ca33 !important; } .lime.darken-2 { background-color: #afb42b !important; } .lime-text.text-darken-2 { color: #afb42b !important; } .lime.darken-3 { background-color: #9e9d24 !important; } .lime-text.text-darken-3 { color: #9e9d24 !important; } .lime.darken-4 { background-color: #827717 !important; } .lime-text.text-darken-4 { color: #827717 !important; } .lime.accent-1 { background-color: #f4ff81 !important; } .lime-text.text-accent-1 { color: #f4ff81 !important; } .lime.accent-2 { background-color: #eeff41 !important; } .lime-text.text-accent-2 { color: #eeff41 !important; } .lime.accent-3 { background-color: #c6ff00 !important; } .lime-text.text-accent-3 { color: #c6ff00 !important; } .lime.accent-4 { background-color: #aeea00 !important; } .lime-text.text-accent-4 { color: #aeea00 !important; } .yellow { background-color: #ffeb3b !important; } .yellow-text { color: #ffeb3b !important; } .yellow.lighten-5 { background-color: #fffde7 !important; } .yellow-text.text-lighten-5 { color: #fffde7 !important; } .yellow.lighten-4 { background-color: #fff9c4 !important; } .yellow-text.text-lighten-4 { color: #fff9c4 !important; } .yellow.lighten-3 { background-color: #fff59d !important; } .yellow-text.text-lighten-3 { color: #fff59d !important; } .yellow.lighten-2 { background-color: #fff176 !important; } .yellow-text.text-lighten-2 { color: #fff176 !important; } .yellow.lighten-1 { background-color: #ffee58 !important; } .yellow-text.text-lighten-1 { color: #ffee58 !important; } .yellow.darken-1 { background-color: #fdd835 !important; } .yellow-text.text-darken-1 { color: #fdd835 !important; } .yellow.darken-2 { background-color: #fbc02d !important; } .yellow-text.text-darken-2 { color: #fbc02d !important; } .yellow.darken-3 { background-color: #f9a825 !important; } .yellow-text.text-darken-3 { color: #f9a825 !important; } .yellow.darken-4 { background-color: #f57f17 !important; } .yellow-text.text-darken-4 { color: #f57f17 !important; } .yellow.accent-1 { background-color: #ffff8d !important; } .yellow-text.text-accent-1 { color: #ffff8d !important; } .yellow.accent-2 { background-color: #ffff00 !important; } .yellow-text.text-accent-2 { color: #ffff00 !important; } .yellow.accent-3 { background-color: #ffea00 !important; } .yellow-text.text-accent-3 { color: #ffea00 !important; } .yellow.accent-4 { background-color: #ffd600 !important; } .yellow-text.text-accent-4 { color: #ffd600 !important; } .amber { background-color: #ffc107 !important; } .amber-text { color: #ffc107 !important; } .amber.lighten-5 { background-color: #fff8e1 !important; } .amber-text.text-lighten-5 { color: #fff8e1 !important; } .amber.lighten-4 { background-color: #ffecb3 !important; } .amber-text.text-lighten-4 { color: #ffecb3 !important; } .amber.lighten-3 { background-color: #ffe082 !important; } .amber-text.text-lighten-3 { color: #ffe082 !important; } .amber.lighten-2 { background-color: #ffd54f !important; } .amber-text.text-lighten-2 { color: #ffd54f !important; } .amber.lighten-1 { background-color: #ffca28 !important; } .amber-text.text-lighten-1 { color: #ffca28 !important; } .amber.darken-1 { background-color: #ffb300 !important; } .amber-text.text-darken-1 { color: #ffb300 !important; } .amber.darken-2 { background-color: #ffa000 !important; } .amber-text.text-darken-2 { color: #ffa000 !important; } .amber.darken-3 { background-color: #ff8f00 !important; } .amber-text.text-darken-3 { color: #ff8f00 !important; } .amber.darken-4 { background-color: #ff6f00 !important; } .amber-text.text-darken-4 { color: #ff6f00 !important; } .amber.accent-1 { background-color: #ffe57f !important; } .amber-text.text-accent-1 { color: #ffe57f !important; } .amber.accent-2 { background-color: #ffd740 !important; } .amber-text.text-accent-2 { color: #ffd740 !important; } .amber.accent-3 { background-color: #ffc400 !important; } .amber-text.text-accent-3 { color: #ffc400 !important; } .amber.accent-4 { background-color: #ffab00 !important; } .amber-text.text-accent-4 { color: #ffab00 !important; } .orange { background-color: #ff9800 !important; } .orange-text { color: #ff9800 !important; } .orange.lighten-5 { background-color: #fff3e0 !important; } .orange-text.text-lighten-5 { color: #fff3e0 !important; } .orange.lighten-4 { background-color: #ffe0b2 !important; } .orange-text.text-lighten-4 { color: #ffe0b2 !important; } .orange.lighten-3 { background-color: #ffcc80 !important; } .orange-text.text-lighten-3 { color: #ffcc80 !important; } .orange.lighten-2 { background-color: #ffb74d !important; } .orange-text.text-lighten-2 { color: #ffb74d !important; } .orange.lighten-1 { background-color: #ffa726 !important; } .orange-text.text-lighten-1 { color: #ffa726 !important; } .orange.darken-1 { background-color: #fb8c00 !important; } .orange-text.text-darken-1 { color: #fb8c00 !important; } .orange.darken-2 { background-color: #f57c00 !important; } .orange-text.text-darken-2 { color: #f57c00 !important; } .orange.darken-3 { background-color: #ef6c00 !important; } .orange-text.text-darken-3 { color: #ef6c00 !important; } .orange.darken-4 { background-color: #e65100 !important; } .orange-text.text-darken-4 { color: #e65100 !important; } .orange.accent-1 { background-color: #ffd180 !important; } .orange-text.text-accent-1 { color: #ffd180 !important; } .orange.accent-2 { background-color: #ffab40 !important; } .orange-text.text-accent-2 { color: #ffab40 !important; } .orange.accent-3 { background-color: #ff9100 !important; } .orange-text.text-accent-3 { color: #ff9100 !important; } .orange.accent-4 { background-color: #ff6d00 !important; } .orange-text.text-accent-4 { color: #ff6d00 !important; } .deep-orange { background-color: #ff5722 !important; } .deep-orange-text { color: #ff5722 !important; } .deep-orange.lighten-5 { background-color: #fbe9e7 !important; } .deep-orange-text.text-lighten-5 { color: #fbe9e7 !important; } .deep-orange.lighten-4 { background-color: #ffccbc !important; } .deep-orange-text.text-lighten-4 { color: #ffccbc !important; } .deep-orange.lighten-3 { background-color: #ffab91 !important; } .deep-orange-text.text-lighten-3 { color: #ffab91 !important; } .deep-orange.lighten-2 { background-color: #ff8a65 !important; } .deep-orange-text.text-lighten-2 { color: #ff8a65 !important; } .deep-orange.lighten-1 { background-color: #ff7043 !important; } .deep-orange-text.text-lighten-1 { color: #ff7043 !important; } .deep-orange.darken-1 { background-color: #f4511e !important; } .deep-orange-text.text-darken-1 { color: #f4511e !important; } .deep-orange.darken-2 { background-color: #e64a19 !important; } .deep-orange-text.text-darken-2 { color: #e64a19 !important; } .deep-orange.darken-3 { background-color: #d84315 !important; } .deep-orange-text.text-darken-3 { color: #d84315 !important; } .deep-orange.darken-4 { background-color: #bf360c !important; } .deep-orange-text.text-darken-4 { color: #bf360c !important; } .deep-orange.accent-1 { background-color: #ff9e80 !important; } .deep-orange-text.text-accent-1 { color: #ff9e80 !important; } .deep-orange.accent-2 { background-color: #ff6e40 !important; } .deep-orange-text.text-accent-2 { color: #ff6e40 !important; } .deep-orange.accent-3 { background-color: #ff3d00 !important; } .deep-orange-text.text-accent-3 { color: #ff3d00 !important; } .deep-orange.accent-4 { background-color: #dd2c00 !important; } .deep-orange-text.text-accent-4 { color: #dd2c00 !important; } .brown { background-color: #795548 !important; } .brown-text { color: #795548 !important; } .brown.lighten-5 { background-color: #efebe9 !important; } .brown-text.text-lighten-5 { color: #efebe9 !important; } .brown.lighten-4 { background-color: #d7ccc8 !important; } .brown-text.text-lighten-4 { color: #d7ccc8 !important; } .brown.lighten-3 { background-color: #bcaaa4 !important; } .brown-text.text-lighten-3 { color: #bcaaa4 !important; } .brown.lighten-2 { background-color: #a1887f !important; } .brown-text.text-lighten-2 { color: #a1887f !important; } .brown.lighten-1 { background-color: #8d6e63 !important; } .brown-text.text-lighten-1 { color: #8d6e63 !important; } .brown.darken-1 { background-color: #6d4c41 !important; } .brown-text.text-darken-1 { color: #6d4c41 !important; } .brown.darken-2 { background-color: #5d4037 !important; } .brown-text.text-darken-2 { color: #5d4037 !important; } .brown.darken-3 { background-color: #4e342e !important; } .brown-text.text-darken-3 { color: #4e342e !important; } .brown.darken-4 { background-color: #3e2723 !important; } .brown-text.text-darken-4 { color: #3e2723 !important; } .blue-grey { background-color: #607d8b !important; } .blue-grey-text { color: #607d8b !important; } .blue-grey.lighten-5 { background-color: #eceff1 !important; } .blue-grey-text.text-lighten-5 { color: #eceff1 !important; } .blue-grey.lighten-4 { background-color: #cfd8dc !important; } .blue-grey-text.text-lighten-4 { color: #cfd8dc !important; } .blue-grey.lighten-3 { background-color: #b0bec5 !important; } .blue-grey-text.text-lighten-3 { color: #b0bec5 !important; } .blue-grey.lighten-2 { background-color: #90a4ae !important; } .blue-grey-text.text-lighten-2 { color: #90a4ae !important; } .blue-grey.lighten-1 { background-color: #78909c !important; } .blue-grey-text.text-lighten-1 { color: #78909c !important; } .blue-grey.darken-1 { background-color: #546e7a !important; } .blue-grey-text.text-darken-1 { color: #546e7a !important; } .blue-grey.darken-2 { background-color: #455a64 !important; } .blue-grey-text.text-darken-2 { color: #455a64 !important; } .blue-grey.darken-3 { background-color: #37474f !important; } .blue-grey-text.text-darken-3 { color: #37474f !important; } .blue-grey.darken-4 { background-color: #263238 !important; } .blue-grey-text.text-darken-4 { color: #263238 !important; } .grey { background-color: #9e9e9e !important; } .grey-text { color: #9e9e9e !important; } .grey.lighten-5 { background-color: #fafafa !important; } .grey-text.text-lighten-5 { color: #fafafa !important; } .grey.lighten-4 { background-color: #f5f5f5 !important; } .grey-text.text-lighten-4 { color: #f5f5f5 !important; } .grey.lighten-3 { background-color: #eeeeee !important; } .grey-text.text-lighten-3 { color: #eeeeee !important; } .grey.lighten-2 { background-color: #e0e0e0 !important; } .grey-text.text-lighten-2 { color: #e0e0e0 !important; } .grey.lighten-1 { background-color: #bdbdbd !important; } .grey-text.text-lighten-1 { color: #bdbdbd !important; } .grey.darken-1 { background-color: #757575 !important; } .grey-text.text-darken-1 { color: #757575 !important; } .grey.darken-2 { background-color: #616161 !important; } .grey-text.text-darken-2 { color: #616161 !important; } .grey.darken-3 { background-color: #424242 !important; } .grey-text.text-darken-3 { color: #424242 !important; } .grey.darken-4 { background-color: #212121 !important; } .grey-text.text-darken-4 { color: #212121 !important; } .black { background-color: #000000 !important; } .black-text { color: #000000 !important; } .white { background-color: #FFFFFF !important; } .white-text { color: #FFFFFF !important; } .transparent { background-color: transparent !important; } .transparent-text { color: transparent !important; } /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in * IE on Windows Phone and in iOS. */ html { line-height: 1.15; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers (opinionated). */ body { margin: 0; } /** * Add the correct display in IE 9-. */ article, aside, footer, header, nav, section { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ h1 { font-size: 2em; margin: 0.67em 0; } /* Grouping content ========================================================================== */ /** * Add the correct display in IE 9-. * 1. Add the correct display in IE. */ figcaption, figure, main { /* 1 */ display: block; } /** * Add the correct margin in IE 8. */ figure { margin: 1em 40px; } /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { -webkit-box-sizing: content-box; box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * 1. Remove the gray background on active links in IE 10. * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. */ a { background-color: transparent; /* 1 */ -webkit-text-decoration-skip: objects; /* 2 */ } /** * 1. Remove the bottom border in Chrome 57- and Firefox 39-. * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ -webkit-text-decoration: underline dotted; -moz-text-decoration: underline dotted; text-decoration: underline dotted; /* 2 */ } /** * Prevent the duplicate application of `bolder` by the next rule in Safari 6. */ b, strong { font-weight: inherit; } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font style in Android 4.3-. */ dfn { font-style: italic; } /** * Add the correct background and color in IE 9-. */ mark { background-color: #ff0; color: #000; } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Add the correct display in IE 9-. */ audio, video { display: inline-block; } /** * Add the correct display in iOS 4-7. */ audio:not([controls]) { display: none; height: 0; } /** * Remove the border on images inside links in IE 10-. */ img { border-style: none; } /** * Hide the overflow in IE. */ svg:not(:root) { overflow: hidden; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers (opinionated). * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: sans-serif; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` * controls in Android 4. * 2. Correct the inability to style clickable types in iOS and Safari. */ button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; /* 2 */ } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { -webkit-box-sizing: border-box; box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * 1. Add the correct display in IE 9-. * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { display: inline-block; /* 1 */ vertical-align: baseline; /* 2 */ } /** * Remove the default vertical scrollbar in IE. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10-. * 2. Remove the padding in IE 10-. */ [type="checkbox"], [type="radio"] { -webkit-box-sizing: border-box; box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in IE 9-. * 1. Add the correct display in Edge, IE, and Firefox. */ details, menu { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Scripting ========================================================================== */ /** * Add the correct display in IE 9-. */ canvas { display: inline-block; } /** * Add the correct display in IE. */ template { display: none; } /* Hidden ========================================================================== */ /** * Add the correct display in IE 10-. */ [hidden] { display: none; } html { -webkit-box-sizing: border-box; box-sizing: border-box; } *, *:before, *:after { -webkit-box-sizing: inherit; box-sizing: inherit; } button, input, optgroup, select, textarea { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } ul:not(.browser-default) { padding-left: 0; list-style-type: none; } ul:not(.browser-default) > li { list-style-type: none; } a { color: #039be5; text-decoration: none; -webkit-tap-highlight-color: transparent; } .valign-wrapper { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; } .clearfix { clear: both; } .z-depth-0 { -webkit-box-shadow: none !important; box-shadow: none !important; } /* 2dp elevation modified*/ .z-depth-1, nav, .card-panel, .card, .toast, .btn, .btn-large, .btn-small, .btn-floating, .dropdown-content, .collapsible, .sidenav { -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); } .z-depth-1-half, .btn:hover, .btn-large:hover, .btn-small:hover, .btn-floating:hover { -webkit-box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2); box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2); } /* 6dp elevation modified*/ .z-depth-2 { -webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3); box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3); } /* 12dp elevation modified*/ .z-depth-3 { -webkit-box-shadow: 0 8px 17px 2px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); box-shadow: 0 8px 17px 2px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); } /* 16dp elevation */ .z-depth-4 { -webkit-box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -7px rgba(0, 0, 0, 0.2); box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -7px rgba(0, 0, 0, 0.2); } /* 24dp elevation */ .z-depth-5, .modal { -webkit-box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.2); box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.2); } .hoverable { -webkit-transition: -webkit-box-shadow .25s; transition: -webkit-box-shadow .25s; transition: box-shadow .25s; transition: box-shadow .25s, -webkit-box-shadow .25s; } .hoverable:hover { -webkit-box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } .divider { height: 1px; overflow: hidden; background-color: #e0e0e0; } blockquote { margin: 20px 0; padding-left: 1.5rem; border-left: 5px solid #ee6e73; } i { line-height: inherit; } i.left { float: left; margin-right: 15px; } i.right { float: right; margin-left: 15px; } i.tiny { font-size: 1rem; } i.small { font-size: 2rem; } i.medium { font-size: 4rem; } i.large { font-size: 6rem; } img.responsive-img, video.responsive-video { max-width: 100%; height: auto; } .pagination li { display: inline-block; border-radius: 2px; text-align: center; vertical-align: top; height: 30px; } .pagination li a { color: #444; display: inline-block; font-size: 1.2rem; padding: 0 10px; line-height: 30px; } .pagination li.active a { color: #fff; } .pagination li.active { background-color: #ee6e73; } .pagination li.disabled a { cursor: default; color: #999; } .pagination li i { font-size: 2rem; } .pagination li.pages ul li { display: inline-block; float: none; } @media only screen and (max-width: 992px) { .pagination { width: 100%; } .pagination li.prev, .pagination li.next { width: 10%; } .pagination li.pages { width: 80%; overflow: hidden; white-space: nowrap; } } .breadcrumb { font-size: 18px; color: rgba(255, 255, 255, 0.7); } .breadcrumb i, .breadcrumb [class^="mdi-"], .breadcrumb [class*="mdi-"], .breadcrumb i.material-icons { display: inline-block; float: left; font-size: 24px; } .breadcrumb:before { content: '\E5CC'; color: rgba(255, 255, 255, 0.7); vertical-align: top; display: inline-block; font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 25px; margin: 0 10px 0 8px; -webkit-font-smoothing: antialiased; } .breadcrumb:first-child:before { display: none; } .breadcrumb:last-child { color: #fff; } .parallax-container { position: relative; overflow: hidden; height: 500px; } .parallax-container .parallax { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; } .parallax-container .parallax img { opacity: 0; position: absolute; left: 50%; bottom: 0; min-width: 100%; min-height: 100%; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); -webkit-transform: translateX(-50%); transform: translateX(-50%); } .pin-top, .pin-bottom { position: relative; } .pinned { position: fixed !important; } /********************* Transition Classes **********************/ ul.staggered-list li { opacity: 0; } .fade-in { opacity: 0; -webkit-transform-origin: 0 50%; transform-origin: 0 50%; } /********************* Media Query Classes **********************/ @media only screen and (max-width: 600px) { .hide-on-small-only, .hide-on-small-and-down { display: none !important; } } @media only screen and (max-width: 992px) { .hide-on-med-and-down { display: none !important; } } @media only screen and (min-width: 601px) { .hide-on-med-and-up { display: none !important; } } @media only screen and (min-width: 600px) and (max-width: 992px) { .hide-on-med-only { display: none !important; } } @media only screen and (min-width: 993px) { .hide-on-large-only { display: none !important; } } @media only screen and (min-width: 1201px) { .hide-on-extra-large-only { display: none !important; } } @media only screen and (min-width: 1201px) { .show-on-extra-large { display: block !important; } } @media only screen and (min-width: 993px) { .show-on-large { display: block !important; } } @media only screen and (min-width: 600px) and (max-width: 992px) { .show-on-medium { display: block !important; } } @media only screen and (max-width: 600px) { .show-on-small { display: block !important; } } @media only screen and (min-width: 601px) { .show-on-medium-and-up { display: block !important; } } @media only screen and (max-width: 992px) { .show-on-medium-and-down { display: block !important; } } @media only screen and (max-width: 600px) { .center-on-small-only { text-align: center; } } .page-footer { padding-top: 20px; color: #fff; background-color: #ee6e73; } .page-footer .footer-copyright { overflow: hidden; min-height: 50px; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; padding: 10px 0px; color: rgba(255, 255, 255, 0.8); background-color: rgba(51, 51, 51, 0.08); } table, th, td { border: none; } table { width: 100%; display: table; border-collapse: collapse; border-spacing: 0; } table.striped tr { border-bottom: none; } table.striped > tbody > tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0.5); } table.striped > tbody > tr > td { border-radius: 0; } table.highlight > tbody > tr { -webkit-transition: background-color .25s ease; transition: background-color .25s ease; } table.highlight > tbody > tr:hover { background-color: rgba(242, 242, 242, 0.5); } table.centered thead tr th, table.centered tbody tr td { text-align: center; } tr { border-bottom: 1px solid rgba(0, 0, 0, 0.12); } td, th { padding: 15px 5px; display: table-cell; text-align: left; vertical-align: middle; border-radius: 2px; } @media only screen and (max-width: 992px) { table.responsive-table { width: 100%; border-collapse: collapse; border-spacing: 0; display: block; position: relative; /* sort out borders */ } table.responsive-table td:empty:before { content: '\00a0'; } table.responsive-table th, table.responsive-table td { margin: 0; vertical-align: top; } table.responsive-table th { text-align: left; } table.responsive-table thead { display: block; float: left; } table.responsive-table thead tr { display: block; padding: 0 10px 0 0; } table.responsive-table thead tr th::before { content: "\00a0"; } table.responsive-table tbody { display: block; width: auto; position: relative; overflow-x: auto; white-space: nowrap; } table.responsive-table tbody tr { display: inline-block; vertical-align: top; } table.responsive-table th { display: block; text-align: right; } table.responsive-table td { display: block; min-height: 1.25em; text-align: left; } table.responsive-table tr { border-bottom: none; padding: 0 10px; } table.responsive-table thead { border: 0; border-right: 1px solid rgba(0, 0, 0, 0.12); } } .collection { margin: 0.5rem 0 1rem 0; border: 1px solid #e0e0e0; border-radius: 2px; overflow: hidden; position: relative; } .collection .collection-item { background-color: #fff; line-height: 1.5rem; padding: 10px 20px; margin: 0; border-bottom: 1px solid #e0e0e0; } .collection .collection-item.avatar { min-height: 84px; padding-left: 72px; position: relative; } .collection .collection-item.avatar:not(.circle-clipper) > .circle, .collection .collection-item.avatar :not(.circle-clipper) > .circle { position: absolute; width: 42px; height: 42px; overflow: hidden; left: 15px; display: inline-block; vertical-align: middle; } .collection .collection-item.avatar i.circle { font-size: 18px; line-height: 42px; color: #fff; background-color: #999; text-align: center; } .collection .collection-item.avatar .title { font-size: 16px; } .collection .collection-item.avatar p { margin: 0; } .collection .collection-item.avatar .secondary-content { position: absolute; top: 16px; right: 16px; } .collection .collection-item:last-child { border-bottom: none; } .collection .collection-item.active { background-color: #26a69a; color: #eafaf9; } .collection .collection-item.active .secondary-content { color: #fff; } .collection a.collection-item { display: block; -webkit-transition: .25s; transition: .25s; color: #26a69a; } .collection a.collection-item:not(.active):hover { background-color: #ddd; } .collection.with-header .collection-header { background-color: #fff; border-bottom: 1px solid #e0e0e0; padding: 10px 20px; } .collection.with-header .collection-item { padding-left: 30px; } .collection.with-header .collection-item.avatar { padding-left: 72px; } .secondary-content { float: right; color: #26a69a; } .collapsible .collection { margin: 0; border: none; } .video-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; } .video-container iframe, .video-container object, .video-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .progress { position: relative; height: 4px; display: block; width: 100%; background-color: #acece6; border-radius: 2px; margin: 0.5rem 0 1rem 0; overflow: hidden; } .progress .determinate { position: absolute; top: 0; left: 0; bottom: 0; background-color: #26a69a; -webkit-transition: width .3s linear; transition: width .3s linear; } .progress .indeterminate { background-color: #26a69a; } .progress .indeterminate:before { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; } .progress .indeterminate:after { content: ''; position: absolute; background-color: inherit; top: 0; left: 0; bottom: 0; will-change: left, right; -webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; -webkit-animation-delay: 1.15s; animation-delay: 1.15s; } @-webkit-keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @keyframes indeterminate { 0% { left: -35%; right: 100%; } 60% { left: 100%; right: -90%; } 100% { left: 100%; right: -90%; } } @-webkit-keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } @keyframes indeterminate-short { 0% { left: -200%; right: 100%; } 60% { left: 107%; right: -8%; } 100% { left: 107%; right: -8%; } } /******************* Utility Classes *******************/ .hide { display: none !important; } .left-align { text-align: left; } .right-align { text-align: right; } .center, .center-align { text-align: center; } .left { float: left !important; } .right { float: right !important; } .no-select, input[type=range], input[type=range] + .thumb { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .circle { border-radius: 50%; } .center-block { display: block; margin-left: auto; margin-right: auto; } .truncate { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .no-padding { padding: 0 !important; } span.badge { min-width: 3rem; padding: 0 6px; margin-left: 14px; text-align: center; font-size: 1rem; line-height: 22px; height: 22px; color: #757575; float: right; -webkit-box-sizing: border-box; box-sizing: border-box; } span.badge.new { font-weight: 300; font-size: 0.8rem; color: #fff; background-color: #26a69a; border-radius: 2px; } span.badge.new:after { content: " new"; } span.badge[data-badge-caption]::after { content: " " attr(data-badge-caption); } nav ul a span.badge { display: inline-block; float: none; margin-left: 4px; line-height: 22px; height: 22px; -webkit-font-smoothing: auto; } .collection-item span.badge { margin-top: calc(0.75rem - 11px); } .collapsible span.badge { margin-left: auto; } .sidenav span.badge { margin-top: calc(24px - 11px); } table span.badge { display: inline-block; float: none; margin-left: auto; } /* This is needed for some mobile phones to display the Google Icon font properly */ .material-icons { text-rendering: optimizeLegibility; -webkit-font-feature-settings: 'liga'; -moz-font-feature-settings: 'liga'; font-feature-settings: 'liga'; } .container { margin: 0 auto; max-width: 1280px; width: 90%; } @media only screen and (min-width: 601px) { .container { width: 85%; } } @media only screen and (min-width: 993px) { .container { width: 70%; } } .col .row { margin-left: -0.75rem; margin-right: -0.75rem; } .section { padding-top: 1rem; padding-bottom: 1rem; } .section.no-pad { padding: 0; } .section.no-pad-bot { padding-bottom: 0; } .section.no-pad-top { padding-top: 0; } .row { margin-left: auto; margin-right: auto; margin-bottom: 20px; } .row:after { content: ""; display: table; clear: both; } .row .col { float: left; -webkit-box-sizing: border-box; box-sizing: border-box; padding: 0 0.75rem; min-height: 1px; } .row .col[class*="push-"], .row .col[class*="pull-"] { position: relative; } .row .col.s1 { width: 8.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.s2 { width: 16.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.s3 { width: 25%; margin-left: auto; left: auto; right: auto; } .row .col.s4 { width: 33.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.s5 { width: 41.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.s6 { width: 50%; margin-left: auto; left: auto; right: auto; } .row .col.s7 { width: 58.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.s8 { width: 66.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.s9 { width: 75%; margin-left: auto; left: auto; right: auto; } .row .col.s10 { width: 83.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.s11 { width: 91.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.s12 { width: 100%; margin-left: auto; left: auto; right: auto; } .row .col.offset-s1 { margin-left: 8.3333333333%; } .row .col.pull-s1 { right: 8.3333333333%; } .row .col.push-s1 { left: 8.3333333333%; } .row .col.offset-s2 { margin-left: 16.6666666667%; } .row .col.pull-s2 { right: 16.6666666667%; } .row .col.push-s2 { left: 16.6666666667%; } .row .col.offset-s3 { margin-left: 25%; } .row .col.pull-s3 { right: 25%; } .row .col.push-s3 { left: 25%; } .row .col.offset-s4 { margin-left: 33.3333333333%; } .row .col.pull-s4 { right: 33.3333333333%; } .row .col.push-s4 { left: 33.3333333333%; } .row .col.offset-s5 { margin-left: 41.6666666667%; } .row .col.pull-s5 { right: 41.6666666667%; } .row .col.push-s5 { left: 41.6666666667%; } .row .col.offset-s6 { margin-left: 50%; } .row .col.pull-s6 { right: 50%; } .row .col.push-s6 { left: 50%; } .row .col.offset-s7 { margin-left: 58.3333333333%; } .row .col.pull-s7 { right: 58.3333333333%; } .row .col.push-s7 { left: 58.3333333333%; } .row .col.offset-s8 { margin-left: 66.6666666667%; } .row .col.pull-s8 { right: 66.6666666667%; } .row .col.push-s8 { left: 66.6666666667%; } .row .col.offset-s9 { margin-left: 75%; } .row .col.pull-s9 { right: 75%; } .row .col.push-s9 { left: 75%; } .row .col.offset-s10 { margin-left: 83.3333333333%; } .row .col.pull-s10 { right: 83.3333333333%; } .row .col.push-s10 { left: 83.3333333333%; } .row .col.offset-s11 { margin-left: 91.6666666667%; } .row .col.pull-s11 { right: 91.6666666667%; } .row .col.push-s11 { left: 91.6666666667%; } .row .col.offset-s12 { margin-left: 100%; } .row .col.pull-s12 { right: 100%; } .row .col.push-s12 { left: 100%; } @media only screen and (min-width: 601px) { .row .col.m1 { width: 8.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.m2 { width: 16.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.m3 { width: 25%; margin-left: auto; left: auto; right: auto; } .row .col.m4 { width: 33.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.m5 { width: 41.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.m6 { width: 50%; margin-left: auto; left: auto; right: auto; } .row .col.m7 { width: 58.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.m8 { width: 66.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.m9 { width: 75%; margin-left: auto; left: auto; right: auto; } .row .col.m10 { width: 83.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.m11 { width: 91.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.m12 { width: 100%; margin-left: auto; left: auto; right: auto; } .row .col.offset-m1 { margin-left: 8.3333333333%; } .row .col.pull-m1 { right: 8.3333333333%; } .row .col.push-m1 { left: 8.3333333333%; } .row .col.offset-m2 { margin-left: 16.6666666667%; } .row .col.pull-m2 { right: 16.6666666667%; } .row .col.push-m2 { left: 16.6666666667%; } .row .col.offset-m3 { margin-left: 25%; } .row .col.pull-m3 { right: 25%; } .row .col.push-m3 { left: 25%; } .row .col.offset-m4 { margin-left: 33.3333333333%; } .row .col.pull-m4 { right: 33.3333333333%; } .row .col.push-m4 { left: 33.3333333333%; } .row .col.offset-m5 { margin-left: 41.6666666667%; } .row .col.pull-m5 { right: 41.6666666667%; } .row .col.push-m5 { left: 41.6666666667%; } .row .col.offset-m6 { margin-left: 50%; } .row .col.pull-m6 { right: 50%; } .row .col.push-m6 { left: 50%; } .row .col.offset-m7 { margin-left: 58.3333333333%; } .row .col.pull-m7 { right: 58.3333333333%; } .row .col.push-m7 { left: 58.3333333333%; } .row .col.offset-m8 { margin-left: 66.6666666667%; } .row .col.pull-m8 { right: 66.6666666667%; } .row .col.push-m8 { left: 66.6666666667%; } .row .col.offset-m9 { margin-left: 75%; } .row .col.pull-m9 { right: 75%; } .row .col.push-m9 { left: 75%; } .row .col.offset-m10 { margin-left: 83.3333333333%; } .row .col.pull-m10 { right: 83.3333333333%; } .row .col.push-m10 { left: 83.3333333333%; } .row .col.offset-m11 { margin-left: 91.6666666667%; } .row .col.pull-m11 { right: 91.6666666667%; } .row .col.push-m11 { left: 91.6666666667%; } .row .col.offset-m12 { margin-left: 100%; } .row .col.pull-m12 { right: 100%; } .row .col.push-m12 { left: 100%; } } @media only screen and (min-width: 993px) { .row .col.l1 { width: 8.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.l2 { width: 16.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.l3 { width: 25%; margin-left: auto; left: auto; right: auto; } .row .col.l4 { width: 33.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.l5 { width: 41.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.l6 { width: 50%; margin-left: auto; left: auto; right: auto; } .row .col.l7 { width: 58.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.l8 { width: 66.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.l9 { width: 75%; margin-left: auto; left: auto; right: auto; } .row .col.l10 { width: 83.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.l11 { width: 91.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.l12 { width: 100%; margin-left: auto; left: auto; right: auto; } .row .col.offset-l1 { margin-left: 8.3333333333%; } .row .col.pull-l1 { right: 8.3333333333%; } .row .col.push-l1 { left: 8.3333333333%; } .row .col.offset-l2 { margin-left: 16.6666666667%; } .row .col.pull-l2 { right: 16.6666666667%; } .row .col.push-l2 { left: 16.6666666667%; } .row .col.offset-l3 { margin-left: 25%; } .row .col.pull-l3 { right: 25%; } .row .col.push-l3 { left: 25%; } .row .col.offset-l4 { margin-left: 33.3333333333%; } .row .col.pull-l4 { right: 33.3333333333%; } .row .col.push-l4 { left: 33.3333333333%; } .row .col.offset-l5 { margin-left: 41.6666666667%; } .row .col.pull-l5 { right: 41.6666666667%; } .row .col.push-l5 { left: 41.6666666667%; } .row .col.offset-l6 { margin-left: 50%; } .row .col.pull-l6 { right: 50%; } .row .col.push-l6 { left: 50%; } .row .col.offset-l7 { margin-left: 58.3333333333%; } .row .col.pull-l7 { right: 58.3333333333%; } .row .col.push-l7 { left: 58.3333333333%; } .row .col.offset-l8 { margin-left: 66.6666666667%; } .row .col.pull-l8 { right: 66.6666666667%; } .row .col.push-l8 { left: 66.6666666667%; } .row .col.offset-l9 { margin-left: 75%; } .row .col.pull-l9 { right: 75%; } .row .col.push-l9 { left: 75%; } .row .col.offset-l10 { margin-left: 83.3333333333%; } .row .col.pull-l10 { right: 83.3333333333%; } .row .col.push-l10 { left: 83.3333333333%; } .row .col.offset-l11 { margin-left: 91.6666666667%; } .row .col.pull-l11 { right: 91.6666666667%; } .row .col.push-l11 { left: 91.6666666667%; } .row .col.offset-l12 { margin-left: 100%; } .row .col.pull-l12 { right: 100%; } .row .col.push-l12 { left: 100%; } } @media only screen and (min-width: 1201px) { .row .col.xl1 { width: 8.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.xl2 { width: 16.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.xl3 { width: 25%; margin-left: auto; left: auto; right: auto; } .row .col.xl4 { width: 33.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.xl5 { width: 41.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.xl6 { width: 50%; margin-left: auto; left: auto; right: auto; } .row .col.xl7 { width: 58.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.xl8 { width: 66.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.xl9 { width: 75%; margin-left: auto; left: auto; right: auto; } .row .col.xl10 { width: 83.3333333333%; margin-left: auto; left: auto; right: auto; } .row .col.xl11 { width: 91.6666666667%; margin-left: auto; left: auto; right: auto; } .row .col.xl12 { width: 100%; margin-left: auto; left: auto; right: auto; } .row .col.offset-xl1 { margin-left: 8.3333333333%; } .row .col.pull-xl1 { right: 8.3333333333%; } .row .col.push-xl1 { left: 8.3333333333%; } .row .col.offset-xl2 { margin-left: 16.6666666667%; } .row .col.pull-xl2 { right: 16.6666666667%; } .row .col.push-xl2 { left: 16.6666666667%; } .row .col.offset-xl3 { margin-left: 25%; } .row .col.pull-xl3 { right: 25%; } .row .col.push-xl3 { left: 25%; } .row .col.offset-xl4 { margin-left: 33.3333333333%; } .row .col.pull-xl4 { right: 33.3333333333%; } .row .col.push-xl4 { left: 33.3333333333%; } .row .col.offset-xl5 { margin-left: 41.6666666667%; } .row .col.pull-xl5 { right: 41.6666666667%; } .row .col.push-xl5 { left: 41.6666666667%; } .row .col.offset-xl6 { margin-left: 50%; } .row .col.pull-xl6 { right: 50%; } .row .col.push-xl6 { left: 50%; } .row .col.offset-xl7 { margin-left: 58.3333333333%; } .row .col.pull-xl7 { right: 58.3333333333%; } .row .col.push-xl7 { left: 58.3333333333%; } .row .col.offset-xl8 { margin-left: 66.6666666667%; } .row .col.pull-xl8 { right: 66.6666666667%; } .row .col.push-xl8 { left: 66.6666666667%; } .row .col.offset-xl9 { margin-left: 75%; } .row .col.pull-xl9 { right: 75%; } .row .col.push-xl9 { left: 75%; } .row .col.offset-xl10 { margin-left: 83.3333333333%; } .row .col.pull-xl10 { right: 83.3333333333%; } .row .col.push-xl10 { left: 83.3333333333%; } .row .col.offset-xl11 { margin-left: 91.6666666667%; } .row .col.pull-xl11 { right: 91.6666666667%; } .row .col.push-xl11 { left: 91.6666666667%; } .row .col.offset-xl12 { margin-left: 100%; } .row .col.pull-xl12 { right: 100%; } .row .col.push-xl12 { left: 100%; } } nav { color: #fff; background-color: #ee6e73; width: 100%; height: 56px; line-height: 56px; } nav.nav-extended { height: auto; } nav.nav-extended .nav-wrapper { min-height: 56px; height: auto; } nav.nav-extended .nav-content { position: relative; line-height: normal; } nav a { color: #fff; } nav i, nav [class^="mdi-"], nav [class*="mdi-"], nav i.material-icons { display: block; font-size: 24px; height: 56px; line-height: 56px; } nav .nav-wrapper { position: relative; height: 100%; } @media only screen and (min-width: 993px) { nav a.sidenav-trigger { display: none; } } nav .sidenav-trigger { float: left; position: relative; z-index: 1; height: 56px; margin: 0 18px; } nav .sidenav-trigger i { height: 56px; line-height: 56px; } nav .brand-logo { position: absolute; color: #fff; display: inline-block; font-size: 2.1rem; padding: 0; } nav .brand-logo.center { left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); } @media only screen and (max-width: 992px) { nav .brand-logo { left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); } nav .brand-logo.left, nav .brand-logo.right { padding: 0; -webkit-transform: none; transform: none; } nav .brand-logo.left { left: 0.5rem; } nav .brand-logo.right { right: 0.5rem; left: auto; } } nav .brand-logo.right { right: 0.5rem; padding: 0; } nav .brand-logo i, nav .brand-logo [class^="mdi-"], nav .brand-logo [class*="mdi-"], nav .brand-logo i.material-icons { float: left; margin-right: 15px; } nav .nav-title { display: inline-block; font-size: 32px; padding: 28px 0; } nav ul { margin: 0; } nav ul li { -webkit-transition: background-color .3s; transition: background-color .3s; float: left; padding: 0; } nav ul li.active { background-color: rgba(0, 0, 0, 0.1); } nav ul a { -webkit-transition: background-color .3s; transition: background-color .3s; font-size: 1rem; color: #fff; display: block; padding: 0 15px; cursor: pointer; } nav ul a.btn, nav ul a.btn-large, nav ul a.btn-small, nav ul a.btn-large, nav ul a.btn-flat, nav ul a.btn-floating { margin-top: -2px; margin-left: 15px; margin-right: 15px; } nav ul a.btn > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-small > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-flat > .material-icons, nav ul a.btn-floating > .material-icons { height: inherit; line-height: inherit; } nav ul a:hover { background-color: rgba(0, 0, 0, 0.1); } nav ul.left { float: left; } nav form { height: 100%; } nav .input-field { margin: 0; height: 100%; } nav .input-field input { height: 100%; font-size: 1.2rem; border: none; padding-left: 2rem; } nav .input-field input:focus, nav .input-field input[type=text]:valid, nav .input-field input[type=password]:valid, nav .input-field input[type=email]:valid, nav .input-field input[type=url]:valid, nav .input-field input[type=date]:valid { border: none; -webkit-box-shadow: none; box-shadow: none; } nav .input-field label { top: 0; left: 0; } nav .input-field label i { color: rgba(255, 255, 255, 0.7); -webkit-transition: color .3s; transition: color .3s; } nav .input-field label.active i { color: #fff; } .navbar-fixed { position: relative; height: 56px; z-index: 997; } .navbar-fixed nav { position: fixed; } @media only screen and (min-width: 601px) { nav.nav-extended .nav-wrapper { min-height: 64px; } nav, nav .nav-wrapper i, nav a.sidenav-trigger, nav a.sidenav-trigger i { height: 64px; line-height: 64px; } .navbar-fixed { height: 64px; } } a { text-decoration: none; } html { line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-weight: normal; color: rgba(0, 0, 0, 0.87); } @media only screen and (min-width: 0) { html { font-size: 14px; } } @media only screen and (min-width: 992px) { html { font-size: 14.5px; } } @media only screen and (min-width: 1200px) { html { font-size: 15px; } } h1, h2, h3, h4, h5, h6 { font-weight: 400; line-height: 1.3; } h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } h1 { font-size: 4.2rem; line-height: 110%; margin: 2.8rem 0 1.68rem 0; } h2 { font-size: 3.56rem; line-height: 110%; margin: 2.3733333333rem 0 1.424rem 0; } h3 { font-size: 2.92rem; line-height: 110%; margin: 1.9466666667rem 0 1.168rem 0; } h4 { font-size: 2.28rem; line-height: 110%; margin: 1.52rem 0 0.912rem 0; } h5 { font-size: 1.64rem; line-height: 110%; margin: 1.0933333333rem 0 0.656rem 0; } h6 { font-size: 1.15rem; line-height: 110%; margin: 0.7666666667rem 0 0.46rem 0; } em { font-style: italic; } strong { font-weight: 500; } small { font-size: 75%; } .light { font-weight: 300; } .thin { font-weight: 200; } @media only screen and (min-width: 360px) { .flow-text { font-size: 1.2rem; } } @media only screen and (min-width: 390px) { .flow-text { font-size: 1.224rem; } } @media only screen and (min-width: 420px) { .flow-text { font-size: 1.248rem; } } @media only screen and (min-width: 450px) { .flow-text { font-size: 1.272rem; } } @media only screen and (min-width: 480px) { .flow-text { font-size: 1.296rem; } } @media only screen and (min-width: 510px) { .flow-text { font-size: 1.32rem; } } @media only screen and (min-width: 540px) { .flow-text { font-size: 1.344rem; } } @media only screen and (min-width: 570px) { .flow-text { font-size: 1.368rem; } } @media only screen and (min-width: 600px) { .flow-text { font-size: 1.392rem; } } @media only screen and (min-width: 630px) { .flow-text { font-size: 1.416rem; } } @media only screen and (min-width: 660px) { .flow-text { font-size: 1.44rem; } } @media only screen and (min-width: 690px) { .flow-text { font-size: 1.464rem; } } @media only screen and (min-width: 720px) { .flow-text { font-size: 1.488rem; } } @media only screen and (min-width: 750px) { .flow-text { font-size: 1.512rem; } } @media only screen and (min-width: 780px) { .flow-text { font-size: 1.536rem; } } @media only screen and (min-width: 810px) { .flow-text { font-size: 1.56rem; } } @media only screen and (min-width: 840px) { .flow-text { font-size: 1.584rem; } } @media only screen and (min-width: 870px) { .flow-text { font-size: 1.608rem; } } @media only screen and (min-width: 900px) { .flow-text { font-size: 1.632rem; } } @media only screen and (min-width: 930px) { .flow-text { font-size: 1.656rem; } } @media only screen and (min-width: 960px) { .flow-text { font-size: 1.68rem; } } @media only screen and (max-width: 360px) { .flow-text { font-size: 1.2rem; } } .scale-transition { -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; transition: -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63), -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; } .scale-transition.scale-out { -webkit-transform: scale(0); transform: scale(0); -webkit-transition: -webkit-transform .2s !important; transition: -webkit-transform .2s !important; transition: transform .2s !important; transition: transform .2s, -webkit-transform .2s !important; } .scale-transition.scale-in { -webkit-transform: scale(1); transform: scale(1); } .card-panel { -webkit-transition: -webkit-box-shadow .25s; transition: -webkit-box-shadow .25s; transition: box-shadow .25s; transition: box-shadow .25s, -webkit-box-shadow .25s; padding: 24px; margin: 0.5rem 0 1rem 0; border-radius: 2px; background-color: #fff; } .card { position: relative; margin: 0.5rem 0 1rem 0; background-color: #fff; -webkit-transition: -webkit-box-shadow .25s; transition: -webkit-box-shadow .25s; transition: box-shadow .25s; transition: box-shadow .25s, -webkit-box-shadow .25s; border-radius: 2px; } .card .card-title { font-size: 24px; font-weight: 300; } .card .card-title.activator { cursor: pointer; } .card.small, .card.medium, .card.large { position: relative; } .card.small .card-image, .card.medium .card-image, .card.large .card-image { max-height: 60%; overflow: hidden; } .card.small .card-image + .card-content, .card.medium .card-image + .card-content, .card.large .card-image + .card-content { max-height: 40%; } .card.small .card-content, .card.medium .card-content, .card.large .card-content { max-height: 100%; overflow: hidden; } .card.small .card-action, .card.medium .card-action, .card.large .card-action { position: absolute; bottom: 0; left: 0; right: 0; } .card.small { height: 300px; } .card.medium { height: 400px; } .card.large { height: 500px; } .card.horizontal { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } .card.horizontal.small .card-image, .card.horizontal.medium .card-image, .card.horizontal.large .card-image { height: 100%; max-height: none; overflow: visible; } .card.horizontal.small .card-image img, .card.horizontal.medium .card-image img, .card.horizontal.large .card-image img { height: 100%; } .card.horizontal .card-image { max-width: 50%; } .card.horizontal .card-image img { border-radius: 2px 0 0 2px; max-width: 100%; width: auto; } .card.horizontal .card-stacked { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; -webkit-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; position: relative; } .card.horizontal .card-stacked .card-content { -webkit-box-flex: 1; -webkit-flex-grow: 1; -ms-flex-positive: 1; flex-grow: 1; } .card.sticky-action .card-action { z-index: 2; } .card.sticky-action .card-reveal { z-index: 1; padding-bottom: 64px; } .card .card-image { position: relative; } .card .card-image img { display: block; border-radius: 2px 2px 0 0; position: relative; left: 0; right: 0; top: 0; bottom: 0; width: 100%; } .card .card-image .card-title { color: #fff; position: absolute; bottom: 0; left: 0; max-width: 100%; padding: 24px; } .card .card-content { padding: 24px; border-radius: 0 0 2px 2px; } .card .card-content p { margin: 0; } .card .card-content .card-title { display: block; line-height: 32px; margin-bottom: 8px; } .card .card-content .card-title i { line-height: 32px; } .card .card-action { background-color: inherit; border-top: 1px solid rgba(160, 160, 160, 0.2); position: relative; padding: 16px 24px; } .card .card-action:last-child { border-radius: 0 0 2px 2px; } .card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating) { color: #ffab40; margin-right: 24px; -webkit-transition: color .3s ease; transition: color .3s ease; text-transform: uppercase; } .card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating):hover { color: #ffd8a6; } .card .card-reveal { padding: 24px; position: absolute; background-color: #fff; width: 100%; overflow-y: auto; left: 0; top: 100%; height: 100%; z-index: 3; display: none; } .card .card-reveal .card-title { cursor: pointer; display: block; } #toast-container { display: block; position: fixed; z-index: 10000; } @media only screen and (max-width: 600px) { #toast-container { min-width: 100%; bottom: 0%; } } @media only screen and (min-width: 601px) and (max-width: 992px) { #toast-container { left: 5%; bottom: 7%; max-width: 90%; } } @media only screen and (min-width: 993px) { #toast-container { top: 10%; right: 7%; max-width: 86%; } } .toast { border-radius: 2px; top: 35px; width: auto; margin-top: 10px; position: relative; max-width: 100%; height: auto; min-height: 48px; line-height: 1.5em; background-color: #323232; padding: 10px 25px; font-size: 1.1rem; font-weight: 300; color: #fff; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; cursor: default; } .toast .toast-action { color: #eeff41; font-weight: 500; margin-right: -25px; margin-left: 3rem; } .toast.rounded { border-radius: 24px; } @media only screen and (max-width: 600px) { .toast { width: 100%; border-radius: 0; } } .tabs { position: relative; overflow-x: auto; overflow-y: hidden; height: 48px; width: 100%; background-color: #fff; margin: 0 auto; white-space: nowrap; } .tabs.tabs-transparent { background-color: transparent; } .tabs.tabs-transparent .tab a, .tabs.tabs-transparent .tab.disabled a, .tabs.tabs-transparent .tab.disabled a:hover { color: rgba(255, 255, 255, 0.7); } .tabs.tabs-transparent .tab a:hover, .tabs.tabs-transparent .tab a.active { color: #fff; } .tabs.tabs-transparent .indicator { background-color: #fff; } .tabs.tabs-fixed-width { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } .tabs.tabs-fixed-width .tab { -webkit-box-flex: 1; -webkit-flex-grow: 1; -ms-flex-positive: 1; flex-grow: 1; } .tabs .tab { display: inline-block; text-align: center; line-height: 48px; height: 48px; padding: 0; margin: 0; text-transform: uppercase; } .tabs .tab a { color: rgba(238, 110, 115, 0.7); display: block; width: 100%; height: 100%; padding: 0 24px; font-size: 14px; text-overflow: ellipsis; overflow: hidden; -webkit-transition: color .28s ease, background-color .28s ease; transition: color .28s ease, background-color .28s ease; } .tabs .tab a:focus, .tabs .tab a:focus.active { background-color: rgba(246, 178, 181, 0.2); outline: none; } .tabs .tab a:hover, .tabs .tab a.active { background-color: transparent; color: #ee6e73; } .tabs .tab.disabled a, .tabs .tab.disabled a:hover { color: rgba(238, 110, 115, 0.4); cursor: default; } .tabs .indicator { position: absolute; bottom: 0; height: 2px; background-color: #f6b2b5; will-change: left, right; } @media only screen and (max-width: 992px) { .tabs { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } .tabs .tab { -webkit-box-flex: 1; -webkit-flex-grow: 1; -ms-flex-positive: 1; flex-grow: 1; } .tabs .tab a { padding: 0 12px; } } .material-tooltip { padding: 10px 8px; font-size: 1rem; z-index: 2000; background-color: transparent; border-radius: 2px; color: #fff; min-height: 36px; line-height: 120%; opacity: 0; position: absolute; text-align: center; max-width: calc(100% - 4px); overflow: hidden; left: 0; top: 0; pointer-events: none; visibility: hidden; background-color: #323232; } .backdrop { position: absolute; opacity: 0; height: 7px; width: 14px; border-radius: 0 0 50% 50%; background-color: #323232; z-index: -1; -webkit-transform-origin: 50% 0%; transform-origin: 50% 0%; visibility: hidden; } .btn, .btn-large, .btn-small, .btn-flat { border: none; border-radius: 2px; display: inline-block; height: 36px; line-height: 36px; padding: 0 16px; text-transform: uppercase; vertical-align: middle; -webkit-tap-highlight-color: transparent; } .btn.disabled, .disabled.btn-large, .disabled.btn-small, .btn-floating.disabled, .btn-large.disabled, .btn-small.disabled, .btn-flat.disabled, .btn:disabled, .btn-large:disabled, .btn-small:disabled, .btn-floating:disabled, .btn-large:disabled, .btn-small:disabled, .btn-flat:disabled, .btn[disabled], .btn-large[disabled], .btn-small[disabled], .btn-floating[disabled], .btn-large[disabled], .btn-small[disabled], .btn-flat[disabled] { pointer-events: none; background-color: #DFDFDF !important; -webkit-box-shadow: none; box-shadow: none; color: #9F9F9F !important; cursor: default; } .btn.disabled:hover, .disabled.btn-large:hover, .disabled.btn-small:hover, .btn-floating.disabled:hover, .btn-large.disabled:hover, .btn-small.disabled:hover, .btn-flat.disabled:hover, .btn:disabled:hover, .btn-large:disabled:hover, .btn-small:disabled:hover, .btn-floating:disabled:hover, .btn-large:disabled:hover, .btn-small:disabled:hover, .btn-flat:disabled:hover, .btn[disabled]:hover, .btn-large[disabled]:hover, .btn-small[disabled]:hover, .btn-floating[disabled]:hover, .btn-large[disabled]:hover, .btn-small[disabled]:hover, .btn-flat[disabled]:hover { background-color: #DFDFDF !important; color: #9F9F9F !important; } .btn, .btn-large, .btn-small, .btn-floating, .btn-large, .btn-small, .btn-flat { font-size: 14px; outline: 0; } .btn i, .btn-large i, .btn-small i, .btn-floating i, .btn-large i, .btn-small i, .btn-flat i { font-size: 1.3rem; line-height: inherit; } .btn:focus, .btn-large:focus, .btn-small:focus, .btn-floating:focus { background-color: #1d7d74; } .btn, .btn-large, .btn-small { text-decoration: none; color: #fff; background-color: #26a69a; text-align: center; letter-spacing: .5px; -webkit-transition: background-color .2s ease-out; transition: background-color .2s ease-out; cursor: pointer; } .btn:hover, .btn-large:hover, .btn-small:hover { background-color: #2bbbad; } .btn-floating { display: inline-block; color: #fff; position: relative; overflow: hidden; z-index: 1; width: 40px; height: 40px; line-height: 40px; padding: 0; background-color: #26a69a; border-radius: 50%; -webkit-transition: background-color .3s; transition: background-color .3s; cursor: pointer; vertical-align: middle; } .btn-floating:hover { background-color: #26a69a; } .btn-floating:before { border-radius: 0; } .btn-floating.btn-large { width: 56px; height: 56px; padding: 0; } .btn-floating.btn-large.halfway-fab { bottom: -28px; } .btn-floating.btn-large i { line-height: 56px; } .btn-floating.btn-small { width: 32.4px; height: 32.4px; } .btn-floating.btn-small.halfway-fab { bottom: -16.2px; } .btn-floating.btn-small i { line-height: 32.4px; } .btn-floating.halfway-fab { position: absolute; right: 24px; bottom: -20px; } .btn-floating.halfway-fab.left { right: auto; left: 24px; } .btn-floating i { width: inherit; display: inline-block; text-align: center; color: #fff; font-size: 1.6rem; line-height: 40px; } button.btn-floating { border: none; } .fixed-action-btn { position: fixed; right: 23px; bottom: 23px; padding-top: 15px; margin-bottom: 0; z-index: 997; } .fixed-action-btn.active ul { visibility: visible; } .fixed-action-btn.direction-left, .fixed-action-btn.direction-right { padding: 0 0 0 15px; } .fixed-action-btn.direction-left ul, .fixed-action-btn.direction-right ul { text-align: right; right: 64px; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); height: 100%; left: auto; /*width 100% only goes to width of button container */ width: 500px; } .fixed-action-btn.direction-left ul li, .fixed-action-btn.direction-right ul li { display: inline-block; margin: 7.5px 15px 0 0; } .fixed-action-btn.direction-right { padding: 0 15px 0 0; } .fixed-action-btn.direction-right ul { text-align: left; direction: rtl; left: 64px; right: auto; } .fixed-action-btn.direction-right ul li { margin: 7.5px 0 0 15px; } .fixed-action-btn.direction-bottom { padding: 0 0 15px 0; } .fixed-action-btn.direction-bottom ul { top: 64px; bottom: auto; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: reverse; -webkit-flex-direction: column-reverse; -ms-flex-direction: column-reverse; flex-direction: column-reverse; } .fixed-action-btn.direction-bottom ul li { margin: 15px 0 0 0; } .fixed-action-btn.toolbar { padding: 0; height: 56px; } .fixed-action-btn.toolbar.active > a i { opacity: 0; } .fixed-action-btn.toolbar ul { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; top: 0; bottom: 0; z-index: 1; } .fixed-action-btn.toolbar ul li { -webkit-box-flex: 1; -webkit-flex: 1; -ms-flex: 1; flex: 1; display: inline-block; margin: 0; height: 100%; -webkit-transition: none; transition: none; } .fixed-action-btn.toolbar ul li a { display: block; overflow: hidden; position: relative; width: 100%; height: 100%; background-color: transparent; -webkit-box-shadow: none; box-shadow: none; color: #fff; line-height: 56px; z-index: 1; } .fixed-action-btn.toolbar ul li a i { line-height: inherit; } .fixed-action-btn ul { left: 0; right: 0; text-align: center; position: absolute; bottom: 64px; margin: 0; visibility: hidden; } .fixed-action-btn ul li { margin-bottom: 15px; } .fixed-action-btn ul a.btn-floating { opacity: 0; } .fixed-action-btn .fab-backdrop { position: absolute; top: 0; left: 0; z-index: -1; width: 40px; height: 40px; background-color: #26a69a; border-radius: 50%; -webkit-transform: scale(0); transform: scale(0); } .btn-flat { -webkit-box-shadow: none; box-shadow: none; background-color: transparent; color: #343434; cursor: pointer; -webkit-transition: background-color .2s; transition: background-color .2s; } .btn-flat:focus, .btn-flat:hover { -webkit-box-shadow: none; box-shadow: none; } .btn-flat:focus { background-color: rgba(0, 0, 0, 0.1); } .btn-flat.disabled, .btn-flat.btn-flat[disabled] { background-color: transparent !important; color: #b3b2b2 !important; cursor: default; } .btn-large { height: 54px; line-height: 54px; font-size: 15px; padding: 0 28px; } .btn-large i { font-size: 1.6rem; } .btn-small { height: 32.4px; line-height: 32.4px; font-size: 13px; } .btn-small i { font-size: 1.2rem; } .btn-block { display: block; } .dropdown-content { background-color: #fff; margin: 0; display: none; min-width: 100px; overflow-y: auto; opacity: 0; position: absolute; left: 0; top: 0; z-index: 9999; -webkit-transform-origin: 0 0; transform-origin: 0 0; } .dropdown-content:focus { outline: 0; } .dropdown-content li { clear: both; color: rgba(0, 0, 0, 0.87); cursor: pointer; min-height: 50px; line-height: 1.5rem; width: 100%; text-align: left; } .dropdown-content li:hover, .dropdown-content li.active { background-color: #eee; } .dropdown-content li:focus { outline: none; } .dropdown-content li.divider { min-height: 0; height: 1px; } .dropdown-content li > a, .dropdown-content li > span { font-size: 16px; color: #26a69a; display: block; line-height: 22px; padding: 14px 16px; } .dropdown-content li > span > label { top: 1px; left: 0; height: 18px; } .dropdown-content li > a > i { height: inherit; line-height: inherit; float: left; margin: 0 24px 0 0; width: 24px; } body.keyboard-focused .dropdown-content li:focus { background-color: #dadada; } .input-field.col .dropdown-content [type="checkbox"] + label { top: 1px; left: 0; height: 18px; -webkit-transform: none; transform: none; } .dropdown-trigger { cursor: pointer; } /*! * Waves v0.6.0 * http://fian.my.id/Waves * * Copyright 2014 Alfiana E. Sibuea and other contributors * Released under the MIT license * https://github.com/fians/Waves/blob/master/LICENSE */ .waves-effect { position: relative; cursor: pointer; display: inline-block; overflow: hidden; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; vertical-align: middle; z-index: 1; -webkit-transition: .3s ease-out; transition: .3s ease-out; } .waves-effect .waves-ripple { position: absolute; border-radius: 50%; width: 20px; height: 20px; margin-top: -10px; margin-left: -10px; opacity: 0; background: rgba(0, 0, 0, 0.2); -webkit-transition: all 0.7s ease-out; transition: all 0.7s ease-out; -webkit-transition-property: opacity, -webkit-transform; transition-property: opacity, -webkit-transform; transition-property: transform, opacity; transition-property: transform, opacity, -webkit-transform; -webkit-transform: scale(0); transform: scale(0); pointer-events: none; } .waves-effect.waves-light .waves-ripple { background-color: rgba(255, 255, 255, 0.45); } .waves-effect.waves-red .waves-ripple { background-color: rgba(244, 67, 54, 0.7); } .waves-effect.waves-yellow .waves-ripple { background-color: rgba(255, 235, 59, 0.7); } .waves-effect.waves-orange .waves-ripple { background-color: rgba(255, 152, 0, 0.7); } .waves-effect.waves-purple .waves-ripple { background-color: rgba(156, 39, 176, 0.7); } .waves-effect.waves-green .waves-ripple { background-color: rgba(76, 175, 80, 0.7); } .waves-effect.waves-teal .waves-ripple { background-color: rgba(0, 150, 136, 0.7); } .waves-effect input[type="button"], .waves-effect input[type="reset"], .waves-effect input[type="submit"] { border: 0; font-style: normal; font-size: inherit; text-transform: inherit; background: none; } .waves-effect img { position: relative; z-index: -1; } .waves-notransition { -webkit-transition: none !important; transition: none !important; } .waves-circle { -webkit-transform: translateZ(0); transform: translateZ(0); -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); } .waves-input-wrapper { border-radius: 0.2em; vertical-align: bottom; } .waves-input-wrapper .waves-button-input { position: relative; top: 0; left: 0; z-index: 1; } .waves-circle { text-align: center; width: 2.5em; height: 2.5em; line-height: 2.5em; border-radius: 50%; -webkit-mask-image: none; } .waves-block { display: block; } /* Firefox Bug: link not triggered */ .waves-effect .waves-ripple { z-index: -1; } .modal { display: none; position: fixed; left: 0; right: 0; background-color: #fafafa; padding: 0; max-height: 70%; width: 55%; margin: auto; overflow-y: auto; border-radius: 2px; will-change: top, opacity; } .modal:focus { outline: none; } @media only screen and (max-width: 992px) { .modal { width: 80%; } } .modal h1, .modal h2, .modal h3, .modal h4 { margin-top: 0; } .modal .modal-content { padding: 24px; } .modal .modal-close { cursor: pointer; } .modal .modal-footer { border-radius: 0 0 2px 2px; background-color: #fafafa; padding: 4px 6px; height: 56px; width: 100%; text-align: right; } .modal .modal-footer .btn, .modal .modal-footer .btn-large, .modal .modal-footer .btn-small, .modal .modal-footer .btn-flat { margin: 6px 0; } .modal-overlay { position: fixed; z-index: 999; top: -25%; left: 0; bottom: 0; right: 0; height: 125%; width: 100%; background: #000; display: none; will-change: opacity; } .modal.modal-fixed-footer { padding: 0; height: 70%; } .modal.modal-fixed-footer .modal-content { position: absolute; height: calc(100% - 56px); max-height: 100%; width: 100%; overflow-y: auto; } .modal.modal-fixed-footer .modal-footer { border-top: 1px solid rgba(0, 0, 0, 0.1); position: absolute; bottom: 0; } .modal.bottom-sheet { top: auto; bottom: -100%; margin: 0; width: 100%; max-height: 45%; border-radius: 0; will-change: bottom, opacity; } .collapsible { border-top: 1px solid #ddd; border-right: 1px solid #ddd; border-left: 1px solid #ddd; margin: 0.5rem 0 1rem 0; } .collapsible-header { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; cursor: pointer; -webkit-tap-highlight-color: transparent; line-height: 1.5; padding: 1rem; background-color: #fff; border-bottom: 1px solid #ddd; } .collapsible-header:focus { outline: 0; } .collapsible-header i { width: 2rem; font-size: 1.6rem; display: inline-block; text-align: center; margin-right: 1rem; } .keyboard-focused .collapsible-header:focus { background-color: #eee; } .collapsible-body { display: none; border-bottom: 1px solid #ddd; -webkit-box-sizing: border-box; box-sizing: border-box; padding: 2rem; } .sidenav .collapsible, .sidenav.fixed .collapsible { border: none; -webkit-box-shadow: none; box-shadow: none; } .sidenav .collapsible li, .sidenav.fixed .collapsible li { padding: 0; } .sidenav .collapsible-header, .sidenav.fixed .collapsible-header { background-color: transparent; border: none; line-height: inherit; height: inherit; padding: 0 16px; } .sidenav .collapsible-header:hover, .sidenav.fixed .collapsible-header:hover { background-color: rgba(0, 0, 0, 0.05); } .sidenav .collapsible-header i, .sidenav.fixed .collapsible-header i { line-height: inherit; } .sidenav .collapsible-body, .sidenav.fixed .collapsible-body { border: 0; background-color: #fff; } .sidenav .collapsible-body li a, .sidenav.fixed .collapsible-body li a { padding: 0 23.5px 0 31px; } .collapsible.popout { border: none; -webkit-box-shadow: none; box-shadow: none; } .collapsible.popout > li { -webkit-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); margin: 0 24px; -webkit-transition: margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); transition: margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); } .collapsible.popout > li.active { -webkit-box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); margin: 16px 0; } .chip { display: inline-block; height: 32px; font-size: 13px; font-weight: 500; color: rgba(0, 0, 0, 0.6); line-height: 32px; padding: 0 12px; border-radius: 16px; background-color: #e4e4e4; margin-bottom: 5px; margin-right: 5px; } .chip:focus { outline: none; background-color: #26a69a; color: #fff; } .chip > img { float: left; margin: 0 8px 0 -12px; height: 32px; width: 32px; border-radius: 50%; } .chip .close { cursor: pointer; float: right; font-size: 16px; line-height: 32px; padding-left: 8px; } .chips { border: none; border-bottom: 1px solid #9e9e9e; -webkit-box-shadow: none; box-shadow: none; margin: 0 0 8px 0; min-height: 45px; outline: none; -webkit-transition: all .3s; transition: all .3s; } .chips.focus { border-bottom: 1px solid #26a69a; -webkit-box-shadow: 0 1px 0 0 #26a69a; box-shadow: 0 1px 0 0 #26a69a; } .chips:hover { cursor: text; } .chips .input { background: none; border: 0; color: rgba(0, 0, 0, 0.6); display: inline-block; font-size: 16px; height: 3rem; line-height: 32px; outline: 0; margin: 0; padding: 0 !important; width: 120px !important; } .chips .input:focus { border: 0 !important; -webkit-box-shadow: none !important; box-shadow: none !important; } .chips .autocomplete-content { margin-top: 0; margin-bottom: 0; } .prefix ~ .chips { margin-left: 3rem; width: 92%; width: calc(100% - 3rem); } .chips:empty ~ label { font-size: 0.8rem; -webkit-transform: translateY(-140%); transform: translateY(-140%); } .materialboxed { display: block; cursor: -webkit-zoom-in; cursor: zoom-in; position: relative; -webkit-transition: opacity .4s; transition: opacity .4s; -webkit-backface-visibility: hidden; } .materialboxed:hover:not(.active) { opacity: .8; } .materialboxed.active { cursor: -webkit-zoom-out; cursor: zoom-out; } #materialbox-overlay { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: #292929; z-index: 1000; will-change: opacity; } .materialbox-caption { position: fixed; display: none; color: #fff; line-height: 50px; bottom: 0; left: 0; width: 100%; text-align: center; padding: 0% 15%; height: 50px; z-index: 1000; -webkit-font-smoothing: antialiased; } select:focus { outline: 1px solid #c9f3ef; } button:focus { outline: none; background-color: #2ab7a9; } label { font-size: 0.8rem; color: #9e9e9e; } /* Text Inputs + Textarea ========================================================================== */ /* Style Placeholders */ ::-webkit-input-placeholder { color: #d1d1d1; } ::-moz-placeholder { color: #d1d1d1; } :-ms-input-placeholder { color: #d1d1d1; } ::-ms-input-placeholder { color: #d1d1d1; } ::placeholder { color: #d1d1d1; } /* Text inputs */ input:not([type]), input[type=text]:not(.browser-default), input[type=password]:not(.browser-default), input[type=email]:not(.browser-default), input[type=url]:not(.browser-default), input[type=time]:not(.browser-default), input[type=date]:not(.browser-default), input[type=datetime]:not(.browser-default), input[type=datetime-local]:not(.browser-default), input[type=tel]:not(.browser-default), input[type=number]:not(.browser-default), input[type=search]:not(.browser-default), textarea.materialize-textarea { background-color: transparent; border: none; border-bottom: 1px solid #9e9e9e; border-radius: 0; outline: none; height: 3rem; width: 100%; font-size: 16px; margin: 0 0 8px 0; padding: 0; -webkit-box-shadow: none; box-shadow: none; -webkit-box-sizing: content-box; box-sizing: content-box; -webkit-transition: border .3s, -webkit-box-shadow .3s; transition: border .3s, -webkit-box-shadow .3s; transition: box-shadow .3s, border .3s; transition: box-shadow .3s, border .3s, -webkit-box-shadow .3s; } input:not([type]):disabled, input:not([type])[readonly="readonly"], input[type=text]:not(.browser-default):disabled, input[type=text]:not(.browser-default)[readonly="readonly"], input[type=password]:not(.browser-default):disabled, input[type=password]:not(.browser-default)[readonly="readonly"], input[type=email]:not(.browser-default):disabled, input[type=email]:not(.browser-default)[readonly="readonly"], input[type=url]:not(.browser-default):disabled, input[type=url]:not(.browser-default)[readonly="readonly"], input[type=time]:not(.browser-default):disabled, input[type=time]:not(.browser-default)[readonly="readonly"], input[type=date]:not(.browser-default):disabled, input[type=date]:not(.browser-default)[readonly="readonly"], input[type=datetime]:not(.browser-default):disabled, input[type=datetime]:not(.browser-default)[readonly="readonly"], input[type=datetime-local]:not(.browser-default):disabled, input[type=datetime-local]:not(.browser-default)[readonly="readonly"], input[type=tel]:not(.browser-default):disabled, input[type=tel]:not(.browser-default)[readonly="readonly"], input[type=number]:not(.browser-default):disabled, input[type=number]:not(.browser-default)[readonly="readonly"], input[type=search]:not(.browser-default):disabled, input[type=search]:not(.browser-default)[readonly="readonly"], textarea.materialize-textarea:disabled, textarea.materialize-textarea[readonly="readonly"] { color: rgba(0, 0, 0, 0.42); border-bottom: 1px dotted rgba(0, 0, 0, 0.42); } input:not([type]):disabled + label, input:not([type])[readonly="readonly"] + label, input[type=text]:not(.browser-default):disabled + label, input[type=text]:not(.browser-default)[readonly="readonly"] + label, input[type=password]:not(.browser-default):disabled + label, input[type=password]:not(.browser-default)[readonly="readonly"] + label, input[type=email]:not(.browser-default):disabled + label, input[type=email]:not(.browser-default)[readonly="readonly"] + label, input[type=url]:not(.browser-default):disabled + label, input[type=url]:not(.browser-default)[readonly="readonly"] + label, input[type=time]:not(.browser-default):disabled + label, input[type=time]:not(.browser-default)[readonly="readonly"] + label, input[type=date]:not(.browser-default):disabled + label, input[type=date]:not(.browser-default)[readonly="readonly"] + label, input[type=datetime]:not(.browser-default):disabled + label, input[type=datetime]:not(.browser-default)[readonly="readonly"] + label, input[type=datetime-local]:not(.browser-default):disabled + label, input[type=datetime-local]:not(.browser-default)[readonly="readonly"] + label, input[type=tel]:not(.browser-default):disabled + label, input[type=tel]:not(.browser-default)[readonly="readonly"] + label, input[type=number]:not(.browser-default):disabled + label, input[type=number]:not(.browser-default)[readonly="readonly"] + label, input[type=search]:not(.browser-default):disabled + label, input[type=search]:not(.browser-default)[readonly="readonly"] + label, textarea.materialize-textarea:disabled + label, textarea.materialize-textarea[readonly="readonly"] + label { color: rgba(0, 0, 0, 0.42); } input:not([type]):focus:not([readonly]), input[type=text]:not(.browser-default):focus:not([readonly]), input[type=password]:not(.browser-default):focus:not([readonly]), input[type=email]:not(.browser-default):focus:not([readonly]), input[type=url]:not(.browser-default):focus:not([readonly]), input[type=time]:not(.browser-default):focus:not([readonly]), input[type=date]:not(.browser-default):focus:not([readonly]), input[type=datetime]:not(.browser-default):focus:not([readonly]), input[type=datetime-local]:not(.browser-default):focus:not([readonly]), input[type=tel]:not(.browser-default):focus:not([readonly]), input[type=number]:not(.browser-default):focus:not([readonly]), input[type=search]:not(.browser-default):focus:not([readonly]), textarea.materialize-textarea:focus:not([readonly]) { border-bottom: 1px solid #26a69a; -webkit-box-shadow: 0 1px 0 0 #26a69a; box-shadow: 0 1px 0 0 #26a69a; } input:not([type]):focus:not([readonly]) + label, input[type=text]:not(.browser-default):focus:not([readonly]) + label, input[type=password]:not(.browser-default):focus:not([readonly]) + label, input[type=email]:not(.browser-default):focus:not([readonly]) + label, input[type=url]:not(.browser-default):focus:not([readonly]) + label, input[type=time]:not(.browser-default):focus:not([readonly]) + label, input[type=date]:not(.browser-default):focus:not([readonly]) + label, input[type=datetime]:not(.browser-default):focus:not([readonly]) + label, input[type=datetime-local]:not(.browser-default):focus:not([readonly]) + label, input[type=tel]:not(.browser-default):focus:not([readonly]) + label, input[type=number]:not(.browser-default):focus:not([readonly]) + label, input[type=search]:not(.browser-default):focus:not([readonly]) + label, textarea.materialize-textarea:focus:not([readonly]) + label { color: #26a69a; } input:not([type]):focus.valid ~ label, input[type=text]:not(.browser-default):focus.valid ~ label, input[type=password]:not(.browser-default):focus.valid ~ label, input[type=email]:not(.browser-default):focus.valid ~ label, input[type=url]:not(.browser-default):focus.valid ~ label, input[type=time]:not(.browser-default):focus.valid ~ label, input[type=date]:not(.browser-default):focus.valid ~ label, input[type=datetime]:not(.browser-default):focus.valid ~ label, input[type=datetime-local]:not(.browser-default):focus.valid ~ label, input[type=tel]:not(.browser-default):focus.valid ~ label, input[type=number]:not(.browser-default):focus.valid ~ label, input[type=search]:not(.browser-default):focus.valid ~ label, textarea.materialize-textarea:focus.valid ~ label { color: #4CAF50; } input:not([type]):focus.invalid ~ label, input[type=text]:not(.browser-default):focus.invalid ~ label, input[type=password]:not(.browser-default):focus.invalid ~ label, input[type=email]:not(.browser-default):focus.invalid ~ label, input[type=url]:not(.browser-default):focus.invalid ~ label, input[type=time]:not(.browser-default):focus.invalid ~ label, input[type=date]:not(.browser-default):focus.invalid ~ label, input[type=datetime]:not(.browser-default):focus.invalid ~ label, input[type=datetime-local]:not(.browser-default):focus.invalid ~ label, input[type=tel]:not(.browser-default):focus.invalid ~ label, input[type=number]:not(.browser-default):focus.invalid ~ label, input[type=search]:not(.browser-default):focus.invalid ~ label, textarea.materialize-textarea:focus.invalid ~ label { color: #F44336; } input:not([type]).validate + label, input[type=text]:not(.browser-default).validate + label, input[type=password]:not(.browser-default).validate + label, input[type=email]:not(.browser-default).validate + label, input[type=url]:not(.browser-default).validate + label, input[type=time]:not(.browser-default).validate + label, input[type=date]:not(.browser-default).validate + label, input[type=datetime]:not(.browser-default).validate + label, input[type=datetime-local]:not(.browser-default).validate + label, input[type=tel]:not(.browser-default).validate + label, input[type=number]:not(.browser-default).validate + label, input[type=search]:not(.browser-default).validate + label, textarea.materialize-textarea.validate + label { width: 100%; } /* Validation Sass Placeholders */ input.valid:not([type]), input.valid:not([type]):focus, input.valid[type=text]:not(.browser-default), input.valid[type=text]:not(.browser-default):focus, input.valid[type=password]:not(.browser-default), input.valid[type=password]:not(.browser-default):focus, input.valid[type=email]:not(.browser-default), input.valid[type=email]:not(.browser-default):focus, input.valid[type=url]:not(.browser-default), input.valid[type=url]:not(.browser-default):focus, input.valid[type=time]:not(.browser-default), input.valid[type=time]:not(.browser-default):focus, input.valid[type=date]:not(.browser-default), input.valid[type=date]:not(.browser-default):focus, input.valid[type=datetime]:not(.browser-default), input.valid[type=datetime]:not(.browser-default):focus, input.valid[type=datetime-local]:not(.browser-default), input.valid[type=datetime-local]:not(.browser-default):focus, input.valid[type=tel]:not(.browser-default), input.valid[type=tel]:not(.browser-default):focus, input.valid[type=number]:not(.browser-default), input.valid[type=number]:not(.browser-default):focus, input.valid[type=search]:not(.browser-default), input.valid[type=search]:not(.browser-default):focus, textarea.materialize-textarea.valid, textarea.materialize-textarea.valid:focus, .select-wrapper.valid > input.select-dropdown { border-bottom: 1px solid #4CAF50; -webkit-box-shadow: 0 1px 0 0 #4CAF50; box-shadow: 0 1px 0 0 #4CAF50; } input.invalid:not([type]), input.invalid:not([type]):focus, input.invalid[type=text]:not(.browser-default), input.invalid[type=text]:not(.browser-default):focus, input.invalid[type=password]:not(.browser-default), input.invalid[type=password]:not(.browser-default):focus, input.invalid[type=email]:not(.browser-default), input.invalid[type=email]:not(.browser-default):focus, input.invalid[type=url]:not(.browser-default), input.invalid[type=url]:not(.browser-default):focus, input.invalid[type=time]:not(.browser-default), input.invalid[type=time]:not(.browser-default):focus, input.invalid[type=date]:not(.browser-default), input.invalid[type=date]:not(.browser-default):focus, input.invalid[type=datetime]:not(.browser-default), input.invalid[type=datetime]:not(.browser-default):focus, input.invalid[type=datetime-local]:not(.browser-default), input.invalid[type=datetime-local]:not(.browser-default):focus, input.invalid[type=tel]:not(.browser-default), input.invalid[type=tel]:not(.browser-default):focus, input.invalid[type=number]:not(.browser-default), input.invalid[type=number]:not(.browser-default):focus, input.invalid[type=search]:not(.browser-default), input.invalid[type=search]:not(.browser-default):focus, textarea.materialize-textarea.invalid, textarea.materialize-textarea.invalid:focus, .select-wrapper.invalid > input.select-dropdown, .select-wrapper.invalid > input.select-dropdown:focus { border-bottom: 1px solid #F44336; -webkit-box-shadow: 0 1px 0 0 #F44336; box-shadow: 0 1px 0 0 #F44336; } input:not([type]).valid ~ .helper-text[data-success], input:not([type]):focus.valid ~ .helper-text[data-success], input:not([type]).invalid ~ .helper-text[data-error], input:not([type]):focus.invalid ~ .helper-text[data-error], input[type=text]:not(.browser-default).valid ~ .helper-text[data-success], input[type=text]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=text]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=text]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=password]:not(.browser-default).valid ~ .helper-text[data-success], input[type=password]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=password]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=password]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=email]:not(.browser-default).valid ~ .helper-text[data-success], input[type=email]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=email]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=email]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=url]:not(.browser-default).valid ~ .helper-text[data-success], input[type=url]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=url]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=url]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=time]:not(.browser-default).valid ~ .helper-text[data-success], input[type=time]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=time]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=time]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=date]:not(.browser-default).valid ~ .helper-text[data-success], input[type=date]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=date]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=date]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=datetime]:not(.browser-default).valid ~ .helper-text[data-success], input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=datetime]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=datetime-local]:not(.browser-default).valid ~ .helper-text[data-success], input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=tel]:not(.browser-default).valid ~ .helper-text[data-success], input[type=tel]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=tel]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=number]:not(.browser-default).valid ~ .helper-text[data-success], input[type=number]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=number]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=number]:not(.browser-default):focus.invalid ~ .helper-text[data-error], input[type=search]:not(.browser-default).valid ~ .helper-text[data-success], input[type=search]:not(.browser-default):focus.valid ~ .helper-text[data-success], input[type=search]:not(.browser-default).invalid ~ .helper-text[data-error], input[type=search]:not(.browser-default):focus.invalid ~ .helper-text[data-error], textarea.materialize-textarea.valid ~ .helper-text[data-success], textarea.materialize-textarea:focus.valid ~ .helper-text[data-success], textarea.materialize-textarea.invalid ~ .helper-text[data-error], textarea.materialize-textarea:focus.invalid ~ .helper-text[data-error], .select-wrapper.valid .helper-text[data-success], .select-wrapper.invalid ~ .helper-text[data-error] { color: transparent; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; pointer-events: none; } input:not([type]).valid ~ .helper-text:after, input:not([type]):focus.valid ~ .helper-text:after, input[type=text]:not(.browser-default).valid ~ .helper-text:after, input[type=text]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=password]:not(.browser-default).valid ~ .helper-text:after, input[type=password]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=email]:not(.browser-default).valid ~ .helper-text:after, input[type=email]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=url]:not(.browser-default).valid ~ .helper-text:after, input[type=url]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=time]:not(.browser-default).valid ~ .helper-text:after, input[type=time]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=date]:not(.browser-default).valid ~ .helper-text:after, input[type=date]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=datetime]:not(.browser-default).valid ~ .helper-text:after, input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=datetime-local]:not(.browser-default).valid ~ .helper-text:after, input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=tel]:not(.browser-default).valid ~ .helper-text:after, input[type=tel]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=number]:not(.browser-default).valid ~ .helper-text:after, input[type=number]:not(.browser-default):focus.valid ~ .helper-text:after, input[type=search]:not(.browser-default).valid ~ .helper-text:after, input[type=search]:not(.browser-default):focus.valid ~ .helper-text:after, textarea.materialize-textarea.valid ~ .helper-text:after, textarea.materialize-textarea:focus.valid ~ .helper-text:after, .select-wrapper.valid ~ .helper-text:after { content: attr(data-success); color: #4CAF50; } input:not([type]).invalid ~ .helper-text:after, input:not([type]):focus.invalid ~ .helper-text:after, input[type=text]:not(.browser-default).invalid ~ .helper-text:after, input[type=text]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=password]:not(.browser-default).invalid ~ .helper-text:after, input[type=password]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=email]:not(.browser-default).invalid ~ .helper-text:after, input[type=email]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=url]:not(.browser-default).invalid ~ .helper-text:after, input[type=url]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=time]:not(.browser-default).invalid ~ .helper-text:after, input[type=time]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=date]:not(.browser-default).invalid ~ .helper-text:after, input[type=date]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=datetime]:not(.browser-default).invalid ~ .helper-text:after, input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text:after, input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=tel]:not(.browser-default).invalid ~ .helper-text:after, input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=number]:not(.browser-default).invalid ~ .helper-text:after, input[type=number]:not(.browser-default):focus.invalid ~ .helper-text:after, input[type=search]:not(.browser-default).invalid ~ .helper-text:after, input[type=search]:not(.browser-default):focus.invalid ~ .helper-text:after, textarea.materialize-textarea.invalid ~ .helper-text:after, textarea.materialize-textarea:focus.invalid ~ .helper-text:after, .select-wrapper.invalid ~ .helper-text:after { content: attr(data-error); color: #F44336; } input:not([type]) + label:after, input[type=text]:not(.browser-default) + label:after, input[type=password]:not(.browser-default) + label:after, input[type=email]:not(.browser-default) + label:after, input[type=url]:not(.browser-default) + label:after, input[type=time]:not(.browser-default) + label:after, input[type=date]:not(.browser-default) + label:after, input[type=datetime]:not(.browser-default) + label:after, input[type=datetime-local]:not(.browser-default) + label:after, input[type=tel]:not(.browser-default) + label:after, input[type=number]:not(.browser-default) + label:after, input[type=search]:not(.browser-default) + label:after, textarea.materialize-textarea + label:after, .select-wrapper + label:after { display: block; content: ""; position: absolute; top: 100%; left: 0; opacity: 0; -webkit-transition: .2s opacity ease-out, .2s color ease-out; transition: .2s opacity ease-out, .2s color ease-out; } .input-field { position: relative; margin-top: 1rem; margin-bottom: 1rem; } .input-field.inline { display: inline-block; vertical-align: middle; margin-left: 5px; } .input-field.inline input, .input-field.inline .select-dropdown { margin-bottom: 1rem; } .input-field.col label { left: 0.75rem; } .input-field.col .prefix ~ label, .input-field.col .prefix ~ .validate ~ label { width: calc(100% - 3rem - 1.5rem); } .input-field > label { color: #9e9e9e; position: absolute; top: 0; left: 0; font-size: 1rem; cursor: text; -webkit-transition: color .2s ease-out, -webkit-transform .2s ease-out; transition: color .2s ease-out, -webkit-transform .2s ease-out; transition: transform .2s ease-out, color .2s ease-out; transition: transform .2s ease-out, color .2s ease-out, -webkit-transform .2s ease-out; -webkit-transform-origin: 0% 100%; transform-origin: 0% 100%; text-align: initial; -webkit-transform: translateY(12px); transform: translateY(12px); } .input-field > label:not(.label-icon).active { -webkit-transform: translateY(-14px) scale(0.8); transform: translateY(-14px) scale(0.8); -webkit-transform-origin: 0 0; transform-origin: 0 0; } .input-field > input[type]:-webkit-autofill:not(.browser-default):not([type="search"]) + label, .input-field > input[type=date]:not(.browser-default) + label, .input-field > input[type=time]:not(.browser-default) + label { -webkit-transform: translateY(-14px) scale(0.8); transform: translateY(-14px) scale(0.8); -webkit-transform-origin: 0 0; transform-origin: 0 0; } .input-field .helper-text { position: relative; min-height: 18px; display: block; font-size: 12px; color: rgba(0, 0, 0, 0.54); } .input-field .helper-text::after { opacity: 1; position: absolute; top: 0; left: 0; } .input-field .prefix { position: absolute; width: 3rem; font-size: 2rem; -webkit-transition: color .2s; transition: color .2s; top: 0.5rem; } .input-field .prefix.active { color: #26a69a; } .input-field .prefix ~ input, .input-field .prefix ~ textarea, .input-field .prefix ~ label, .input-field .prefix ~ .validate ~ label, .input-field .prefix ~ .helper-text, .input-field .prefix ~ .autocomplete-content { margin-left: 3rem; width: 92%; width: calc(100% - 3rem); } .input-field .prefix ~ label { margin-left: 3rem; } @media only screen and (max-width: 992px) { .input-field .prefix ~ input { width: 86%; width: calc(100% - 3rem); } } @media only screen and (max-width: 600px) { .input-field .prefix ~ input { width: 80%; width: calc(100% - 3rem); } } /* Search Field */ .input-field input[type=search] { display: block; line-height: inherit; -webkit-transition: .3s background-color; transition: .3s background-color; } .nav-wrapper .input-field input[type=search] { height: inherit; padding-left: 4rem; width: calc(100% - 4rem); border: 0; -webkit-box-shadow: none; box-shadow: none; } .input-field input[type=search]:focus:not(.browser-default) { background-color: #fff; border: 0; -webkit-box-shadow: none; box-shadow: none; color: #444; } .input-field input[type=search]:focus:not(.browser-default) + label i, .input-field input[type=search]:focus:not(.browser-default) ~ .mdi-navigation-close, .input-field input[type=search]:focus:not(.browser-default) ~ .material-icons { color: #444; } .input-field input[type=search] + .label-icon { -webkit-transform: none; transform: none; left: 1rem; } .input-field input[type=search] ~ .mdi-navigation-close, .input-field input[type=search] ~ .material-icons { position: absolute; top: 0; right: 1rem; color: transparent; cursor: pointer; font-size: 2rem; -webkit-transition: .3s color; transition: .3s color; } /* Textarea */ textarea { width: 100%; height: 3rem; background-color: transparent; } textarea.materialize-textarea { line-height: normal; overflow-y: hidden; /* prevents scroll bar flash */ padding: .8rem 0 .8rem 0; /* prevents text jump on Enter keypress */ resize: none; min-height: 3rem; -webkit-box-sizing: border-box; box-sizing: border-box; } .hiddendiv { visibility: hidden; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; /* future version of deprecated 'word-wrap' */ padding-top: 1.2rem; /* prevents text jump on Enter keypress */ position: absolute; top: 0; z-index: -1; } /* Autocomplete */ .autocomplete-content li .highlight { color: #444; } .autocomplete-content li img { height: 40px; width: 40px; margin: 5px 15px; } /* Character Counter */ .character-counter { min-height: 18px; } /* Radio Buttons ========================================================================== */ [type="radio"]:not(:checked), [type="radio"]:checked { position: absolute; opacity: 0; pointer-events: none; } [type="radio"]:not(:checked) + span, [type="radio"]:checked + span { position: relative; padding-left: 35px; cursor: pointer; display: inline-block; height: 25px; line-height: 25px; font-size: 1rem; -webkit-transition: .28s ease; transition: .28s ease; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } [type="radio"] + span:before, [type="radio"] + span:after { content: ''; position: absolute; left: 0; top: 0; margin: 4px; width: 16px; height: 16px; z-index: 0; -webkit-transition: .28s ease; transition: .28s ease; } /* Unchecked styles */ [type="radio"]:not(:checked) + span:before, [type="radio"]:not(:checked) + span:after, [type="radio"]:checked + span:before, [type="radio"]:checked + span:after, [type="radio"].with-gap:checked + span:before, [type="radio"].with-gap:checked + span:after { border-radius: 50%; } [type="radio"]:not(:checked) + span:before, [type="radio"]:not(:checked) + span:after { border: 2px solid #5a5a5a; } [type="radio"]:not(:checked) + span:after { -webkit-transform: scale(0); transform: scale(0); } /* Checked styles */ [type="radio"]:checked + span:before { border: 2px solid transparent; } [type="radio"]:checked + span:after, [type="radio"].with-gap:checked + span:before, [type="radio"].with-gap:checked + span:after { border: 2px solid #26a69a; } [type="radio"]:checked + span:after, [type="radio"].with-gap:checked + span:after { background-color: #26a69a; } [type="radio"]:checked + span:after { -webkit-transform: scale(1.02); transform: scale(1.02); } /* Radio With gap */ [type="radio"].with-gap:checked + span:after { -webkit-transform: scale(0.5); transform: scale(0.5); } /* Focused styles */ [type="radio"].tabbed:focus + span:before { -webkit-box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); } /* Disabled Radio With gap */ [type="radio"].with-gap:disabled:checked + span:before { border: 2px solid rgba(0, 0, 0, 0.42); } [type="radio"].with-gap:disabled:checked + span:after { border: none; background-color: rgba(0, 0, 0, 0.42); } /* Disabled style */ [type="radio"]:disabled:not(:checked) + span:before, [type="radio"]:disabled:checked + span:before { background-color: transparent; border-color: rgba(0, 0, 0, 0.42); } [type="radio"]:disabled + span { color: rgba(0, 0, 0, 0.42); } [type="radio"]:disabled:not(:checked) + span:before { border-color: rgba(0, 0, 0, 0.42); } [type="radio"]:disabled:checked + span:after { background-color: rgba(0, 0, 0, 0.42); border-color: #949494; } /* Checkboxes ========================================================================== */ /* Remove default checkbox */ [type="checkbox"]:not(:checked), [type="checkbox"]:checked { position: absolute; opacity: 0; pointer-events: none; } [type="checkbox"] { /* checkbox aspect */ } [type="checkbox"] + span:not(.lever) { position: relative; padding-left: 35px; cursor: pointer; display: inline-block; height: 25px; line-height: 25px; font-size: 1rem; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } [type="checkbox"] + span:not(.lever):before, [type="checkbox"]:not(.filled-in) + span:not(.lever):after { content: ''; position: absolute; top: 0; left: 0; width: 18px; height: 18px; z-index: 0; border: 2px solid #5a5a5a; border-radius: 1px; margin-top: 3px; -webkit-transition: .2s; transition: .2s; } [type="checkbox"]:not(.filled-in) + span:not(.lever):after { border: 0; -webkit-transform: scale(0); transform: scale(0); } [type="checkbox"]:not(:checked):disabled + span:not(.lever):before { border: none; background-color: rgba(0, 0, 0, 0.42); } [type="checkbox"].tabbed:focus + span:not(.lever):after { -webkit-transform: scale(1); transform: scale(1); border: 0; border-radius: 50%; -webkit-box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1); } [type="checkbox"]:checked + span:not(.lever):before { top: -4px; left: -5px; width: 12px; height: 22px; border-top: 2px solid transparent; border-left: 2px solid transparent; border-right: 2px solid #26a69a; border-bottom: 2px solid #26a69a; -webkit-transform: rotate(40deg); transform: rotate(40deg); -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; } [type="checkbox"]:checked:disabled + span:before { border-right: 2px solid rgba(0, 0, 0, 0.42); border-bottom: 2px solid rgba(0, 0, 0, 0.42); } /* Indeterminate checkbox */ [type="checkbox"]:indeterminate + span:not(.lever):before { top: -11px; left: -12px; width: 10px; height: 22px; border-top: none; border-left: none; border-right: 2px solid #26a69a; border-bottom: none; -webkit-transform: rotate(90deg); transform: rotate(90deg); -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; } [type="checkbox"]:indeterminate:disabled + span:not(.lever):before { border-right: 2px solid rgba(0, 0, 0, 0.42); background-color: transparent; } [type="checkbox"].filled-in + span:not(.lever):after { border-radius: 2px; } [type="checkbox"].filled-in + span:not(.lever):before, [type="checkbox"].filled-in + span:not(.lever):after { content: ''; left: 0; position: absolute; /* .1s delay is for check animation */ -webkit-transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s; transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s; z-index: 1; } [type="checkbox"].filled-in:not(:checked) + span:not(.lever):before { width: 0; height: 0; border: 3px solid transparent; left: 6px; top: 10px; -webkit-transform: rotateZ(37deg); transform: rotateZ(37deg); -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; } [type="checkbox"].filled-in:not(:checked) + span:not(.lever):after { height: 20px; width: 20px; background-color: transparent; border: 2px solid #5a5a5a; top: 0px; z-index: 0; } [type="checkbox"].filled-in:checked + span:not(.lever):before { top: 0; left: 1px; width: 8px; height: 13px; border-top: 2px solid transparent; border-left: 2px solid transparent; border-right: 2px solid #fff; border-bottom: 2px solid #fff; -webkit-transform: rotateZ(37deg); transform: rotateZ(37deg); -webkit-transform-origin: 100% 100%; transform-origin: 100% 100%; } [type="checkbox"].filled-in:checked + span:not(.lever):after { top: 0; width: 20px; height: 20px; border: 2px solid #26a69a; background-color: #26a69a; z-index: 0; } [type="checkbox"].filled-in.tabbed:focus + span:not(.lever):after { border-radius: 2px; border-color: #5a5a5a; background-color: rgba(0, 0, 0, 0.1); } [type="checkbox"].filled-in.tabbed:checked:focus + span:not(.lever):after { border-radius: 2px; background-color: #26a69a; border-color: #26a69a; } [type="checkbox"].filled-in:disabled:not(:checked) + span:not(.lever):before { background-color: transparent; border: 2px solid transparent; } [type="checkbox"].filled-in:disabled:not(:checked) + span:not(.lever):after { border-color: transparent; background-color: #949494; } [type="checkbox"].filled-in:disabled:checked + span:not(.lever):before { background-color: transparent; } [type="checkbox"].filled-in:disabled:checked + span:not(.lever):after { background-color: #949494; border-color: #949494; } /* Switch ========================================================================== */ .switch, .switch * { -webkit-tap-highlight-color: transparent; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .switch label { cursor: pointer; } .switch label input[type=checkbox] { opacity: 0; width: 0; height: 0; } .switch label input[type=checkbox]:checked + .lever { background-color: #84c7c1; } .switch label input[type=checkbox]:checked + .lever:before, .switch label input[type=checkbox]:checked + .lever:after { left: 18px; } .switch label input[type=checkbox]:checked + .lever:after { background-color: #26a69a; } .switch label .lever { content: ""; display: inline-block; position: relative; width: 36px; height: 14px; background-color: rgba(0, 0, 0, 0.38); border-radius: 15px; margin-right: 10px; -webkit-transition: background 0.3s ease; transition: background 0.3s ease; vertical-align: middle; margin: 0 16px; } .switch label .lever:before, .switch label .lever:after { content: ""; position: absolute; display: inline-block; width: 20px; height: 20px; border-radius: 50%; left: 0; top: -3px; -webkit-transition: left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; transition: left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease; transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; } .switch label .lever:before { background-color: rgba(38, 166, 154, 0.15); } .switch label .lever:after { background-color: #F1F1F1; -webkit-box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); } input[type=checkbox]:checked:not(:disabled) ~ .lever:active::before, input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::before { -webkit-transform: scale(2.4); transform: scale(2.4); background-color: rgba(38, 166, 154, 0.15); } input[type=checkbox]:not(:disabled) ~ .lever:active:before, input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before { -webkit-transform: scale(2.4); transform: scale(2.4); background-color: rgba(0, 0, 0, 0.08); } .switch input[type=checkbox][disabled] + .lever { cursor: default; background-color: rgba(0, 0, 0, 0.12); } .switch label input[type=checkbox][disabled] + .lever:after, .switch label input[type=checkbox][disabled]:checked + .lever:after { background-color: #949494; } /* Select Field ========================================================================== */ select { display: none; } select.browser-default { display: block; } select { background-color: rgba(255, 255, 255, 0.9); width: 100%; padding: 5px; border: 1px solid #f2f2f2; border-radius: 2px; height: 3rem; } .select-label { position: absolute; } .select-wrapper { position: relative; } .select-wrapper.valid + label, .select-wrapper.invalid + label { width: 100%; pointer-events: none; } .select-wrapper input.select-dropdown { position: relative; cursor: pointer; background-color: transparent; border: none; border-bottom: 1px solid #9e9e9e; outline: none; height: 3rem; line-height: 3rem; width: 100%; font-size: 16px; margin: 0 0 8px 0; padding: 0; display: block; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; z-index: 1; } .select-wrapper input.select-dropdown:focus { border-bottom: 1px solid #26a69a; } .select-wrapper .caret { position: absolute; right: 0; top: 0; bottom: 0; margin: auto 0; z-index: 0; fill: rgba(0, 0, 0, 0.87); } .select-wrapper + label { position: absolute; top: -26px; font-size: 0.8rem; } select:disabled { color: rgba(0, 0, 0, 0.42); } .select-wrapper.disabled + label { color: rgba(0, 0, 0, 0.42); } .select-wrapper.disabled .caret { fill: rgba(0, 0, 0, 0.42); } .select-wrapper input.select-dropdown:disabled { color: rgba(0, 0, 0, 0.42); cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .select-wrapper i { color: rgba(0, 0, 0, 0.3); } .select-dropdown li.disabled, .select-dropdown li.disabled > span, .select-dropdown li.optgroup { color: rgba(0, 0, 0, 0.3); background-color: transparent; } body.keyboard-focused .select-dropdown.dropdown-content li:focus { background-color: rgba(0, 0, 0, 0.08); } .select-dropdown.dropdown-content li:hover { background-color: rgba(0, 0, 0, 0.08); } .select-dropdown.dropdown-content li.selected { background-color: rgba(0, 0, 0, 0.03); } .prefix ~ .select-wrapper { margin-left: 3rem; width: 92%; width: calc(100% - 3rem); } .prefix ~ label { margin-left: 3rem; } .select-dropdown li img { height: 40px; width: 40px; margin: 5px 15px; float: right; } .select-dropdown li.optgroup { border-top: 1px solid #eee; } .select-dropdown li.optgroup.selected > span { color: rgba(0, 0, 0, 0.7); } .select-dropdown li.optgroup > span { color: rgba(0, 0, 0, 0.4); } .select-dropdown li.optgroup ~ li.optgroup-option { padding-left: 1rem; } /* File Input ========================================================================== */ .file-field { position: relative; } .file-field .file-path-wrapper { overflow: hidden; padding-left: 10px; } .file-field input.file-path { width: 100%; } .file-field .btn, .file-field .btn-large, .file-field .btn-small { float: left; height: 3rem; line-height: 3rem; } .file-field span { cursor: pointer; } .file-field input[type=file] { position: absolute; top: 0; right: 0; left: 0; bottom: 0; width: 100%; margin: 0; padding: 0; font-size: 20px; cursor: pointer; opacity: 0; filter: alpha(opacity=0); } .file-field input[type=file]::-webkit-file-upload-button { display: none; } /* Range ========================================================================== */ .range-field { position: relative; } input[type=range], input[type=range] + .thumb { cursor: pointer; } input[type=range] { position: relative; background-color: transparent; border: none; outline: none; width: 100%; margin: 15px 0; padding: 0; } input[type=range]:focus { outline: none; } input[type=range] + .thumb { position: absolute; top: 10px; left: 0; border: none; height: 0; width: 0; border-radius: 50%; background-color: #26a69a; margin-left: 7px; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; -webkit-transform: rotate(-45deg); transform: rotate(-45deg); } input[type=range] + .thumb .value { display: block; width: 30px; text-align: center; color: #26a69a; font-size: 0; -webkit-transform: rotate(45deg); transform: rotate(45deg); } input[type=range] + .thumb.active { border-radius: 50% 50% 50% 0; } input[type=range] + .thumb.active .value { color: #fff; margin-left: -1px; margin-top: 8px; font-size: 10px; } input[type=range] { -webkit-appearance: none; } input[type=range]::-webkit-slider-runnable-track { height: 3px; background: #c2c0c2; border: none; } input[type=range]::-webkit-slider-thumb { border: none; height: 14px; width: 14px; border-radius: 50%; background: #26a69a; -webkit-transition: -webkit-box-shadow .3s; transition: -webkit-box-shadow .3s; transition: box-shadow .3s; transition: box-shadow .3s, -webkit-box-shadow .3s; -webkit-appearance: none; background-color: #26a69a; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; margin: -5px 0 0 0; } .keyboard-focused input[type=range]:focus:not(.active)::-webkit-slider-thumb { -webkit-box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); } input[type=range] { /* fix for FF unable to apply focus style bug */ border: 1px solid white; /*required for proper track sizing in FF*/ } input[type=range]::-moz-range-track { height: 3px; background: #c2c0c2; border: none; } input[type=range]::-moz-focus-inner { border: 0; } input[type=range]::-moz-range-thumb { border: none; height: 14px; width: 14px; border-radius: 50%; background: #26a69a; -webkit-transition: -webkit-box-shadow .3s; transition: -webkit-box-shadow .3s; transition: box-shadow .3s; transition: box-shadow .3s, -webkit-box-shadow .3s; margin-top: -5px; } input[type=range]:-moz-focusring { outline: 1px solid #fff; outline-offset: -1px; } .keyboard-focused input[type=range]:focus:not(.active)::-moz-range-thumb { box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); } input[type=range]::-ms-track { height: 3px; background: transparent; border-color: transparent; border-width: 6px 0; /*remove default tick marks*/ color: transparent; } input[type=range]::-ms-fill-lower { background: #777; } input[type=range]::-ms-fill-upper { background: #ddd; } input[type=range]::-ms-thumb { border: none; height: 14px; width: 14px; border-radius: 50%; background: #26a69a; -webkit-transition: -webkit-box-shadow .3s; transition: -webkit-box-shadow .3s; transition: box-shadow .3s; transition: box-shadow .3s, -webkit-box-shadow .3s; } .keyboard-focused input[type=range]:focus:not(.active)::-ms-thumb { box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); } /*************** Nav List ***************/ .table-of-contents.fixed { position: fixed; } .table-of-contents li { padding: 2px 0; } .table-of-contents a { display: inline-block; font-weight: 300; color: #757575; padding-left: 16px; height: 1.5rem; line-height: 1.5rem; letter-spacing: .4; display: inline-block; } .table-of-contents a:hover { color: #a8a8a8; padding-left: 15px; border-left: 1px solid #ee6e73; } .table-of-contents a.active { font-weight: 500; padding-left: 14px; border-left: 2px solid #ee6e73; } .sidenav { position: fixed; width: 300px; left: 0; top: 0; margin: 0; -webkit-transform: translateX(-100%); transform: translateX(-100%); height: 100%; height: calc(100% + 60px); height: -moz-calc(100%); padding-bottom: 60px; background-color: #fff; z-index: 999; overflow-y: auto; will-change: transform; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateX(-105%); transform: translateX(-105%); } .sidenav.right-aligned { right: 0; -webkit-transform: translateX(105%); transform: translateX(105%); left: auto; -webkit-transform: translateX(100%); transform: translateX(100%); } .sidenav .collapsible { margin: 0; } .sidenav li { float: none; line-height: 48px; } .sidenav li.active { background-color: rgba(0, 0, 0, 0.05); } .sidenav li > a { color: rgba(0, 0, 0, 0.87); display: block; font-size: 14px; font-weight: 500; height: 48px; line-height: 48px; padding: 0 32px; } .sidenav li > a:hover { background-color: rgba(0, 0, 0, 0.05); } .sidenav li > a.btn, .sidenav li > a.btn-large, .sidenav li > a.btn-small, .sidenav li > a.btn-large, .sidenav li > a.btn-flat, .sidenav li > a.btn-floating { margin: 10px 15px; } .sidenav li > a.btn, .sidenav li > a.btn-large, .sidenav li > a.btn-small, .sidenav li > a.btn-large, .sidenav li > a.btn-floating { color: #fff; } .sidenav li > a.btn-flat { color: #343434; } .sidenav li > a.btn:hover, .sidenav li > a.btn-large:hover, .sidenav li > a.btn-small:hover, .sidenav li > a.btn-large:hover { background-color: #2bbbad; } .sidenav li > a.btn-floating:hover { background-color: #26a69a; } .sidenav li > a > i, .sidenav li > a > [class^="mdi-"], .sidenav li > a li > a > [class*="mdi-"], .sidenav li > a > i.material-icons { float: left; height: 48px; line-height: 48px; margin: 0 32px 0 0; width: 24px; color: rgba(0, 0, 0, 0.54); } .sidenav .divider { margin: 8px 0 0 0; } .sidenav .subheader { cursor: initial; pointer-events: none; color: rgba(0, 0, 0, 0.54); font-size: 14px; font-weight: 500; line-height: 48px; } .sidenav .subheader:hover { background-color: transparent; } .sidenav .user-view { position: relative; padding: 32px 32px 0; margin-bottom: 8px; } .sidenav .user-view > a { height: auto; padding: 0; } .sidenav .user-view > a:hover { background-color: transparent; } .sidenav .user-view .background { overflow: hidden; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; } .sidenav .user-view .circle, .sidenav .user-view .name, .sidenav .user-view .email { display: block; } .sidenav .user-view .circle { height: 64px; width: 64px; } .sidenav .user-view .name, .sidenav .user-view .email { font-size: 14px; line-height: 24px; } .sidenav .user-view .name { margin-top: 16px; font-weight: 500; } .sidenav .user-view .email { padding-bottom: 16px; font-weight: 400; } .drag-target { height: 100%; width: 10px; position: fixed; top: 0; z-index: 998; } .drag-target.right-aligned { right: 0; } .sidenav.sidenav-fixed { left: 0; -webkit-transform: translateX(0); transform: translateX(0); position: fixed; } .sidenav.sidenav-fixed.right-aligned { right: 0; left: auto; } @media only screen and (max-width: 992px) { .sidenav.sidenav-fixed { -webkit-transform: translateX(-105%); transform: translateX(-105%); } .sidenav.sidenav-fixed.right-aligned { -webkit-transform: translateX(105%); transform: translateX(105%); } .sidenav > a { padding: 0 16px; } .sidenav .user-view { padding: 16px 16px 0; } } .sidenav .collapsible-body > ul:not(.collapsible) > li.active, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active { background-color: #ee6e73; } .sidenav .collapsible-body > ul:not(.collapsible) > li.active a, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active a { color: #fff; } .sidenav .collapsible-body { padding: 0; } .sidenav-overlay { position: fixed; top: 0; left: 0; right: 0; opacity: 0; height: 120vh; background-color: rgba(0, 0, 0, 0.5); z-index: 997; display: none; } /* @license Copyright (c) 2014 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ /**************************/ /* STYLES FOR THE SPINNER */ /**************************/ /* * Constants: * STROKEWIDTH = 3px * ARCSIZE = 270 degrees (amount of circle the arc takes up) * ARCTIME = 1333ms (time it takes to expand and contract arc) * ARCSTARTROT = 216 degrees (how much the start location of the arc * should rotate each time, 216 gives us a * 5 pointed star shape (it's 360/5 * 3). * For a 7 pointed star, we might do * 360/7 * 3 = 154.286) * CONTAINERWIDTH = 28px * SHRINK_TIME = 400ms */ .preloader-wrapper { display: inline-block; position: relative; width: 50px; height: 50px; } .preloader-wrapper.small { width: 36px; height: 36px; } .preloader-wrapper.big { width: 64px; height: 64px; } .preloader-wrapper.active { /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */ -webkit-animation: container-rotate 1568ms linear infinite; animation: container-rotate 1568ms linear infinite; } @-webkit-keyframes container-rotate { to { -webkit-transform: rotate(360deg); } } @keyframes container-rotate { to { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } .spinner-layer { position: absolute; width: 100%; height: 100%; opacity: 0; border-color: #26a69a; } .spinner-blue, .spinner-blue-only { border-color: #4285f4; } .spinner-red, .spinner-red-only { border-color: #db4437; } .spinner-yellow, .spinner-yellow-only { border-color: #f4b400; } .spinner-green, .spinner-green-only { border-color: #0f9d58; } /** * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee): * * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't * guarantee that the animation will start _exactly_ after that value. So we avoid using * animation-delay and instead set custom keyframes for each color (as redundant as it * seems). * * We write out each animation in full (instead of separating animation-name, * animation-duration, etc.) because under the polyfill, Safari does not recognize those * specific properties properly, treats them as -webkit-animation, and overrides the * other animation rules. See https://github.com/Polymer/platform/issues/53. */ .active .spinner-layer.spinner-blue { /* durations: 4 * ARCTIME */ -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .active .spinner-layer.spinner-red { /* durations: 4 * ARCTIME */ -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .active .spinner-layer.spinner-yellow { /* durations: 4 * ARCTIME */ -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .active .spinner-layer.spinner-green { /* durations: 4 * ARCTIME */ -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .active .spinner-layer, .active .spinner-layer.spinner-blue-only, .active .spinner-layer.spinner-red-only, .active .spinner-layer.spinner-yellow-only, .active .spinner-layer.spinner-green-only { /* durations: 4 * ARCTIME */ opacity: 1; -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } @-webkit-keyframes fill-unfill-rotate { 12.5% { -webkit-transform: rotate(135deg); } /* 0.5 * ARCSIZE */ 25% { -webkit-transform: rotate(270deg); } /* 1 * ARCSIZE */ 37.5% { -webkit-transform: rotate(405deg); } /* 1.5 * ARCSIZE */ 50% { -webkit-transform: rotate(540deg); } /* 2 * ARCSIZE */ 62.5% { -webkit-transform: rotate(675deg); } /* 2.5 * ARCSIZE */ 75% { -webkit-transform: rotate(810deg); } /* 3 * ARCSIZE */ 87.5% { -webkit-transform: rotate(945deg); } /* 3.5 * ARCSIZE */ to { -webkit-transform: rotate(1080deg); } /* 4 * ARCSIZE */ } @keyframes fill-unfill-rotate { 12.5% { -webkit-transform: rotate(135deg); transform: rotate(135deg); } /* 0.5 * ARCSIZE */ 25% { -webkit-transform: rotate(270deg); transform: rotate(270deg); } /* 1 * ARCSIZE */ 37.5% { -webkit-transform: rotate(405deg); transform: rotate(405deg); } /* 1.5 * ARCSIZE */ 50% { -webkit-transform: rotate(540deg); transform: rotate(540deg); } /* 2 * ARCSIZE */ 62.5% { -webkit-transform: rotate(675deg); transform: rotate(675deg); } /* 2.5 * ARCSIZE */ 75% { -webkit-transform: rotate(810deg); transform: rotate(810deg); } /* 3 * ARCSIZE */ 87.5% { -webkit-transform: rotate(945deg); transform: rotate(945deg); } /* 3.5 * ARCSIZE */ to { -webkit-transform: rotate(1080deg); transform: rotate(1080deg); } /* 4 * ARCSIZE */ } @-webkit-keyframes blue-fade-in-out { from { opacity: 1; } 25% { opacity: 1; } 26% { opacity: 0; } 89% { opacity: 0; } 90% { opacity: 1; } 100% { opacity: 1; } } @keyframes blue-fade-in-out { from { opacity: 1; } 25% { opacity: 1; } 26% { opacity: 0; } 89% { opacity: 0; } 90% { opacity: 1; } 100% { opacity: 1; } } @-webkit-keyframes red-fade-in-out { from { opacity: 0; } 15% { opacity: 0; } 25% { opacity: 1; } 50% { opacity: 1; } 51% { opacity: 0; } } @keyframes red-fade-in-out { from { opacity: 0; } 15% { opacity: 0; } 25% { opacity: 1; } 50% { opacity: 1; } 51% { opacity: 0; } } @-webkit-keyframes yellow-fade-in-out { from { opacity: 0; } 40% { opacity: 0; } 50% { opacity: 1; } 75% { opacity: 1; } 76% { opacity: 0; } } @keyframes yellow-fade-in-out { from { opacity: 0; } 40% { opacity: 0; } 50% { opacity: 1; } 75% { opacity: 1; } 76% { opacity: 0; } } @-webkit-keyframes green-fade-in-out { from { opacity: 0; } 65% { opacity: 0; } 75% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; } } @keyframes green-fade-in-out { from { opacity: 0; } 65% { opacity: 0; } 75% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; } } /** * Patch the gap that appear between the two adjacent div.circle-clipper while the * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11). */ .gap-patch { position: absolute; top: 0; left: 45%; width: 10%; height: 100%; overflow: hidden; border-color: inherit; } .gap-patch .circle { width: 1000%; left: -450%; } .circle-clipper { display: inline-block; position: relative; width: 50%; height: 100%; overflow: hidden; border-color: inherit; } .circle-clipper .circle { width: 200%; height: 100%; border-width: 3px; /* STROKEWIDTH */ border-style: solid; border-color: inherit; border-bottom-color: transparent !important; border-radius: 50%; -webkit-animation: none; animation: none; position: absolute; top: 0; right: 0; bottom: 0; } .circle-clipper.left .circle { left: 0; border-right-color: transparent !important; -webkit-transform: rotate(129deg); transform: rotate(129deg); } .circle-clipper.right .circle { left: -100%; border-left-color: transparent !important; -webkit-transform: rotate(-129deg); transform: rotate(-129deg); } .active .circle-clipper.left .circle { /* duration: ARCTIME */ -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } .active .circle-clipper.right .circle { /* duration: ARCTIME */ -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } @-webkit-keyframes left-spin { from { -webkit-transform: rotate(130deg); } 50% { -webkit-transform: rotate(-5deg); } to { -webkit-transform: rotate(130deg); } } @keyframes left-spin { from { -webkit-transform: rotate(130deg); transform: rotate(130deg); } 50% { -webkit-transform: rotate(-5deg); transform: rotate(-5deg); } to { -webkit-transform: rotate(130deg); transform: rotate(130deg); } } @-webkit-keyframes right-spin { from { -webkit-transform: rotate(-130deg); } 50% { -webkit-transform: rotate(5deg); } to { -webkit-transform: rotate(-130deg); } } @keyframes right-spin { from { -webkit-transform: rotate(-130deg); transform: rotate(-130deg); } 50% { -webkit-transform: rotate(5deg); transform: rotate(5deg); } to { -webkit-transform: rotate(-130deg); transform: rotate(-130deg); } } #spinnerContainer.cooldown { /* duration: SHRINK_TIME */ -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1); animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1); } @-webkit-keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } .slider { position: relative; height: 400px; width: 100%; } .slider.fullscreen { height: 100%; width: 100%; position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .slider.fullscreen ul.slides { height: 100%; } .slider.fullscreen ul.indicators { z-index: 2; bottom: 30px; } .slider .slides { background-color: #9e9e9e; margin: 0; height: 400px; } .slider .slides li { opacity: 0; position: absolute; top: 0; left: 0; z-index: 1; width: 100%; height: inherit; overflow: hidden; } .slider .slides li img { height: 100%; width: 100%; background-size: cover; background-position: center; } .slider .slides li .caption { color: #fff; position: absolute; top: 15%; left: 15%; width: 70%; opacity: 0; } .slider .slides li .caption p { color: #e0e0e0; } .slider .slides li.active { z-index: 2; } .slider .indicators { position: absolute; text-align: center; left: 0; right: 0; bottom: 0; margin: 0; } .slider .indicators .indicator-item { display: inline-block; position: relative; cursor: pointer; height: 16px; width: 16px; margin: 0 12px; background-color: #e0e0e0; -webkit-transition: background-color .3s; transition: background-color .3s; border-radius: 50%; } .slider .indicators .indicator-item.active { background-color: #4CAF50; } .carousel { overflow: hidden; position: relative; width: 100%; height: 400px; -webkit-perspective: 500px; perspective: 500px; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-transform-origin: 0% 50%; transform-origin: 0% 50%; } .carousel.carousel-slider { top: 0; left: 0; } .carousel.carousel-slider .carousel-fixed-item { position: absolute; left: 0; right: 0; bottom: 20px; z-index: 1; } .carousel.carousel-slider .carousel-fixed-item.with-indicators { bottom: 68px; } .carousel.carousel-slider .carousel-item { width: 100%; height: 100%; min-height: 400px; position: absolute; top: 0; left: 0; } .carousel.carousel-slider .carousel-item h2 { font-size: 24px; font-weight: 500; line-height: 32px; } .carousel.carousel-slider .carousel-item p { font-size: 15px; } .carousel .carousel-item { visibility: hidden; width: 200px; height: 200px; position: absolute; top: 0; left: 0; } .carousel .carousel-item > img { width: 100%; } .carousel .indicators { position: absolute; text-align: center; left: 0; right: 0; bottom: 0; margin: 0; } .carousel .indicators .indicator-item { display: inline-block; position: relative; cursor: pointer; height: 8px; width: 8px; margin: 24px 4px; background-color: rgba(255, 255, 255, 0.5); -webkit-transition: background-color .3s; transition: background-color .3s; border-radius: 50%; } .carousel .indicators .indicator-item.active { background-color: #fff; } .carousel.scrolling .carousel-item .materialboxed, .carousel .carousel-item:not(.active) .materialboxed { pointer-events: none; } .tap-target-wrapper { width: 800px; height: 800px; position: fixed; z-index: 1000; visibility: hidden; -webkit-transition: visibility 0s .3s; transition: visibility 0s .3s; } .tap-target-wrapper.open { visibility: visible; -webkit-transition: visibility 0s; transition: visibility 0s; } .tap-target-wrapper.open .tap-target { -webkit-transform: scale(1); transform: scale(1); opacity: .95; -webkit-transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); } .tap-target-wrapper.open .tap-target-wave::before { -webkit-transform: scale(1); transform: scale(1); } .tap-target-wrapper.open .tap-target-wave::after { visibility: visible; -webkit-animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; -webkit-transition: opacity .3s, visibility 0s 1s, -webkit-transform .3s; transition: opacity .3s, visibility 0s 1s, -webkit-transform .3s; transition: opacity .3s, transform .3s, visibility 0s 1s; transition: opacity .3s, transform .3s, visibility 0s 1s, -webkit-transform .3s; } .tap-target { position: absolute; font-size: 1rem; border-radius: 50%; background-color: #ee6e73; -webkit-box-shadow: 0 20px 20px 0 rgba(0, 0, 0, 0.14), 0 10px 50px 0 rgba(0, 0, 0, 0.12), 0 30px 10px -20px rgba(0, 0, 0, 0.2); box-shadow: 0 20px 20px 0 rgba(0, 0, 0, 0.14), 0 10px 50px 0 rgba(0, 0, 0, 0.12), 0 30px 10px -20px rgba(0, 0, 0, 0.2); width: 100%; height: 100%; opacity: 0; -webkit-transform: scale(0); transform: scale(0); -webkit-transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1); transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); } .tap-target-content { position: relative; display: table-cell; } .tap-target-wave { position: absolute; border-radius: 50%; z-index: 10001; } .tap-target-wave::before, .tap-target-wave::after { content: ''; display: block; position: absolute; width: 100%; height: 100%; border-radius: 50%; background-color: #ffffff; } .tap-target-wave::before { -webkit-transform: scale(0); transform: scale(0); -webkit-transition: -webkit-transform .3s; transition: -webkit-transform .3s; transition: transform .3s; transition: transform .3s, -webkit-transform .3s; } .tap-target-wave::after { visibility: hidden; -webkit-transition: opacity .3s, visibility 0s, -webkit-transform .3s; transition: opacity .3s, visibility 0s, -webkit-transform .3s; transition: opacity .3s, transform .3s, visibility 0s; transition: opacity .3s, transform .3s, visibility 0s, -webkit-transform .3s; z-index: -1; } .tap-target-origin { top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); z-index: 10002; position: absolute !important; } .tap-target-origin:not(.btn):not(.btn-large):not(.btn-small), .tap-target-origin:not(.btn):not(.btn-large):not(.btn-small):hover { background: none; } @media only screen and (max-width: 600px) { .tap-target, .tap-target-wrapper { width: 600px; height: 600px; } } .pulse { overflow: visible; position: relative; } .pulse::before { content: ''; display: block; position: absolute; width: 100%; height: 100%; top: 0; left: 0; background-color: inherit; border-radius: inherit; -webkit-transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, -webkit-transform .3s; transition: opacity .3s, transform .3s; transition: opacity .3s, transform .3s, -webkit-transform .3s; -webkit-animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; z-index: -1; } @-webkit-keyframes pulse-animation { 0% { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } 50% { opacity: 0; -webkit-transform: scale(1.5); transform: scale(1.5); } 100% { opacity: 0; -webkit-transform: scale(1.5); transform: scale(1.5); } } @keyframes pulse-animation { 0% { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } 50% { opacity: 0; -webkit-transform: scale(1.5); transform: scale(1.5); } 100% { opacity: 0; -webkit-transform: scale(1.5); transform: scale(1.5); } } /* Modal */ .datepicker-modal { max-width: 325px; min-width: 300px; max-height: none; } .datepicker-container.modal-content { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; padding: 0; } .datepicker-controls { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; width: 280px; margin: 0 auto; } .datepicker-controls .selects-container { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } .datepicker-controls .select-wrapper input { border-bottom: none; text-align: center; margin: 0; } .datepicker-controls .select-wrapper input:focus { border-bottom: none; } .datepicker-controls .select-wrapper .caret { display: none; } .datepicker-controls .select-year input { width: 50px; } .datepicker-controls .select-month input { width: 70px; } .month-prev, .month-next { margin-top: 4px; cursor: pointer; background-color: transparent; border: none; } /* Date Display */ .datepicker-date-display { -webkit-box-flex: 1; -webkit-flex: 1 auto; -ms-flex: 1 auto; flex: 1 auto; background-color: #26a69a; color: #fff; padding: 20px 22px; font-weight: 500; } .datepicker-date-display .year-text { display: block; font-size: 1.5rem; line-height: 25px; color: rgba(255, 255, 255, 0.7); } .datepicker-date-display .date-text { display: block; font-size: 2.8rem; line-height: 47px; font-weight: 500; } /* Calendar */ .datepicker-calendar-container { -webkit-box-flex: 2.5; -webkit-flex: 2.5 auto; -ms-flex: 2.5 auto; flex: 2.5 auto; } .datepicker-table { width: 280px; font-size: 1rem; margin: 0 auto; } .datepicker-table thead { border-bottom: none; } .datepicker-table th { padding: 10px 5px; text-align: center; } .datepicker-table tr { border: none; } .datepicker-table abbr { text-decoration: none; color: #999; } .datepicker-table td { border-radius: 50%; padding: 0; } .datepicker-table td.is-today { color: #26a69a; } .datepicker-table td.is-selected { background-color: #26a69a; color: #fff; } .datepicker-table td.is-outside-current-month, .datepicker-table td.is-disabled { color: rgba(0, 0, 0, 0.3); pointer-events: none; } .datepicker-day-button { background-color: transparent; border: none; line-height: 38px; display: block; width: 100%; border-radius: 50%; padding: 0 5px; cursor: pointer; color: inherit; } .datepicker-day-button:focus { background-color: rgba(43, 161, 150, 0.25); } /* Footer */ .datepicker-footer { width: 280px; margin: 0 auto; padding-bottom: 5px; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; } .datepicker-cancel, .datepicker-clear, .datepicker-today, .datepicker-done { color: #26a69a; padding: 0 1rem; } .datepicker-clear { color: #F44336; } /* Media Queries */ @media only screen and (min-width: 601px) { .datepicker-modal { max-width: 625px; } .datepicker-container.modal-content { -webkit-box-orient: horizontal; -webkit-box-direction: normal; -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; } .datepicker-date-display { -webkit-box-flex: 0; -webkit-flex: 0 1 270px; -ms-flex: 0 1 270px; flex: 0 1 270px; } .datepicker-controls, .datepicker-table, .datepicker-footer { width: 320px; } .datepicker-day-button { line-height: 44px; } } /* Timepicker Containers */ .timepicker-modal { max-width: 325px; max-height: none; } .timepicker-container.modal-content { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; padding: 0; } .text-primary { color: white; } /* Clock Digital Display */ .timepicker-digital-display { -webkit-box-flex: 1; -webkit-flex: 1 auto; -ms-flex: 1 auto; flex: 1 auto; background-color: #26a69a; padding: 10px; font-weight: 300; } .timepicker-text-container { font-size: 4rem; font-weight: bold; text-align: center; color: rgba(255, 255, 255, 0.6); font-weight: 400; position: relative; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .timepicker-span-hours, .timepicker-span-minutes, .timepicker-span-am-pm div { cursor: pointer; } .timepicker-span-hours { margin-right: 3px; } .timepicker-span-minutes { margin-left: 3px; } .timepicker-display-am-pm { font-size: 1.3rem; position: absolute; right: 1rem; bottom: 1rem; font-weight: 400; } /* Analog Clock Display */ .timepicker-analog-display { -webkit-box-flex: 2.5; -webkit-flex: 2.5 auto; -ms-flex: 2.5 auto; flex: 2.5 auto; } .timepicker-plate { background-color: #eee; border-radius: 50%; width: 270px; height: 270px; overflow: visible; position: relative; margin: auto; margin-top: 25px; margin-bottom: 5px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .timepicker-canvas, .timepicker-dial { position: absolute; left: 0; right: 0; top: 0; bottom: 0; } .timepicker-minutes { visibility: hidden; } .timepicker-tick { border-radius: 50%; color: rgba(0, 0, 0, 0.87); line-height: 40px; text-align: center; width: 40px; height: 40px; position: absolute; cursor: pointer; font-size: 15px; } .timepicker-tick.active, .timepicker-tick:hover { background-color: rgba(38, 166, 154, 0.25); } .timepicker-dial { -webkit-transition: opacity 350ms, -webkit-transform 350ms; transition: opacity 350ms, -webkit-transform 350ms; transition: transform 350ms, opacity 350ms; transition: transform 350ms, opacity 350ms, -webkit-transform 350ms; } .timepicker-dial-out { opacity: 0; } .timepicker-dial-out.timepicker-hours { -webkit-transform: scale(1.1, 1.1); transform: scale(1.1, 1.1); } .timepicker-dial-out.timepicker-minutes { -webkit-transform: scale(0.8, 0.8); transform: scale(0.8, 0.8); } .timepicker-canvas { -webkit-transition: opacity 175ms; transition: opacity 175ms; } .timepicker-canvas line { stroke: #26a69a; stroke-width: 4; stroke-linecap: round; } .timepicker-canvas-out { opacity: 0.25; } .timepicker-canvas-bearing { stroke: none; fill: #26a69a; } .timepicker-canvas-bg { stroke: none; fill: #26a69a; } /* Footer */ .timepicker-footer { margin: 0 auto; padding: 5px 1rem; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between; } .timepicker-clear { color: #F44336; } .timepicker-close { color: #26a69a; } .timepicker-clear, .timepicker-close { padding: 0 20px; } /* Media Queries */ @media only screen and (min-width: 601px) { .timepicker-modal { max-width: 600px; } .timepicker-container.modal-content { -webkit-box-orient: horizontal; -webkit-box-direction: normal; -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; } .timepicker-text-container { top: 32%; } .timepicker-display-am-pm { position: relative; right: auto; bottom: auto; text-align: center; margin-top: 1.2rem; } } ================================================ FILE: public/css/seat-base.css ================================================ a,.dropdown-content li>a { color: #44A729; } a:hover { color: #55544B; text-decoration: underline; } /* begin: Pour le menu "user" en haut à gauche*/ .dropdown-content li>a:hover, .dropdown-content li>span:hover{ color: #44A729; text-decoration: none; } .dropdown-content li>a, .dropdown-content li>span { color: #44A729; } /* end: Pour le menu "user" en haut à gauche*/ .important { color: #44A729; } .seat-green { background-color: #44A729; } .seat-green2 { background-color: #91BD10; } .seat-orange { background-color: #eaad00; } .seat-orange2 { background-color: #fecc00; } .seat-text-green { color: #44A729; } .seat-text-green2 { color: #91BD10; } .seat-text-orange { color: #eaad00; } .seat-text-orange2 { color: #fecc00; } .btn { background-color: #eaad00; } .btn:hover { background-color: #fecc00; } .btn:focus { background-color: #eaad00; } body { background-color: transparent; /*font-family: Calibri, "Helvetica Neue", Arial, Helvetica, sans-serif;*/ } .btn-full { display: block; width: 100%; } .seat-main-container { width: 100%; } @media only screen and (max-width: 600px) { .menu .card .card-content { padding: 0; } .row .col.menu { padding: 0; } } /* begin: Panier sur la droite */ .panier-item { margin-bottom: 10px; } .panier-item .divider { margin-top: 5px; } .inline-icon { vertical-align: bottom; font-size: 18px !important; } .panier-total { margin-bottom: 10px; } .panier-total-price { display: flex; justify-content: space-between; } .panier-total-price-label { font-weight: bold; } .panier-total .divider { margin-top: 15px; } .remove-from-basket { font-size: 80%; } /* end: Panier sur la droite */ /* begin: carte take away */ .products { display: flex; flex-direction: row; justify-content: space-between; flex-wrap: wrap; list-style-type: none; } .product { position: relative; justify-content: space-between; margin-bottom: 16px; padding: 16px; border: 1px solid transparent; border-radius: 2px; background-color: #f9f9f9; box-shadow: none; outline: none; transition: box-shadow 0.2s ease-in-out; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; flex: 0 1 46%; flex-direction: row; } .category { text-align: center; font-size: 2.28rem; line-height: 110%; margin: 1.52rem 0 .912rem 0; } .product-info { display: flex; justify-content: space-between; } .product-name { font-weight: bold; } #product-modal .modal-content { padding: 0; } #product-modal .title { padding: 10px; } #product-modal .sector { background-color: #e8ebeb; padding: 8px 24px; } #product-modal .supplements { padding: 0 10px; } #product-modal .options { padding: 10px 10px; } #product-modal .comments { padding: 10px 10px; } #product-modal .modal-sub-footer { display: flex; flex-direction: row; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; } #product-modal .modal-sub-footer .quantity-zone { margin: auto; } #product-modal .modal-sub-footer .quantity-zone .quantity { text-align: center; width: 50px; display: inline-block; } #product-modal .modal-sub-footer .add { position: absolute; right: 5px; } @media only screen and (max-width: 600px) { #product-modal { width: 100%; max-height: 100%; height: 100%; top: 0 !important; } .product { flex: 1 1 100%; margin: 0; border: none; border-radius: 0; border-left: none; border-right: none; border-top: 1px solid #e8ebeb; border-bottom: none; } .product:last-child { border-bottom: 1px solid #e8ebeb; } } /* end: carte take away */ .footer-to-order-on-mobile { position: fixed; bottom: 0; width: 100%; z-index: 1; background-color: white; padding: 5px 10% } ================================================ FILE: public/css/seat.css ================================================ html { background: url('/images/background1.jpg') no-repeat center center fixed; -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover; } ================================================ FILE: public/ico/browserconfig.xml ================================================ #ffffff ================================================ FILE: public/ico/manifest.json ================================================ { "name": "App", "icons": [ { "src": "\/android-icon-36x36.png", "sizes": "36x36", "type": "image\/png", "density": "0.75" }, { "src": "\/android-icon-48x48.png", "sizes": "48x48", "type": "image\/png", "density": "1.0" }, { "src": "\/android-icon-72x72.png", "sizes": "72x72", "type": "image\/png", "density": "1.5" }, { "src": "\/android-icon-96x96.png", "sizes": "96x96", "type": "image\/png", "density": "2.0" }, { "src": "\/android-icon-144x144.png", "sizes": "144x144", "type": "image\/png", "density": "3.0" }, { "src": "\/android-icon-192x192.png", "sizes": "192x192", "type": "image\/png", "density": "4.0" } ] } ================================================ FILE: public/index.php ================================================ handle($request); $response->send(); $kernel->terminate($request, $response); ================================================ FILE: public/js/materialize.js ================================================ /*! * Materialize v1.0.0 (http://materializecss.com) * Copyright 2014-2017 Materialize * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) */ var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /*! cash-dom 1.3.5, https://github.com/kenwheeler/cash @license MIT */ (function (factory) { window.cash = factory(); })(function () { var doc = document, win = window, ArrayProto = Array.prototype, slice = ArrayProto.slice, filter = ArrayProto.filter, push = ArrayProto.push; var noop = function () {}, isFunction = function (item) { // @see https://crbug.com/568448 return typeof item === typeof noop && item.call; }, isString = function (item) { return typeof item === typeof ""; }; var idMatch = /^#[\w-]*$/, classMatch = /^\.[\w-]*$/, htmlMatch = /<.+>/, singlet = /^\w+$/; function find(selector, context) { context = context || doc; var elems = classMatch.test(selector) ? context.getElementsByClassName(selector.slice(1)) : singlet.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector); return elems; } var frag; function parseHTML(str) { if (!frag) { frag = doc.implementation.createHTMLDocument(null); var base = frag.createElement("base"); base.href = doc.location.href; frag.head.appendChild(base); } frag.body.innerHTML = str; return frag.body.childNodes; } function onReady(fn) { if (doc.readyState !== "loading") { fn(); } else { doc.addEventListener("DOMContentLoaded", fn); } } function Init(selector, context) { if (!selector) { return this; } // If already a cash collection, don't do any further processing if (selector.cash && selector !== win) { return selector; } var elems = selector, i = 0, length; if (isString(selector)) { elems = idMatch.test(selector) ? // If an ID use the faster getElementById check doc.getElementById(selector.slice(1)) : htmlMatch.test(selector) ? // If HTML, parse it into real elements parseHTML(selector) : // else use `find` find(selector, context); // If function, use as shortcut for DOM ready } else if (isFunction(selector)) { onReady(selector);return this; } if (!elems) { return this; } // If a single DOM element is passed in or received via ID, return the single element if (elems.nodeType || elems === win) { this[0] = elems; this.length = 1; } else { // Treat like an array and loop through each item. length = this.length = elems.length; for (; i < length; i++) { this[i] = elems[i]; } } return this; } function cash(selector, context) { return new Init(selector, context); } var fn = cash.fn = cash.prototype = Init.prototype = { // jshint ignore:line cash: true, length: 0, push: push, splice: ArrayProto.splice, map: ArrayProto.map, init: Init }; Object.defineProperty(fn, "constructor", { value: cash }); cash.parseHTML = parseHTML; cash.noop = noop; cash.isFunction = isFunction; cash.isString = isString; cash.extend = fn.extend = function (target) { target = target || {}; var args = slice.call(arguments), length = args.length, i = 1; if (args.length === 1) { target = this; i = 0; } for (; i < length; i++) { if (!args[i]) { continue; } for (var key in args[i]) { if (args[i].hasOwnProperty(key)) { target[key] = args[i][key]; } } } return target; }; function each(collection, callback) { var l = collection.length, i = 0; for (; i < l; i++) { if (callback.call(collection[i], collection[i], i, collection) === false) { break; } } } function matches(el, selector) { var m = el && (el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector || el.oMatchesSelector); return !!m && m.call(el, selector); } function getCompareFunction(selector) { return ( /* Use browser's `matches` function if string */ isString(selector) ? matches : /* Match a cash element */ selector.cash ? function (el) { return selector.is(el); } : /* Direct comparison */ function (el, selector) { return el === selector; } ); } function unique(collection) { return cash(slice.call(collection).filter(function (item, index, self) { return self.indexOf(item) === index; })); } cash.extend({ merge: function (first, second) { var len = +second.length, i = first.length, j = 0; for (; j < len; i++, j++) { first[i] = second[j]; } first.length = i; return first; }, each: each, matches: matches, unique: unique, isArray: Array.isArray, isNumeric: function (n) { return !isNaN(parseFloat(n)) && isFinite(n); } }); var uid = cash.uid = "_cash" + Date.now(); function getDataCache(node) { return node[uid] = node[uid] || {}; } function setData(node, key, value) { return getDataCache(node)[key] = value; } function getData(node, key) { var c = getDataCache(node); if (c[key] === undefined) { c[key] = node.dataset ? node.dataset[key] : cash(node).attr("data-" + key); } return c[key]; } function removeData(node, key) { var c = getDataCache(node); if (c) { delete c[key]; } else if (node.dataset) { delete node.dataset[key]; } else { cash(node).removeAttr("data-" + name); } } fn.extend({ data: function (name, value) { if (isString(name)) { return value === undefined ? getData(this[0], name) : this.each(function (v) { return setData(v, name, value); }); } for (var key in name) { this.data(key, name[key]); } return this; }, removeData: function (key) { return this.each(function (v) { return removeData(v, key); }); } }); var notWhiteMatch = /\S+/g; function getClasses(c) { return isString(c) && c.match(notWhiteMatch); } function hasClass(v, c) { return v.classList ? v.classList.contains(c) : new RegExp("(^| )" + c + "( |$)", "gi").test(v.className); } function addClass(v, c, spacedName) { if (v.classList) { v.classList.add(c); } else if (spacedName.indexOf(" " + c + " ")) { v.className += " " + c; } } function removeClass(v, c) { if (v.classList) { v.classList.remove(c); } else { v.className = v.className.replace(c, ""); } } fn.extend({ addClass: function (c) { var classes = getClasses(c); return classes ? this.each(function (v) { var spacedName = " " + v.className + " "; each(classes, function (c) { addClass(v, c, spacedName); }); }) : this; }, attr: function (name, value) { if (!name) { return undefined; } if (isString(name)) { if (value === undefined) { return this[0] ? this[0].getAttribute ? this[0].getAttribute(name) : this[0][name] : undefined; } return this.each(function (v) { if (v.setAttribute) { v.setAttribute(name, value); } else { v[name] = value; } }); } for (var key in name) { this.attr(key, name[key]); } return this; }, hasClass: function (c) { var check = false, classes = getClasses(c); if (classes && classes.length) { this.each(function (v) { check = hasClass(v, classes[0]); return !check; }); } return check; }, prop: function (name, value) { if (isString(name)) { return value === undefined ? this[0][name] : this.each(function (v) { v[name] = value; }); } for (var key in name) { this.prop(key, name[key]); } return this; }, removeAttr: function (name) { return this.each(function (v) { if (v.removeAttribute) { v.removeAttribute(name); } else { delete v[name]; } }); }, removeClass: function (c) { if (!arguments.length) { return this.attr("class", ""); } var classes = getClasses(c); return classes ? this.each(function (v) { each(classes, function (c) { removeClass(v, c); }); }) : this; }, removeProp: function (name) { return this.each(function (v) { delete v[name]; }); }, toggleClass: function (c, state) { if (state !== undefined) { return this[state ? "addClass" : "removeClass"](c); } var classes = getClasses(c); return classes ? this.each(function (v) { var spacedName = " " + v.className + " "; each(classes, function (c) { if (hasClass(v, c)) { removeClass(v, c); } else { addClass(v, c, spacedName); } }); }) : this; } }); fn.extend({ add: function (selector, context) { return unique(cash.merge(this, cash(selector, context))); }, each: function (callback) { each(this, callback); return this; }, eq: function (index) { return cash(this.get(index)); }, filter: function (selector) { if (!selector) { return this; } var comparator = isFunction(selector) ? selector : getCompareFunction(selector); return cash(filter.call(this, function (e) { return comparator(e, selector); })); }, first: function () { return this.eq(0); }, get: function (index) { if (index === undefined) { return slice.call(this); } return index < 0 ? this[index + this.length] : this[index]; }, index: function (elem) { var child = elem ? cash(elem)[0] : this[0], collection = elem ? this : cash(child).parent().children(); return slice.call(collection).indexOf(child); }, last: function () { return this.eq(-1); } }); var camelCase = function () { var camelRegex = /(?:^\w|[A-Z]|\b\w)/g, whiteSpace = /[\s-_]+/g; return function (str) { return str.replace(camelRegex, function (letter, index) { return letter[index === 0 ? "toLowerCase" : "toUpperCase"](); }).replace(whiteSpace, ""); }; }(); var getPrefixedProp = function () { var cache = {}, doc = document, div = doc.createElement("div"), style = div.style; return function (prop) { prop = camelCase(prop); if (cache[prop]) { return cache[prop]; } var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), prefixes = ["webkit", "moz", "ms", "o"], props = (prop + " " + prefixes.join(ucProp + " ") + ucProp).split(" "); each(props, function (p) { if (p in style) { cache[p] = prop = cache[prop] = p; return false; } }); return cache[prop]; }; }(); cash.prefixedProp = getPrefixedProp; cash.camelCase = camelCase; fn.extend({ css: function (prop, value) { if (isString(prop)) { prop = getPrefixedProp(prop); return arguments.length > 1 ? this.each(function (v) { return v.style[prop] = value; }) : win.getComputedStyle(this[0])[prop]; } for (var key in prop) { this.css(key, prop[key]); } return this; } }); function compute(el, prop) { return parseInt(win.getComputedStyle(el[0], null)[prop], 10) || 0; } each(["Width", "Height"], function (v) { var lower = v.toLowerCase(); fn[lower] = function () { return this[0].getBoundingClientRect()[lower]; }; fn["inner" + v] = function () { return this[0]["client" + v]; }; fn["outer" + v] = function (margins) { return this[0]["offset" + v] + (margins ? compute(this, "margin" + (v === "Width" ? "Left" : "Top")) + compute(this, "margin" + (v === "Width" ? "Right" : "Bottom")) : 0); }; }); function registerEvent(node, eventName, callback) { var eventCache = getData(node, "_cashEvents") || setData(node, "_cashEvents", {}); eventCache[eventName] = eventCache[eventName] || []; eventCache[eventName].push(callback); node.addEventListener(eventName, callback); } function removeEvent(node, eventName, callback) { var events = getData(node, "_cashEvents"), eventCache = events && events[eventName], index; if (!eventCache) { return; } if (callback) { node.removeEventListener(eventName, callback); index = eventCache.indexOf(callback); if (index >= 0) { eventCache.splice(index, 1); } } else { each(eventCache, function (event) { node.removeEventListener(eventName, event); }); eventCache = []; } } fn.extend({ off: function (eventName, callback) { return this.each(function (v) { return removeEvent(v, eventName, callback); }); }, on: function (eventName, delegate, callback, runOnce) { // jshint ignore:line var originalCallback; if (!isString(eventName)) { for (var key in eventName) { this.on(key, delegate, eventName[key]); } return this; } if (isFunction(delegate)) { callback = delegate; delegate = null; } if (eventName === "ready") { onReady(callback); return this; } if (delegate) { originalCallback = callback; callback = function (e) { var t = e.target; while (!matches(t, delegate)) { if (t === this || t === null) { return t = false; } t = t.parentNode; } if (t) { originalCallback.call(t, e); } }; } return this.each(function (v) { var finalCallback = callback; if (runOnce) { finalCallback = function () { callback.apply(this, arguments); removeEvent(v, eventName, finalCallback); }; } registerEvent(v, eventName, finalCallback); }); }, one: function (eventName, delegate, callback) { return this.on(eventName, delegate, callback, true); }, ready: onReady, /** * Modified * Triggers browser event * @param String eventName * @param Object data - Add properties to event object */ trigger: function (eventName, data) { if (document.createEvent) { var evt = document.createEvent('HTMLEvents'); evt.initEvent(eventName, true, false); evt = this.extend(evt, data); return this.each(function (v) { return v.dispatchEvent(evt); }); } } }); function encode(name, value) { return "&" + encodeURIComponent(name) + "=" + encodeURIComponent(value).replace(/%20/g, "+"); } function getSelectMultiple_(el) { var values = []; each(el.options, function (o) { if (o.selected) { values.push(o.value); } }); return values.length ? values : null; } function getSelectSingle_(el) { var selectedIndex = el.selectedIndex; return selectedIndex >= 0 ? el.options[selectedIndex].value : null; } function getValue(el) { var type = el.type; if (!type) { return null; } switch (type.toLowerCase()) { case "select-one": return getSelectSingle_(el); case "select-multiple": return getSelectMultiple_(el); case "radio": return el.checked ? el.value : null; case "checkbox": return el.checked ? el.value : null; default: return el.value ? el.value : null; } } fn.extend({ serialize: function () { var query = ""; each(this[0].elements || this, function (el) { if (el.disabled || el.tagName === "FIELDSET") { return; } var name = el.name; switch (el.type.toLowerCase()) { case "file": case "reset": case "submit": case "button": break; case "select-multiple": var values = getValue(el); if (values !== null) { each(values, function (value) { query += encode(name, value); }); } break; default: var value = getValue(el); if (value !== null) { query += encode(name, value); } } }); return query.substr(1); }, val: function (value) { if (value === undefined) { return getValue(this[0]); } return this.each(function (v) { return v.value = value; }); } }); function insertElement(el, child, prepend) { if (prepend) { var first = el.childNodes[0]; el.insertBefore(child, first); } else { el.appendChild(child); } } function insertContent(parent, child, prepend) { var str = isString(child); if (!str && child.length) { each(child, function (v) { return insertContent(parent, v, prepend); }); return; } each(parent, str ? function (v) { return v.insertAdjacentHTML(prepend ? "afterbegin" : "beforeend", child); } : function (v, i) { return insertElement(v, i === 0 ? child : child.cloneNode(true), prepend); }); } fn.extend({ after: function (selector) { cash(selector).insertAfter(this); return this; }, append: function (content) { insertContent(this, content); return this; }, appendTo: function (parent) { insertContent(cash(parent), this); return this; }, before: function (selector) { cash(selector).insertBefore(this); return this; }, clone: function () { return cash(this.map(function (v) { return v.cloneNode(true); })); }, empty: function () { this.html(""); return this; }, html: function (content) { if (content === undefined) { return this[0].innerHTML; } var source = content.nodeType ? content[0].outerHTML : content; return this.each(function (v) { return v.innerHTML = source; }); }, insertAfter: function (selector) { var _this = this; cash(selector).each(function (el, i) { var parent = el.parentNode, sibling = el.nextSibling; _this.each(function (v) { parent.insertBefore(i === 0 ? v : v.cloneNode(true), sibling); }); }); return this; }, insertBefore: function (selector) { var _this2 = this; cash(selector).each(function (el, i) { var parent = el.parentNode; _this2.each(function (v) { parent.insertBefore(i === 0 ? v : v.cloneNode(true), el); }); }); return this; }, prepend: function (content) { insertContent(this, content, true); return this; }, prependTo: function (parent) { insertContent(cash(parent), this, true); return this; }, remove: function () { return this.each(function (v) { if (!!v.parentNode) { return v.parentNode.removeChild(v); } }); }, text: function (content) { if (content === undefined) { return this[0].textContent; } return this.each(function (v) { return v.textContent = content; }); } }); var docEl = doc.documentElement; fn.extend({ position: function () { var el = this[0]; return { left: el.offsetLeft, top: el.offsetTop }; }, offset: function () { var rect = this[0].getBoundingClientRect(); return { top: rect.top + win.pageYOffset - docEl.clientTop, left: rect.left + win.pageXOffset - docEl.clientLeft }; }, offsetParent: function () { return cash(this[0].offsetParent); } }); fn.extend({ children: function (selector) { var elems = []; this.each(function (el) { push.apply(elems, el.children); }); elems = unique(elems); return !selector ? elems : elems.filter(function (v) { return matches(v, selector); }); }, closest: function (selector) { if (!selector || this.length < 1) { return cash(); } if (this.is(selector)) { return this.filter(selector); } return this.parent().closest(selector); }, is: function (selector) { if (!selector) { return false; } var match = false, comparator = getCompareFunction(selector); this.each(function (el) { match = comparator(el, selector); return !match; }); return match; }, find: function (selector) { if (!selector || selector.nodeType) { return cash(selector && this.has(selector).length ? selector : null); } var elems = []; this.each(function (el) { push.apply(elems, find(selector, el)); }); return unique(elems); }, has: function (selector) { var comparator = isString(selector) ? function (el) { return find(selector, el).length !== 0; } : function (el) { return el.contains(selector); }; return this.filter(comparator); }, next: function () { return cash(this[0].nextElementSibling); }, not: function (selector) { if (!selector) { return this; } var comparator = getCompareFunction(selector); return this.filter(function (el) { return !comparator(el, selector); }); }, parent: function () { var result = []; this.each(function (item) { if (item && item.parentNode) { result.push(item.parentNode); } }); return unique(result); }, parents: function (selector) { var last, result = []; this.each(function (item) { last = item; while (last && last.parentNode && last !== doc.body.parentNode) { last = last.parentNode; if (!selector || selector && matches(last, selector)) { result.push(last); } } }); return unique(result); }, prev: function () { return cash(this[0].previousElementSibling); }, siblings: function (selector) { var collection = this.parent().children(selector), el = this[0]; return collection.filter(function (i) { return i !== el; }); } }); return cash; }); ; var Component = function () { /** * Generic constructor for all components * @constructor * @param {Element} el * @param {Object} options */ function Component(classDef, el, options) { _classCallCheck(this, Component); // Display error if el is valid HTML Element if (!(el instanceof Element)) { console.error(Error(el + ' is not an HTML Element')); } // If exists, destroy and reinitialize in child var ins = classDef.getInstance(el); if (!!ins) { ins.destroy(); } this.el = el; this.$el = cash(el); } /** * Initializes components * @param {class} classDef * @param {Element | NodeList | jQuery} els * @param {Object} options */ _createClass(Component, null, [{ key: "init", value: function init(classDef, els, options) { var instances = null; if (els instanceof Element) { instances = new classDef(els, options); } else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) { var instancesArr = []; for (var i = 0; i < els.length; i++) { instancesArr.push(new classDef(els[i], options)); } instances = instancesArr; } return instances; } }]); return Component; }(); ; // Required for Meteor package, the use of window prevents export by Meteor (function (window) { if (window.Package) { M = {}; } else { window.M = {}; } // Check for jQuery M.jQueryLoaded = !!window.jQuery; })(window); // AMD if (typeof define === 'function' && define.amd) { define('M', [], function () { return M; }); // Common JS } else if (typeof exports !== 'undefined' && !exports.nodeType) { if (typeof module !== 'undefined' && !module.nodeType && module.exports) { exports = module.exports = M; } exports.default = M; } M.version = '1.0.0'; M.keys = { TAB: 9, ENTER: 13, ESC: 27, ARROW_UP: 38, ARROW_DOWN: 40 }; /** * TabPress Keydown handler */ M.tabPressed = false; M.keyDown = false; var docHandleKeydown = function (e) { M.keyDown = true; if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) { M.tabPressed = true; } }; var docHandleKeyup = function (e) { M.keyDown = false; if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) { M.tabPressed = false; } }; var docHandleFocus = function (e) { if (M.keyDown) { document.body.classList.add('keyboard-focused'); } }; var docHandleBlur = function (e) { document.body.classList.remove('keyboard-focused'); }; document.addEventListener('keydown', docHandleKeydown, true); document.addEventListener('keyup', docHandleKeyup, true); document.addEventListener('focus', docHandleFocus, true); document.addEventListener('blur', docHandleBlur, true); /** * Initialize jQuery wrapper for plugin * @param {Class} plugin javascript class * @param {string} pluginName jQuery plugin name * @param {string} classRef Class reference name */ M.initializeJqueryWrapper = function (plugin, pluginName, classRef) { jQuery.fn[pluginName] = function (methodOrOptions) { // Call plugin method if valid method name is passed in if (plugin.prototype[methodOrOptions]) { var params = Array.prototype.slice.call(arguments, 1); // Getter methods if (methodOrOptions.slice(0, 3) === 'get') { var instance = this.first()[0][classRef]; return instance[methodOrOptions].apply(instance, params); } // Void methods return this.each(function () { var instance = this[classRef]; instance[methodOrOptions].apply(instance, params); }); // Initialize plugin if options or no argument is passed in } else if (typeof methodOrOptions === 'object' || !methodOrOptions) { plugin.init(this, arguments[0]); return this; } // Return error if an unrecognized method name is passed in jQuery.error("Method " + methodOrOptions + " does not exist on jQuery." + pluginName); }; }; /** * Automatically initialize components * @param {Element} context DOM Element to search within for components */ M.AutoInit = function (context) { // Use document.body if no context is given var root = !!context ? context : document.body; var registry = { Autocomplete: root.querySelectorAll('.autocomplete:not(.no-autoinit)'), Carousel: root.querySelectorAll('.carousel:not(.no-autoinit)'), Chips: root.querySelectorAll('.chips:not(.no-autoinit)'), Collapsible: root.querySelectorAll('.collapsible:not(.no-autoinit)'), Datepicker: root.querySelectorAll('.datepicker:not(.no-autoinit)'), Dropdown: root.querySelectorAll('.dropdown-trigger:not(.no-autoinit)'), Materialbox: root.querySelectorAll('.materialboxed:not(.no-autoinit)'), Modal: root.querySelectorAll('.modal:not(.no-autoinit)'), Parallax: root.querySelectorAll('.parallax:not(.no-autoinit)'), Pushpin: root.querySelectorAll('.pushpin:not(.no-autoinit)'), ScrollSpy: root.querySelectorAll('.scrollspy:not(.no-autoinit)'), FormSelect: root.querySelectorAll('select:not(.no-autoinit)'), Sidenav: root.querySelectorAll('.sidenav:not(.no-autoinit)'), Tabs: root.querySelectorAll('.tabs:not(.no-autoinit)'), TapTarget: root.querySelectorAll('.tap-target:not(.no-autoinit)'), Timepicker: root.querySelectorAll('.timepicker:not(.no-autoinit)'), Tooltip: root.querySelectorAll('.tooltipped:not(.no-autoinit)'), FloatingActionButton: root.querySelectorAll('.fixed-action-btn:not(.no-autoinit)') }; for (var pluginName in registry) { var plugin = M[pluginName]; plugin.init(registry[pluginName]); } }; /** * Generate approximated selector string for a jQuery object * @param {jQuery} obj jQuery object to be parsed * @returns {string} */ M.objectSelectorString = function (obj) { var tagStr = obj.prop('tagName') || ''; var idStr = obj.attr('id') || ''; var classStr = obj.attr('class') || ''; return (tagStr + idStr + classStr).replace(/\s/g, ''); }; // Unique Random ID M.guid = function () { function s4() { return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); } return function () { return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); }; }(); /** * Escapes hash from special characters * @param {string} hash String returned from this.hash * @returns {string} */ M.escapeHash = function (hash) { return hash.replace(/(:|\.|\[|\]|,|=|\/)/g, '\\$1'); }; M.elementOrParentIsFixed = function (element) { var $element = $(element); var $checkElements = $element.add($element.parents()); var isFixed = false; $checkElements.each(function () { if ($(this).css('position') === 'fixed') { isFixed = true; return false; } }); return isFixed; }; /** * @typedef {Object} Edges * @property {Boolean} top If the top edge was exceeded * @property {Boolean} right If the right edge was exceeded * @property {Boolean} bottom If the bottom edge was exceeded * @property {Boolean} left If the left edge was exceeded */ /** * @typedef {Object} Bounding * @property {Number} left left offset coordinate * @property {Number} top top offset coordinate * @property {Number} width * @property {Number} height */ /** * Escapes hash from special characters * @param {Element} container Container element that acts as the boundary * @param {Bounding} bounding element bounding that is being checked * @param {Number} offset offset from edge that counts as exceeding * @returns {Edges} */ M.checkWithinContainer = function (container, bounding, offset) { var edges = { top: false, right: false, bottom: false, left: false }; var containerRect = container.getBoundingClientRect(); // If body element is smaller than viewport, use viewport height instead. var containerBottom = container === document.body ? Math.max(containerRect.bottom, window.innerHeight) : containerRect.bottom; var scrollLeft = container.scrollLeft; var scrollTop = container.scrollTop; var scrolledX = bounding.left - scrollLeft; var scrolledY = bounding.top - scrollTop; // Check for container and viewport for each edge if (scrolledX < containerRect.left + offset || scrolledX < offset) { edges.left = true; } if (scrolledX + bounding.width > containerRect.right - offset || scrolledX + bounding.width > window.innerWidth - offset) { edges.right = true; } if (scrolledY < containerRect.top + offset || scrolledY < offset) { edges.top = true; } if (scrolledY + bounding.height > containerBottom - offset || scrolledY + bounding.height > window.innerHeight - offset) { edges.bottom = true; } return edges; }; M.checkPossibleAlignments = function (el, container, bounding, offset) { var canAlign = { top: true, right: true, bottom: true, left: true, spaceOnTop: null, spaceOnRight: null, spaceOnBottom: null, spaceOnLeft: null }; var containerAllowsOverflow = getComputedStyle(container).overflow === 'visible'; var containerRect = container.getBoundingClientRect(); var containerHeight = Math.min(containerRect.height, window.innerHeight); var containerWidth = Math.min(containerRect.width, window.innerWidth); var elOffsetRect = el.getBoundingClientRect(); var scrollLeft = container.scrollLeft; var scrollTop = container.scrollTop; var scrolledX = bounding.left - scrollLeft; var scrolledYTopEdge = bounding.top - scrollTop; var scrolledYBottomEdge = bounding.top + elOffsetRect.height - scrollTop; // Check for container and viewport for left canAlign.spaceOnRight = !containerAllowsOverflow ? containerWidth - (scrolledX + bounding.width) : window.innerWidth - (elOffsetRect.left + bounding.width); if (canAlign.spaceOnRight < 0) { canAlign.left = false; } // Check for container and viewport for Right canAlign.spaceOnLeft = !containerAllowsOverflow ? scrolledX - bounding.width + elOffsetRect.width : elOffsetRect.right - bounding.width; if (canAlign.spaceOnLeft < 0) { canAlign.right = false; } // Check for container and viewport for Top canAlign.spaceOnBottom = !containerAllowsOverflow ? containerHeight - (scrolledYTopEdge + bounding.height + offset) : window.innerHeight - (elOffsetRect.top + bounding.height + offset); if (canAlign.spaceOnBottom < 0) { canAlign.top = false; } // Check for container and viewport for Bottom canAlign.spaceOnTop = !containerAllowsOverflow ? scrolledYBottomEdge - (bounding.height - offset) : elOffsetRect.bottom - (bounding.height + offset); if (canAlign.spaceOnTop < 0) { canAlign.bottom = false; } return canAlign; }; M.getOverflowParent = function (element) { if (element == null) { return null; } if (element === document.body || getComputedStyle(element).overflow !== 'visible') { return element; } return M.getOverflowParent(element.parentElement); }; /** * Gets id of component from a trigger * @param {Element} trigger trigger * @returns {string} */ M.getIdFromTrigger = function (trigger) { var id = trigger.getAttribute('data-target'); if (!id) { id = trigger.getAttribute('href'); if (id) { id = id.slice(1); } else { id = ''; } } return id; }; /** * Multi browser support for document scroll top * @returns {Number} */ M.getDocumentScrollTop = function () { return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }; /** * Multi browser support for document scroll left * @returns {Number} */ M.getDocumentScrollLeft = function () { return window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; }; /** * @typedef {Object} Edges * @property {Boolean} top If the top edge was exceeded * @property {Boolean} right If the right edge was exceeded * @property {Boolean} bottom If the bottom edge was exceeded * @property {Boolean} left If the left edge was exceeded */ /** * @typedef {Object} Bounding * @property {Number} left left offset coordinate * @property {Number} top top offset coordinate * @property {Number} width * @property {Number} height */ /** * Get time in ms * @license https://raw.github.com/jashkenas/underscore/master/LICENSE * @type {function} * @return {number} */ var getTime = Date.now || function () { return new Date().getTime(); }; /** * Returns a function, that, when invoked, will only be triggered at most once * during a given window of time. Normally, the throttled function will run * as much as it can, without ever going more than once per `wait` duration; * but if you'd like to disable the execution on the leading edge, pass * `{leading: false}`. To disable execution on the trailing edge, ditto. * @license https://raw.github.com/jashkenas/underscore/master/LICENSE * @param {function} func * @param {number} wait * @param {Object=} options * @returns {Function} */ M.throttle = function (func, wait, options) { var context = void 0, args = void 0, result = void 0; var timeout = null; var previous = 0; options || (options = {}); var later = function () { previous = options.leading === false ? 0 : getTime(); timeout = null; result = func.apply(context, args); context = args = null; }; return function () { var now = getTime(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0) { clearTimeout(timeout); timeout = null; previous = now; result = func.apply(context, args); context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; }; ; /* v2.2.0 2017 Julian Garnier Released under the MIT license */ var $jscomp = { scope: {} };$jscomp.defineProperty = "function" == typeof Object.defineProperties ? Object.defineProperty : function (e, r, p) { if (p.get || p.set) throw new TypeError("ES3 does not support getters and setters.");e != Array.prototype && e != Object.prototype && (e[r] = p.value); };$jscomp.getGlobal = function (e) { return "undefined" != typeof window && window === e ? e : "undefined" != typeof global && null != global ? global : e; };$jscomp.global = $jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX = "jscomp_symbol_"; $jscomp.initSymbol = function () { $jscomp.initSymbol = function () {};$jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol); };$jscomp.symbolCounter_ = 0;$jscomp.Symbol = function (e) { return $jscomp.SYMBOL_PREFIX + (e || "") + $jscomp.symbolCounter_++; }; $jscomp.initSymbolIterator = function () { $jscomp.initSymbol();var e = $jscomp.global.Symbol.iterator;e || (e = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator"));"function" != typeof Array.prototype[e] && $jscomp.defineProperty(Array.prototype, e, { configurable: !0, writable: !0, value: function () { return $jscomp.arrayIterator(this); } });$jscomp.initSymbolIterator = function () {}; };$jscomp.arrayIterator = function (e) { var r = 0;return $jscomp.iteratorPrototype(function () { return r < e.length ? { done: !1, value: e[r++] } : { done: !0 }; }); }; $jscomp.iteratorPrototype = function (e) { $jscomp.initSymbolIterator();e = { next: e };e[$jscomp.global.Symbol.iterator] = function () { return this; };return e; };$jscomp.array = $jscomp.array || {};$jscomp.iteratorFromArray = function (e, r) { $jscomp.initSymbolIterator();e instanceof String && (e += "");var p = 0, m = { next: function () { if (p < e.length) { var u = p++;return { value: r(u, e[u]), done: !1 }; }m.next = function () { return { done: !0, value: void 0 }; };return m.next(); } };m[Symbol.iterator] = function () { return m; };return m; }; $jscomp.polyfill = function (e, r, p, m) { if (r) { p = $jscomp.global;e = e.split(".");for (m = 0; m < e.length - 1; m++) { var u = e[m];u in p || (p[u] = {});p = p[u]; }e = e[e.length - 1];m = p[e];r = r(m);r != m && null != r && $jscomp.defineProperty(p, e, { configurable: !0, writable: !0, value: r }); } };$jscomp.polyfill("Array.prototype.keys", function (e) { return e ? e : function () { return $jscomp.iteratorFromArray(this, function (e) { return e; }); }; }, "es6-impl", "es3");var $jscomp$this = this; (function (r) { M.anime = r(); })(function () { function e(a) { if (!h.col(a)) try { return document.querySelectorAll(a); } catch (c) {} }function r(a, c) { for (var d = a.length, b = 2 <= arguments.length ? arguments[1] : void 0, f = [], n = 0; n < d; n++) { if (n in a) { var k = a[n];c.call(b, k, n, a) && f.push(k); } }return f; }function p(a) { return a.reduce(function (a, d) { return a.concat(h.arr(d) ? p(d) : d); }, []); }function m(a) { if (h.arr(a)) return a; h.str(a) && (a = e(a) || a);return a instanceof NodeList || a instanceof HTMLCollection ? [].slice.call(a) : [a]; }function u(a, c) { return a.some(function (a) { return a === c; }); }function C(a) { var c = {}, d;for (d in a) { c[d] = a[d]; }return c; }function D(a, c) { var d = C(a), b;for (b in a) { d[b] = c.hasOwnProperty(b) ? c[b] : a[b]; }return d; }function z(a, c) { var d = C(a), b;for (b in c) { d[b] = h.und(a[b]) ? c[b] : a[b]; }return d; }function T(a) { a = a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, function (a, c, d, k) { return c + c + d + d + k + k; });var c = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a); a = parseInt(c[1], 16);var d = parseInt(c[2], 16), c = parseInt(c[3], 16);return "rgba(" + a + "," + d + "," + c + ",1)"; }function U(a) { function c(a, c, b) { 0 > b && (b += 1);1 < b && --b;return b < 1 / 6 ? a + 6 * (c - a) * b : .5 > b ? c : b < 2 / 3 ? a + (c - a) * (2 / 3 - b) * 6 : a; }var d = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(a);a = parseInt(d[1]) / 360;var b = parseInt(d[2]) / 100, f = parseInt(d[3]) / 100, d = d[4] || 1;if (0 == b) f = b = a = f;else { var n = .5 > f ? f * (1 + b) : f + b - f * b, k = 2 * f - n, f = c(k, n, a + 1 / 3), b = c(k, n, a);a = c(k, n, a - 1 / 3); }return "rgba(" + 255 * f + "," + 255 * b + "," + 255 * a + "," + d + ")"; }function y(a) { if (a = /([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(a)) return a[2]; }function V(a) { if (-1 < a.indexOf("translate") || "perspective" === a) return "px";if (-1 < a.indexOf("rotate") || -1 < a.indexOf("skew")) return "deg"; }function I(a, c) { return h.fnc(a) ? a(c.target, c.id, c.total) : a; }function E(a, c) { if (c in a.style) return getComputedStyle(a).getPropertyValue(c.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()) || "0"; }function J(a, c) { if (h.dom(a) && u(W, c)) return "transform";if (h.dom(a) && (a.getAttribute(c) || h.svg(a) && a[c])) return "attribute";if (h.dom(a) && "transform" !== c && E(a, c)) return "css";if (null != a[c]) return "object"; }function X(a, c) { var d = V(c), d = -1 < c.indexOf("scale") ? 1 : 0 + d;a = a.style.transform;if (!a) return d;for (var b = [], f = [], n = [], k = /(\w+)\((.+?)\)/g; b = k.exec(a);) { f.push(b[1]), n.push(b[2]); }a = r(n, function (a, b) { return f[b] === c; });return a.length ? a[0] : d; }function K(a, c) { switch (J(a, c)) {case "transform": return X(a, c);case "css": return E(a, c);case "attribute": return a.getAttribute(c);}return a[c] || 0; }function L(a, c) { var d = /^(\*=|\+=|-=)/.exec(a);if (!d) return a;var b = y(a) || 0;c = parseFloat(c);a = parseFloat(a.replace(d[0], ""));switch (d[0][0]) {case "+": return c + a + b;case "-": return c - a + b;case "*": return c * a + b;} }function F(a, c) { return Math.sqrt(Math.pow(c.x - a.x, 2) + Math.pow(c.y - a.y, 2)); }function M(a) { a = a.points;for (var c = 0, d, b = 0; b < a.numberOfItems; b++) { var f = a.getItem(b);0 < b && (c += F(d, f));d = f; }return c; }function N(a) { if (a.getTotalLength) return a.getTotalLength();switch (a.tagName.toLowerCase()) {case "circle": return 2 * Math.PI * a.getAttribute("r");case "rect": return 2 * a.getAttribute("width") + 2 * a.getAttribute("height");case "line": return F({ x: a.getAttribute("x1"), y: a.getAttribute("y1") }, { x: a.getAttribute("x2"), y: a.getAttribute("y2") });case "polyline": return M(a);case "polygon": var c = a.points;return M(a) + F(c.getItem(c.numberOfItems - 1), c.getItem(0));} }function Y(a, c) { function d(b) { b = void 0 === b ? 0 : b;return a.el.getPointAtLength(1 <= c + b ? c + b : 0); }var b = d(), f = d(-1), n = d(1);switch (a.property) {case "x": return b.x;case "y": return b.y; case "angle": return 180 * Math.atan2(n.y - f.y, n.x - f.x) / Math.PI;} }function O(a, c) { var d = /-?\d*\.?\d+/g, b;b = h.pth(a) ? a.totalLength : a;if (h.col(b)) { if (h.rgb(b)) { var f = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(b);b = f ? "rgba(" + f[1] + ",1)" : b; } else b = h.hex(b) ? T(b) : h.hsl(b) ? U(b) : void 0; } else f = (f = y(b)) ? b.substr(0, b.length - f.length) : b, b = c && !/\s/g.test(b) ? f + c : f;b += "";return { original: b, numbers: b.match(d) ? b.match(d).map(Number) : [0], strings: h.str(a) || c ? b.split(d) : [] }; }function P(a) { a = a ? p(h.arr(a) ? a.map(m) : m(a)) : [];return r(a, function (a, d, b) { return b.indexOf(a) === d; }); }function Z(a) { var c = P(a);return c.map(function (a, b) { return { target: a, id: b, total: c.length }; }); }function aa(a, c) { var d = C(c);if (h.arr(a)) { var b = a.length;2 !== b || h.obj(a[0]) ? h.fnc(c.duration) || (d.duration = c.duration / b) : a = { value: a }; }return m(a).map(function (a, b) { b = b ? 0 : c.delay;a = h.obj(a) && !h.pth(a) ? a : { value: a };h.und(a.delay) && (a.delay = b);return a; }).map(function (a) { return z(a, d); }); }function ba(a, c) { var d = {}, b;for (b in a) { var f = I(a[b], c);h.arr(f) && (f = f.map(function (a) { return I(a, c); }), 1 === f.length && (f = f[0]));d[b] = f; }d.duration = parseFloat(d.duration);d.delay = parseFloat(d.delay);return d; }function ca(a) { return h.arr(a) ? A.apply(this, a) : Q[a]; }function da(a, c) { var d;return a.tweens.map(function (b) { b = ba(b, c);var f = b.value, e = K(c.target, a.name), k = d ? d.to.original : e, k = h.arr(f) ? f[0] : k, w = L(h.arr(f) ? f[1] : f, k), e = y(w) || y(k) || y(e);b.from = O(k, e);b.to = O(w, e);b.start = d ? d.end : a.offset;b.end = b.start + b.delay + b.duration;b.easing = ca(b.easing);b.elasticity = (1E3 - Math.min(Math.max(b.elasticity, 1), 999)) / 1E3;b.isPath = h.pth(f);b.isColor = h.col(b.from.original);b.isColor && (b.round = 1);return d = b; }); }function ea(a, c) { return r(p(a.map(function (a) { return c.map(function (b) { var c = J(a.target, b.name);if (c) { var d = da(b, a);b = { type: c, property: b.name, animatable: a, tweens: d, duration: d[d.length - 1].end, delay: d[0].delay }; } else b = void 0;return b; }); })), function (a) { return !h.und(a); }); }function R(a, c, d, b) { var f = "delay" === a;return c.length ? (f ? Math.min : Math.max).apply(Math, c.map(function (b) { return b[a]; })) : f ? b.delay : d.offset + b.delay + b.duration; }function fa(a) { var c = D(ga, a), d = D(S, a), b = Z(a.targets), f = [], e = z(c, d), k;for (k in a) { e.hasOwnProperty(k) || "targets" === k || f.push({ name: k, offset: e.offset, tweens: aa(a[k], d) }); }a = ea(b, f);return z(c, { children: [], animatables: b, animations: a, duration: R("duration", a, c, d), delay: R("delay", a, c, d) }); }function q(a) { function c() { return window.Promise && new Promise(function (a) { return p = a; }); }function d(a) { return g.reversed ? g.duration - a : a; }function b(a) { for (var b = 0, c = {}, d = g.animations, f = d.length; b < f;) { var e = d[b], k = e.animatable, h = e.tweens, n = h.length - 1, l = h[n];n && (l = r(h, function (b) { return a < b.end; })[0] || l);for (var h = Math.min(Math.max(a - l.start - l.delay, 0), l.duration) / l.duration, w = isNaN(h) ? 1 : l.easing(h, l.elasticity), h = l.to.strings, p = l.round, n = [], m = void 0, m = l.to.numbers.length, t = 0; t < m; t++) { var x = void 0, x = l.to.numbers[t], q = l.from.numbers[t], x = l.isPath ? Y(l.value, w * x) : q + w * (x - q);p && (l.isColor && 2 < t || (x = Math.round(x * p) / p));n.push(x); }if (l = h.length) for (m = h[0], w = 0; w < l; w++) { p = h[w + 1], t = n[w], isNaN(t) || (m = p ? m + (t + p) : m + (t + " ")); } else m = n[0];ha[e.type](k.target, e.property, m, c, k.id);e.currentValue = m;b++; }if (b = Object.keys(c).length) for (d = 0; d < b; d++) { H || (H = E(document.body, "transform") ? "transform" : "-webkit-transform"), g.animatables[d].target.style[H] = c[d].join(" "); }g.currentTime = a;g.progress = a / g.duration * 100; }function f(a) { if (g[a]) g[a](g); }function e() { g.remaining && !0 !== g.remaining && g.remaining--; }function k(a) { var k = g.duration, n = g.offset, w = n + g.delay, r = g.currentTime, x = g.reversed, q = d(a);if (g.children.length) { var u = g.children, v = u.length; if (q >= g.currentTime) for (var G = 0; G < v; G++) { u[G].seek(q); } else for (; v--;) { u[v].seek(q); } }if (q >= w || !k) g.began || (g.began = !0, f("begin")), f("run");if (q > n && q < k) b(q);else if (q <= n && 0 !== r && (b(0), x && e()), q >= k && r !== k || !k) b(k), x || e();f("update");a >= k && (g.remaining ? (t = h, "alternate" === g.direction && (g.reversed = !g.reversed)) : (g.pause(), g.completed || (g.completed = !0, f("complete"), "Promise" in window && (p(), m = c()))), l = 0); }a = void 0 === a ? {} : a;var h, t, l = 0, p = null, m = c(), g = fa(a);g.reset = function () { var a = g.direction, c = g.loop;g.currentTime = 0;g.progress = 0;g.paused = !0;g.began = !1;g.completed = !1;g.reversed = "reverse" === a;g.remaining = "alternate" === a && 1 === c ? 2 : c;b(0);for (a = g.children.length; a--;) { g.children[a].reset(); } };g.tick = function (a) { h = a;t || (t = h);k((l + h - t) * q.speed); };g.seek = function (a) { k(d(a)); };g.pause = function () { var a = v.indexOf(g);-1 < a && v.splice(a, 1);g.paused = !0; };g.play = function () { g.paused && (g.paused = !1, t = 0, l = d(g.currentTime), v.push(g), B || ia()); };g.reverse = function () { g.reversed = !g.reversed;t = 0;l = d(g.currentTime); };g.restart = function () { g.pause(); g.reset();g.play(); };g.finished = m;g.reset();g.autoplay && g.play();return g; }var ga = { update: void 0, begin: void 0, run: void 0, complete: void 0, loop: 1, direction: "normal", autoplay: !0, offset: 0 }, S = { duration: 1E3, delay: 0, easing: "easeOutElastic", elasticity: 500, round: 0 }, W = "translateX translateY translateZ rotate rotateX rotateY rotateZ scale scaleX scaleY scaleZ skewX skewY perspective".split(" "), H, h = { arr: function (a) { return Array.isArray(a); }, obj: function (a) { return -1 < Object.prototype.toString.call(a).indexOf("Object"); }, pth: function (a) { return h.obj(a) && a.hasOwnProperty("totalLength"); }, svg: function (a) { return a instanceof SVGElement; }, dom: function (a) { return a.nodeType || h.svg(a); }, str: function (a) { return "string" === typeof a; }, fnc: function (a) { return "function" === typeof a; }, und: function (a) { return "undefined" === typeof a; }, hex: function (a) { return (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a) ); }, rgb: function (a) { return (/^rgb/.test(a) ); }, hsl: function (a) { return (/^hsl/.test(a) ); }, col: function (a) { return h.hex(a) || h.rgb(a) || h.hsl(a); } }, A = function () { function a(a, d, b) { return (((1 - 3 * b + 3 * d) * a + (3 * b - 6 * d)) * a + 3 * d) * a; }return function (c, d, b, f) { if (0 <= c && 1 >= c && 0 <= b && 1 >= b) { var e = new Float32Array(11);if (c !== d || b !== f) for (var k = 0; 11 > k; ++k) { e[k] = a(.1 * k, c, b); }return function (k) { if (c === d && b === f) return k;if (0 === k) return 0;if (1 === k) return 1;for (var h = 0, l = 1; 10 !== l && e[l] <= k; ++l) { h += .1; }--l;var l = h + (k - e[l]) / (e[l + 1] - e[l]) * .1, n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;if (.001 <= n) { for (h = 0; 4 > h; ++h) { n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;if (0 === n) break;var m = a(l, c, b) - k, l = l - m / n; }k = l; } else if (0 === n) k = l;else { var l = h, h = h + .1, g = 0;do { m = l + (h - l) / 2, n = a(m, c, b) - k, 0 < n ? h = m : l = m; } while (1e-7 < Math.abs(n) && 10 > ++g);k = m; }return a(k, d, f); }; } }; }(), Q = function () { function a(a, b) { return 0 === a || 1 === a ? a : -Math.pow(2, 10 * (a - 1)) * Math.sin(2 * (a - 1 - b / (2 * Math.PI) * Math.asin(1)) * Math.PI / b); }var c = "Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "), d = { In: [[.55, .085, .68, .53], [.55, .055, .675, .19], [.895, .03, .685, .22], [.755, .05, .855, .06], [.47, 0, .745, .715], [.95, .05, .795, .035], [.6, .04, .98, .335], [.6, -.28, .735, .045], a], Out: [[.25, .46, .45, .94], [.215, .61, .355, 1], [.165, .84, .44, 1], [.23, 1, .32, 1], [.39, .575, .565, 1], [.19, 1, .22, 1], [.075, .82, .165, 1], [.175, .885, .32, 1.275], function (b, c) { return 1 - a(1 - b, c); }], InOut: [[.455, .03, .515, .955], [.645, .045, .355, 1], [.77, 0, .175, 1], [.86, 0, .07, 1], [.445, .05, .55, .95], [1, 0, 0, 1], [.785, .135, .15, .86], [.68, -.55, .265, 1.55], function (b, c) { return .5 > b ? a(2 * b, c) / 2 : 1 - a(-2 * b + 2, c) / 2; }] }, b = { linear: A(.25, .25, .75, .75) }, f = {}, e;for (e in d) { f.type = e, d[f.type].forEach(function (a) { return function (d, f) { b["ease" + a.type + c[f]] = h.fnc(d) ? d : A.apply($jscomp$this, d); }; }(f)), f = { type: f.type }; }return b; }(), ha = { css: function (a, c, d) { return a.style[c] = d; }, attribute: function (a, c, d) { return a.setAttribute(c, d); }, object: function (a, c, d) { return a[c] = d; }, transform: function (a, c, d, b, f) { b[f] || (b[f] = []);b[f].push(c + "(" + d + ")"); } }, v = [], B = 0, ia = function () { function a() { B = requestAnimationFrame(c); }function c(c) { var b = v.length;if (b) { for (var d = 0; d < b;) { v[d] && v[d].tick(c), d++; }a(); } else cancelAnimationFrame(B), B = 0; }return a; }();q.version = "2.2.0";q.speed = 1;q.running = v;q.remove = function (a) { a = P(a);for (var c = v.length; c--;) { for (var d = v[c], b = d.animations, f = b.length; f--;) { u(a, b[f].animatable.target) && (b.splice(f, 1), b.length || d.pause()); } } };q.getValue = K;q.path = function (a, c) { var d = h.str(a) ? e(a)[0] : a, b = c || 100;return function (a) { return { el: d, property: a, totalLength: N(d) * (b / 100) }; }; };q.setDashoffset = function (a) { var c = N(a);a.setAttribute("stroke-dasharray", c);return c; };q.bezier = A;q.easings = Q;q.timeline = function (a) { var c = q(a);c.pause();c.duration = 0;c.add = function (d) { c.children.forEach(function (a) { a.began = !0;a.completed = !0; });m(d).forEach(function (b) { var d = z(b, D(S, a || {}));d.targets = d.targets || a.targets;b = c.duration;var e = d.offset;d.autoplay = !1;d.direction = c.direction;d.offset = h.und(e) ? b : L(e, b);c.began = !0;c.completed = !0;c.seek(d.offset);d = q(d);d.began = !0;d.completed = !0;d.duration > b && (c.duration = d.duration);c.children.push(d); });c.seek(0);c.reset();c.autoplay && c.restart();return c; };return c; };q.random = function (a, c) { return Math.floor(Math.random() * (c - a + 1)) + a; };return q; }); ;(function ($, anim) { 'use strict'; var _defaults = { accordion: true, onOpenStart: undefined, onOpenEnd: undefined, onCloseStart: undefined, onCloseEnd: undefined, inDuration: 300, outDuration: 300 }; /** * @class * */ var Collapsible = function (_Component) { _inherits(Collapsible, _Component); /** * Construct Collapsible instance * @constructor * @param {Element} el * @param {Object} options */ function Collapsible(el, options) { _classCallCheck(this, Collapsible); var _this3 = _possibleConstructorReturn(this, (Collapsible.__proto__ || Object.getPrototypeOf(Collapsible)).call(this, Collapsible, el, options)); _this3.el.M_Collapsible = _this3; /** * Options for the collapsible * @member Collapsible#options * @prop {Boolean} [accordion=false] - Type of the collapsible * @prop {Function} onOpenStart - Callback function called before collapsible is opened * @prop {Function} onOpenEnd - Callback function called after collapsible is opened * @prop {Function} onCloseStart - Callback function called before collapsible is closed * @prop {Function} onCloseEnd - Callback function called after collapsible is closed * @prop {Number} inDuration - Transition in duration in milliseconds. * @prop {Number} outDuration - Transition duration in milliseconds. */ _this3.options = $.extend({}, Collapsible.defaults, options); // Setup tab indices _this3.$headers = _this3.$el.children('li').children('.collapsible-header'); _this3.$headers.attr('tabindex', 0); _this3._setupEventHandlers(); // Open first active var $activeBodies = _this3.$el.children('li.active').children('.collapsible-body'); if (_this3.options.accordion) { // Handle Accordion $activeBodies.first().css('display', 'block'); } else { // Handle Expandables $activeBodies.css('display', 'block'); } return _this3; } _createClass(Collapsible, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this.el.M_Collapsible = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { var _this4 = this; this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this); this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this); this.el.addEventListener('click', this._handleCollapsibleClickBound); this.$headers.each(function (header) { header.addEventListener('keydown', _this4._handleCollapsibleKeydownBound); }); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { var _this5 = this; this.el.removeEventListener('click', this._handleCollapsibleClickBound); this.$headers.each(function (header) { header.removeEventListener('keydown', _this5._handleCollapsibleKeydownBound); }); } /** * Handle Collapsible Click * @param {Event} e */ }, { key: "_handleCollapsibleClick", value: function _handleCollapsibleClick(e) { var $header = $(e.target).closest('.collapsible-header'); if (e.target && $header.length) { var $collapsible = $header.closest('.collapsible'); if ($collapsible[0] === this.el) { var $collapsibleLi = $header.closest('li'); var $collapsibleLis = $collapsible.children('li'); var isActive = $collapsibleLi[0].classList.contains('active'); var index = $collapsibleLis.index($collapsibleLi); if (isActive) { this.close(index); } else { this.open(index); } } } } /** * Handle Collapsible Keydown * @param {Event} e */ }, { key: "_handleCollapsibleKeydown", value: function _handleCollapsibleKeydown(e) { if (e.keyCode === 13) { this._handleCollapsibleClickBound(e); } } /** * Animate in collapsible slide * @param {Number} index - 0th index of slide */ }, { key: "_animateIn", value: function _animateIn(index) { var _this6 = this; var $collapsibleLi = this.$el.children('li').eq(index); if ($collapsibleLi.length) { var $body = $collapsibleLi.children('.collapsible-body'); anim.remove($body[0]); $body.css({ display: 'block', overflow: 'hidden', height: 0, paddingTop: '', paddingBottom: '' }); var pTop = $body.css('padding-top'); var pBottom = $body.css('padding-bottom'); var finalHeight = $body[0].scrollHeight; $body.css({ paddingTop: 0, paddingBottom: 0 }); anim({ targets: $body[0], height: finalHeight, paddingTop: pTop, paddingBottom: pBottom, duration: this.options.inDuration, easing: 'easeInOutCubic', complete: function (anim) { $body.css({ overflow: '', paddingTop: '', paddingBottom: '', height: '' }); // onOpenEnd callback if (typeof _this6.options.onOpenEnd === 'function') { _this6.options.onOpenEnd.call(_this6, $collapsibleLi[0]); } } }); } } /** * Animate out collapsible slide * @param {Number} index - 0th index of slide to open */ }, { key: "_animateOut", value: function _animateOut(index) { var _this7 = this; var $collapsibleLi = this.$el.children('li').eq(index); if ($collapsibleLi.length) { var $body = $collapsibleLi.children('.collapsible-body'); anim.remove($body[0]); $body.css('overflow', 'hidden'); anim({ targets: $body[0], height: 0, paddingTop: 0, paddingBottom: 0, duration: this.options.outDuration, easing: 'easeInOutCubic', complete: function () { $body.css({ height: '', overflow: '', padding: '', display: '' }); // onCloseEnd callback if (typeof _this7.options.onCloseEnd === 'function') { _this7.options.onCloseEnd.call(_this7, $collapsibleLi[0]); } } }); } } /** * Open Collapsible * @param {Number} index - 0th index of slide */ }, { key: "open", value: function open(index) { var _this8 = this; var $collapsibleLi = this.$el.children('li').eq(index); if ($collapsibleLi.length && !$collapsibleLi[0].classList.contains('active')) { // onOpenStart callback if (typeof this.options.onOpenStart === 'function') { this.options.onOpenStart.call(this, $collapsibleLi[0]); } // Handle accordion behavior if (this.options.accordion) { var $collapsibleLis = this.$el.children('li'); var $activeLis = this.$el.children('li.active'); $activeLis.each(function (el) { var index = $collapsibleLis.index($(el)); _this8.close(index); }); } // Animate in $collapsibleLi[0].classList.add('active'); this._animateIn(index); } } /** * Close Collapsible * @param {Number} index - 0th index of slide */ }, { key: "close", value: function close(index) { var $collapsibleLi = this.$el.children('li').eq(index); if ($collapsibleLi.length && $collapsibleLi[0].classList.contains('active')) { // onCloseStart callback if (typeof this.options.onCloseStart === 'function') { this.options.onCloseStart.call(this, $collapsibleLi[0]); } // Animate out $collapsibleLi[0].classList.remove('active'); this._animateOut(index); } } }], [{ key: "init", value: function init(els, options) { return _get(Collapsible.__proto__ || Object.getPrototypeOf(Collapsible), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Collapsible; } }, { key: "defaults", get: function () { return _defaults; } }]); return Collapsible; }(Component); M.Collapsible = Collapsible; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Collapsible, 'collapsible', 'M_Collapsible'); } })(cash, M.anime); ;(function ($, anim) { 'use strict'; var _defaults = { alignment: 'left', autoFocus: true, constrainWidth: true, container: null, coverTrigger: true, closeOnClick: true, hover: false, inDuration: 150, outDuration: 250, onOpenStart: null, onOpenEnd: null, onCloseStart: null, onCloseEnd: null, onItemClick: null }; /** * @class */ var Dropdown = function (_Component2) { _inherits(Dropdown, _Component2); function Dropdown(el, options) { _classCallCheck(this, Dropdown); var _this9 = _possibleConstructorReturn(this, (Dropdown.__proto__ || Object.getPrototypeOf(Dropdown)).call(this, Dropdown, el, options)); _this9.el.M_Dropdown = _this9; Dropdown._dropdowns.push(_this9); _this9.id = M.getIdFromTrigger(el); _this9.dropdownEl = document.getElementById(_this9.id); _this9.$dropdownEl = $(_this9.dropdownEl); /** * Options for the dropdown * @member Dropdown#options * @prop {String} [alignment='left'] - Edge which the dropdown is aligned to * @prop {Boolean} [autoFocus=true] - Automatically focus dropdown el for keyboard * @prop {Boolean} [constrainWidth=true] - Constrain width to width of the button * @prop {Element} container - Container element to attach dropdown to (optional) * @prop {Boolean} [coverTrigger=true] - Place dropdown over trigger * @prop {Boolean} [closeOnClick=true] - Close on click of dropdown item * @prop {Boolean} [hover=false] - Open dropdown on hover * @prop {Number} [inDuration=150] - Duration of open animation in ms * @prop {Number} [outDuration=250] - Duration of close animation in ms * @prop {Function} onOpenStart - Function called when dropdown starts opening * @prop {Function} onOpenEnd - Function called when dropdown finishes opening * @prop {Function} onCloseStart - Function called when dropdown starts closing * @prop {Function} onCloseEnd - Function called when dropdown finishes closing */ _this9.options = $.extend({}, Dropdown.defaults, options); /** * Describes open/close state of dropdown * @type {Boolean} */ _this9.isOpen = false; /** * Describes if dropdown content is scrollable * @type {Boolean} */ _this9.isScrollable = false; /** * Describes if touch moving on dropdown content * @type {Boolean} */ _this9.isTouchMoving = false; _this9.focusedIndex = -1; _this9.filterQuery = []; // Move dropdown-content after dropdown-trigger if (!!_this9.options.container) { $(_this9.options.container).append(_this9.dropdownEl); } else { _this9.$el.after(_this9.dropdownEl); } _this9._makeDropdownFocusable(); _this9._resetFilterQueryBound = _this9._resetFilterQuery.bind(_this9); _this9._handleDocumentClickBound = _this9._handleDocumentClick.bind(_this9); _this9._handleDocumentTouchmoveBound = _this9._handleDocumentTouchmove.bind(_this9); _this9._handleDropdownClickBound = _this9._handleDropdownClick.bind(_this9); _this9._handleDropdownKeydownBound = _this9._handleDropdownKeydown.bind(_this9); _this9._handleTriggerKeydownBound = _this9._handleTriggerKeydown.bind(_this9); _this9._setupEventHandlers(); return _this9; } _createClass(Dropdown, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._resetDropdownStyles(); this._removeEventHandlers(); Dropdown._dropdowns.splice(Dropdown._dropdowns.indexOf(this), 1); this.el.M_Dropdown = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { // Trigger keydown handler this.el.addEventListener('keydown', this._handleTriggerKeydownBound); // Item click handler this.dropdownEl.addEventListener('click', this._handleDropdownClickBound); // Hover event handlers if (this.options.hover) { this._handleMouseEnterBound = this._handleMouseEnter.bind(this); this.el.addEventListener('mouseenter', this._handleMouseEnterBound); this._handleMouseLeaveBound = this._handleMouseLeave.bind(this); this.el.addEventListener('mouseleave', this._handleMouseLeaveBound); this.dropdownEl.addEventListener('mouseleave', this._handleMouseLeaveBound); // Click event handlers } else { this._handleClickBound = this._handleClick.bind(this); this.el.addEventListener('click', this._handleClickBound); } } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('keydown', this._handleTriggerKeydownBound); this.dropdownEl.removeEventListener('click', this._handleDropdownClickBound); if (this.options.hover) { this.el.removeEventListener('mouseenter', this._handleMouseEnterBound); this.el.removeEventListener('mouseleave', this._handleMouseLeaveBound); this.dropdownEl.removeEventListener('mouseleave', this._handleMouseLeaveBound); } else { this.el.removeEventListener('click', this._handleClickBound); } } }, { key: "_setupTemporaryEventHandlers", value: function _setupTemporaryEventHandlers() { // Use capture phase event handler to prevent click document.body.addEventListener('click', this._handleDocumentClickBound, true); document.body.addEventListener('touchend', this._handleDocumentClickBound); document.body.addEventListener('touchmove', this._handleDocumentTouchmoveBound); this.dropdownEl.addEventListener('keydown', this._handleDropdownKeydownBound); } }, { key: "_removeTemporaryEventHandlers", value: function _removeTemporaryEventHandlers() { // Use capture phase event handler to prevent click document.body.removeEventListener('click', this._handleDocumentClickBound, true); document.body.removeEventListener('touchend', this._handleDocumentClickBound); document.body.removeEventListener('touchmove', this._handleDocumentTouchmoveBound); this.dropdownEl.removeEventListener('keydown', this._handleDropdownKeydownBound); } }, { key: "_handleClick", value: function _handleClick(e) { e.preventDefault(); this.open(); } }, { key: "_handleMouseEnter", value: function _handleMouseEnter() { this.open(); } }, { key: "_handleMouseLeave", value: function _handleMouseLeave(e) { var toEl = e.toElement || e.relatedTarget; var leaveToDropdownContent = !!$(toEl).closest('.dropdown-content').length; var leaveToActiveDropdownTrigger = false; var $closestTrigger = $(toEl).closest('.dropdown-trigger'); if ($closestTrigger.length && !!$closestTrigger[0].M_Dropdown && $closestTrigger[0].M_Dropdown.isOpen) { leaveToActiveDropdownTrigger = true; } // Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) { this.close(); } } }, { key: "_handleDocumentClick", value: function _handleDocumentClick(e) { var _this10 = this; var $target = $(e.target); if (this.options.closeOnClick && $target.closest('.dropdown-content').length && !this.isTouchMoving) { // isTouchMoving to check if scrolling on mobile. setTimeout(function () { _this10.close(); }, 0); } else if ($target.closest('.dropdown-trigger').length || !$target.closest('.dropdown-content').length) { setTimeout(function () { _this10.close(); }, 0); } this.isTouchMoving = false; } }, { key: "_handleTriggerKeydown", value: function _handleTriggerKeydown(e) { // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ENTER) && !this.isOpen) { e.preventDefault(); this.open(); } } /** * Handle Document Touchmove * @param {Event} e */ }, { key: "_handleDocumentTouchmove", value: function _handleDocumentTouchmove(e) { var $target = $(e.target); if ($target.closest('.dropdown-content').length) { this.isTouchMoving = true; } } /** * Handle Dropdown Click * @param {Event} e */ }, { key: "_handleDropdownClick", value: function _handleDropdownClick(e) { // onItemClick callback if (typeof this.options.onItemClick === 'function') { var itemEl = $(e.target).closest('li')[0]; this.options.onItemClick.call(this, itemEl); } } /** * Handle Dropdown Keydown * @param {Event} e */ }, { key: "_handleDropdownKeydown", value: function _handleDropdownKeydown(e) { if (e.which === M.keys.TAB) { e.preventDefault(); this.close(); // Navigate down dropdown list } else if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) && this.isOpen) { e.preventDefault(); var direction = e.which === M.keys.ARROW_DOWN ? 1 : -1; var newFocusedIndex = this.focusedIndex; var foundNewIndex = false; do { newFocusedIndex = newFocusedIndex + direction; if (!!this.dropdownEl.children[newFocusedIndex] && this.dropdownEl.children[newFocusedIndex].tabIndex !== -1) { foundNewIndex = true; break; } } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0); if (foundNewIndex) { this.focusedIndex = newFocusedIndex; this._focusFocusedItem(); } // ENTER selects choice on focused item } else if (e.which === M.keys.ENTER && this.isOpen) { // Search for and ") + ''; } }, { key: "renderRow", value: function renderRow(days, isRTL, isRowSelected) { return '' + (isRTL ? days.reverse() : days).join('') + ''; } }, { key: "renderTable", value: function renderTable(opts, data, randId) { return '
' + this.renderHead(opts) + this.renderBody(data) + '
'; } }, { key: "renderHead", value: function renderHead(opts) { var i = void 0, arr = []; for (i = 0; i < 7; i++) { arr.push("" + this.renderDayName(opts, i, true) + ""); } return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; } }, { key: "renderBody", value: function renderBody(rows) { return '' + rows.join('') + ''; } }, { key: "renderTitle", value: function renderTitle(instance, c, year, month, refYear, randId) { var i = void 0, j = void 0, arr = void 0, opts = this.options, isMinYear = year === opts.minYear, isMaxYear = year === opts.maxYear, html = '
', monthHtml = void 0, yearHtml = void 0, prev = true, next = true; for (arr = [], i = 0; i < 12; i++) { arr.push(''); } monthHtml = ''; if ($.isArray(opts.yearRange)) { i = opts.yearRange[0]; j = opts.yearRange[1] + 1; } else { i = year - opts.yearRange; j = 1 + year + opts.yearRange; } for (arr = []; i < j && i <= opts.maxYear; i++) { if (i >= opts.minYear) { arr.push(""); } } yearHtml = ""; var leftArrow = ''; html += ""; html += '
'; if (opts.showMonthAfterYear) { html += yearHtml + monthHtml; } else { html += monthHtml + yearHtml; } html += '
'; if (isMinYear && (month === 0 || opts.minMonth >= month)) { prev = false; } if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { next = false; } var rightArrow = ''; html += ""; return html += '
'; } /** * refresh the HTML */ }, { key: "draw", value: function draw(force) { if (!this.isOpen && !force) { return; } var opts = this.options, minYear = opts.minYear, maxYear = opts.maxYear, minMonth = opts.minMonth, maxMonth = opts.maxMonth, html = '', randId = void 0; if (this._y <= minYear) { this._y = minYear; if (!isNaN(minMonth) && this._m < minMonth) { this._m = minMonth; } } if (this._y >= maxYear) { this._y = maxYear; if (!isNaN(maxMonth) && this._m > maxMonth) { this._m = maxMonth; } } randId = 'datepicker-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2); for (var c = 0; c < 1; c++) { this._renderDateDisplay(); html += this.renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId); } this.destroySelects(); this.calendarEl.innerHTML = html; // Init Materialize Select var yearSelect = this.calendarEl.querySelector('.orig-select-year'); var monthSelect = this.calendarEl.querySelector('.orig-select-month'); M.FormSelect.init(yearSelect, { classes: 'select-year', dropdownOptions: { container: document.body, constrainWidth: false } }); M.FormSelect.init(monthSelect, { classes: 'select-month', dropdownOptions: { container: document.body, constrainWidth: false } }); // Add change handlers for select yearSelect.addEventListener('change', this._handleYearChange.bind(this)); monthSelect.addEventListener('change', this._handleMonthChange.bind(this)); if (typeof this.options.onDraw === 'function') { this.options.onDraw(this); } } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { this._handleInputKeydownBound = this._handleInputKeydown.bind(this); this._handleInputClickBound = this._handleInputClick.bind(this); this._handleInputChangeBound = this._handleInputChange.bind(this); this._handleCalendarClickBound = this._handleCalendarClick.bind(this); this._finishSelectionBound = this._finishSelection.bind(this); this._handleMonthChange = this._handleMonthChange.bind(this); this._closeBound = this.close.bind(this); this.el.addEventListener('click', this._handleInputClickBound); this.el.addEventListener('keydown', this._handleInputKeydownBound); this.el.addEventListener('change', this._handleInputChangeBound); this.calendarEl.addEventListener('click', this._handleCalendarClickBound); this.doneBtn.addEventListener('click', this._finishSelectionBound); this.cancelBtn.addEventListener('click', this._closeBound); if (this.options.showClearBtn) { this._handleClearClickBound = this._handleClearClick.bind(this); this.clearBtn.addEventListener('click', this._handleClearClickBound); } } }, { key: "_setupVariables", value: function _setupVariables() { var _this56 = this; this.$modalEl = $(Datepicker._template); this.modalEl = this.$modalEl[0]; this.calendarEl = this.modalEl.querySelector('.datepicker-calendar'); this.yearTextEl = this.modalEl.querySelector('.year-text'); this.dateTextEl = this.modalEl.querySelector('.date-text'); if (this.options.showClearBtn) { this.clearBtn = this.modalEl.querySelector('.datepicker-clear'); } this.doneBtn = this.modalEl.querySelector('.datepicker-done'); this.cancelBtn = this.modalEl.querySelector('.datepicker-cancel'); this.formats = { d: function () { return _this56.date.getDate(); }, dd: function () { var d = _this56.date.getDate(); return (d < 10 ? '0' : '') + d; }, ddd: function () { return _this56.options.i18n.weekdaysShort[_this56.date.getDay()]; }, dddd: function () { return _this56.options.i18n.weekdays[_this56.date.getDay()]; }, m: function () { return _this56.date.getMonth() + 1; }, mm: function () { var m = _this56.date.getMonth() + 1; return (m < 10 ? '0' : '') + m; }, mmm: function () { return _this56.options.i18n.monthsShort[_this56.date.getMonth()]; }, mmmm: function () { return _this56.options.i18n.months[_this56.date.getMonth()]; }, yy: function () { return ('' + _this56.date.getFullYear()).slice(2); }, yyyy: function () { return _this56.date.getFullYear(); } }; } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('click', this._handleInputClickBound); this.el.removeEventListener('keydown', this._handleInputKeydownBound); this.el.removeEventListener('change', this._handleInputChangeBound); this.calendarEl.removeEventListener('click', this._handleCalendarClickBound); } }, { key: "_handleInputClick", value: function _handleInputClick() { this.open(); } }, { key: "_handleInputKeydown", value: function _handleInputKeydown(e) { if (e.which === M.keys.ENTER) { e.preventDefault(); this.open(); } } }, { key: "_handleCalendarClick", value: function _handleCalendarClick(e) { if (!this.isOpen) { return; } var $target = $(e.target); if (!$target.hasClass('is-disabled')) { if ($target.hasClass('datepicker-day-button') && !$target.hasClass('is-empty') && !$target.parent().hasClass('is-disabled')) { this.setDate(new Date(e.target.getAttribute('data-year'), e.target.getAttribute('data-month'), e.target.getAttribute('data-day'))); if (this.options.autoClose) { this._finishSelection(); } } else if ($target.closest('.month-prev').length) { this.prevMonth(); } else if ($target.closest('.month-next').length) { this.nextMonth(); } } } }, { key: "_handleClearClick", value: function _handleClearClick() { this.date = null; this.setInputValue(); this.close(); } }, { key: "_handleMonthChange", value: function _handleMonthChange(e) { this.gotoMonth(e.target.value); } }, { key: "_handleYearChange", value: function _handleYearChange(e) { this.gotoYear(e.target.value); } /** * change view to a specific month (zero-index, e.g. 0: January) */ }, { key: "gotoMonth", value: function gotoMonth(month) { if (!isNaN(month)) { this.calendars[0].month = parseInt(month, 10); this.adjustCalendars(); } } /** * change view to a specific full year (e.g. "2012") */ }, { key: "gotoYear", value: function gotoYear(year) { if (!isNaN(year)) { this.calendars[0].year = parseInt(year, 10); this.adjustCalendars(); } } }, { key: "_handleInputChange", value: function _handleInputChange(e) { var date = void 0; // Prevent change event from being fired when triggered by the plugin if (e.firedBy === this) { return; } if (this.options.parse) { date = this.options.parse(this.el.value, this.options.format); } else { date = new Date(Date.parse(this.el.value)); } if (Datepicker._isDate(date)) { this.setDate(date); } } }, { key: "renderDayName", value: function renderDayName(opts, day, abbr) { day += opts.firstDay; while (day >= 7) { day -= 7; } return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day]; } /** * Set input value to the selected date and close Datepicker */ }, { key: "_finishSelection", value: function _finishSelection() { this.setInputValue(); this.close(); } /** * Open Datepicker */ }, { key: "open", value: function open() { if (this.isOpen) { return; } this.isOpen = true; if (typeof this.options.onOpen === 'function') { this.options.onOpen.call(this); } this.draw(); this.modal.open(); return this; } /** * Close Datepicker */ }, { key: "close", value: function close() { if (!this.isOpen) { return; } this.isOpen = false; if (typeof this.options.onClose === 'function') { this.options.onClose.call(this); } this.modal.close(); return this; } }], [{ key: "init", value: function init(els, options) { return _get(Datepicker.__proto__ || Object.getPrototypeOf(Datepicker), "init", this).call(this, this, els, options); } }, { key: "_isDate", value: function _isDate(obj) { return (/Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()) ); } }, { key: "_isWeekend", value: function _isWeekend(date) { var day = date.getDay(); return day === 0 || day === 6; } }, { key: "_setToStartOfDay", value: function _setToStartOfDay(date) { if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); } }, { key: "_getDaysInMonth", value: function _getDaysInMonth(year, month) { return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; } }, { key: "_isLeapYear", value: function _isLeapYear(year) { // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; } }, { key: "_compareDates", value: function _compareDates(a, b) { // weak date comparison (use setToStartOfDay(date) to ensure correct result) return a.getTime() === b.getTime(); } }, { key: "_setToStartOfDay", value: function _setToStartOfDay(date) { if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Datepicker; } }, { key: "defaults", get: function () { return _defaults; } }]); return Datepicker; }(Component); Datepicker._template = [''].join(''); M.Datepicker = Datepicker; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Datepicker, 'datepicker', 'M_Datepicker'); } })(cash); ;(function ($) { 'use strict'; var _defaults = { dialRadius: 135, outerRadius: 105, innerRadius: 70, tickRadius: 20, duration: 350, container: null, defaultTime: 'now', // default time, 'now' or '13:14' e.g. fromNow: 0, // Millisecond offset from the defaultTime showClearBtn: false, // internationalization i18n: { cancel: 'Cancel', clear: 'Clear', done: 'Ok' }, autoClose: false, // auto close when minute is selected twelveHour: true, // change to 12 hour AM/PM clock from 24 hour vibrate: true, // vibrate the device when dragging clock hand // Callbacks onOpenStart: null, onOpenEnd: null, onCloseStart: null, onCloseEnd: null, onSelect: null }; /** * @class * */ var Timepicker = function (_Component16) { _inherits(Timepicker, _Component16); function Timepicker(el, options) { _classCallCheck(this, Timepicker); var _this57 = _possibleConstructorReturn(this, (Timepicker.__proto__ || Object.getPrototypeOf(Timepicker)).call(this, Timepicker, el, options)); _this57.el.M_Timepicker = _this57; _this57.options = $.extend({}, Timepicker.defaults, options); _this57.id = M.guid(); _this57._insertHTMLIntoDOM(); _this57._setupModal(); _this57._setupVariables(); _this57._setupEventHandlers(); _this57._clockSetup(); _this57._pickerSetup(); return _this57; } _createClass(Timepicker, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this.modal.destroy(); $(this.modalEl).remove(); this.el.M_Timepicker = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { this._handleInputKeydownBound = this._handleInputKeydown.bind(this); this._handleInputClickBound = this._handleInputClick.bind(this); this._handleClockClickStartBound = this._handleClockClickStart.bind(this); this._handleDocumentClickMoveBound = this._handleDocumentClickMove.bind(this); this._handleDocumentClickEndBound = this._handleDocumentClickEnd.bind(this); this.el.addEventListener('click', this._handleInputClickBound); this.el.addEventListener('keydown', this._handleInputKeydownBound); this.plate.addEventListener('mousedown', this._handleClockClickStartBound); this.plate.addEventListener('touchstart', this._handleClockClickStartBound); $(this.spanHours).on('click', this.showView.bind(this, 'hours')); $(this.spanMinutes).on('click', this.showView.bind(this, 'minutes')); } }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('click', this._handleInputClickBound); this.el.removeEventListener('keydown', this._handleInputKeydownBound); } }, { key: "_handleInputClick", value: function _handleInputClick() { this.open(); } }, { key: "_handleInputKeydown", value: function _handleInputKeydown(e) { if (e.which === M.keys.ENTER) { e.preventDefault(); this.open(); } } }, { key: "_handleClockClickStart", value: function _handleClockClickStart(e) { e.preventDefault(); var clockPlateBR = this.plate.getBoundingClientRect(); var offset = { x: clockPlateBR.left, y: clockPlateBR.top }; this.x0 = offset.x + this.options.dialRadius; this.y0 = offset.y + this.options.dialRadius; this.moved = false; var clickPos = Timepicker._Pos(e); this.dx = clickPos.x - this.x0; this.dy = clickPos.y - this.y0; // Set clock hands this.setHand(this.dx, this.dy, false); // Mousemove on document document.addEventListener('mousemove', this._handleDocumentClickMoveBound); document.addEventListener('touchmove', this._handleDocumentClickMoveBound); // Mouseup on document document.addEventListener('mouseup', this._handleDocumentClickEndBound); document.addEventListener('touchend', this._handleDocumentClickEndBound); } }, { key: "_handleDocumentClickMove", value: function _handleDocumentClickMove(e) { e.preventDefault(); var clickPos = Timepicker._Pos(e); var x = clickPos.x - this.x0; var y = clickPos.y - this.y0; this.moved = true; this.setHand(x, y, false, true); } }, { key: "_handleDocumentClickEnd", value: function _handleDocumentClickEnd(e) { var _this58 = this; e.preventDefault(); document.removeEventListener('mouseup', this._handleDocumentClickEndBound); document.removeEventListener('touchend', this._handleDocumentClickEndBound); var clickPos = Timepicker._Pos(e); var x = clickPos.x - this.x0; var y = clickPos.y - this.y0; if (this.moved && x === this.dx && y === this.dy) { this.setHand(x, y); } if (this.currentView === 'hours') { this.showView('minutes', this.options.duration / 2); } else if (this.options.autoClose) { $(this.minutesView).addClass('timepicker-dial-out'); setTimeout(function () { _this58.done(); }, this.options.duration / 2); } if (typeof this.options.onSelect === 'function') { this.options.onSelect.call(this, this.hours, this.minutes); } // Unbind mousemove event document.removeEventListener('mousemove', this._handleDocumentClickMoveBound); document.removeEventListener('touchmove', this._handleDocumentClickMoveBound); } }, { key: "_insertHTMLIntoDOM", value: function _insertHTMLIntoDOM() { this.$modalEl = $(Timepicker._template); this.modalEl = this.$modalEl[0]; this.modalEl.id = 'modal-' + this.id; // Append popover to input by default var containerEl = document.querySelector(this.options.container); if (this.options.container && !!containerEl) { this.$modalEl.appendTo(containerEl); } else { this.$modalEl.insertBefore(this.el); } } }, { key: "_setupModal", value: function _setupModal() { var _this59 = this; this.modal = M.Modal.init(this.modalEl, { onOpenStart: this.options.onOpenStart, onOpenEnd: this.options.onOpenEnd, onCloseStart: this.options.onCloseStart, onCloseEnd: function () { if (typeof _this59.options.onCloseEnd === 'function') { _this59.options.onCloseEnd.call(_this59); } _this59.isOpen = false; } }); } }, { key: "_setupVariables", value: function _setupVariables() { this.currentView = 'hours'; this.vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; this._canvas = this.modalEl.querySelector('.timepicker-canvas'); this.plate = this.modalEl.querySelector('.timepicker-plate'); this.hoursView = this.modalEl.querySelector('.timepicker-hours'); this.minutesView = this.modalEl.querySelector('.timepicker-minutes'); this.spanHours = this.modalEl.querySelector('.timepicker-span-hours'); this.spanMinutes = this.modalEl.querySelector('.timepicker-span-minutes'); this.spanAmPm = this.modalEl.querySelector('.timepicker-span-am-pm'); this.footer = this.modalEl.querySelector('.timepicker-footer'); this.amOrPm = 'PM'; } }, { key: "_pickerSetup", value: function _pickerSetup() { var $clearBtn = $("").appendTo(this.footer).on('click', this.clear.bind(this)); if (this.options.showClearBtn) { $clearBtn.css({ visibility: '' }); } var confirmationBtnsContainer = $('
'); $('').appendTo(confirmationBtnsContainer).on('click', this.close.bind(this)); $('').appendTo(confirmationBtnsContainer).on('click', this.done.bind(this)); confirmationBtnsContainer.appendTo(this.footer); } }, { key: "_clockSetup", value: function _clockSetup() { if (this.options.twelveHour) { this.$amBtn = $('
AM
'); this.$pmBtn = $('
PM
'); this.$amBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); this.$pmBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); } this._buildHoursView(); this._buildMinutesView(); this._buildSVGClock(); } }, { key: "_buildSVGClock", value: function _buildSVGClock() { // Draw clock hands and others var dialRadius = this.options.dialRadius; var tickRadius = this.options.tickRadius; var diameter = dialRadius * 2; var svg = Timepicker._createSVGEl('svg'); svg.setAttribute('class', 'timepicker-svg'); svg.setAttribute('width', diameter); svg.setAttribute('height', diameter); var g = Timepicker._createSVGEl('g'); g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); var bearing = Timepicker._createSVGEl('circle'); bearing.setAttribute('class', 'timepicker-canvas-bearing'); bearing.setAttribute('cx', 0); bearing.setAttribute('cy', 0); bearing.setAttribute('r', 4); var hand = Timepicker._createSVGEl('line'); hand.setAttribute('x1', 0); hand.setAttribute('y1', 0); var bg = Timepicker._createSVGEl('circle'); bg.setAttribute('class', 'timepicker-canvas-bg'); bg.setAttribute('r', tickRadius); g.appendChild(hand); g.appendChild(bg); g.appendChild(bearing); svg.appendChild(g); this._canvas.appendChild(svg); this.hand = hand; this.bg = bg; this.bearing = bearing; this.g = g; } }, { key: "_buildHoursView", value: function _buildHoursView() { var $tick = $('
'); // Hours view if (this.options.twelveHour) { for (var i = 1; i < 13; i += 1) { var tick = $tick.clone(); var radian = i / 6 * Math.PI; var radius = this.options.outerRadius; tick.css({ left: this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px', top: this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px' }); tick.html(i === 0 ? '00' : i); this.hoursView.appendChild(tick[0]); // tick.on(mousedownEvent, mousedown); } } else { for (var _i2 = 0; _i2 < 24; _i2 += 1) { var _tick = $tick.clone(); var _radian = _i2 / 6 * Math.PI; var inner = _i2 > 0 && _i2 < 13; var _radius = inner ? this.options.innerRadius : this.options.outerRadius; _tick.css({ left: this.options.dialRadius + Math.sin(_radian) * _radius - this.options.tickRadius + 'px', top: this.options.dialRadius - Math.cos(_radian) * _radius - this.options.tickRadius + 'px' }); _tick.html(_i2 === 0 ? '00' : _i2); this.hoursView.appendChild(_tick[0]); // tick.on(mousedownEvent, mousedown); } } } }, { key: "_buildMinutesView", value: function _buildMinutesView() { var $tick = $('
'); // Minutes view for (var i = 0; i < 60; i += 5) { var tick = $tick.clone(); var radian = i / 30 * Math.PI; tick.css({ left: this.options.dialRadius + Math.sin(radian) * this.options.outerRadius - this.options.tickRadius + 'px', top: this.options.dialRadius - Math.cos(radian) * this.options.outerRadius - this.options.tickRadius + 'px' }); tick.html(Timepicker._addLeadingZero(i)); this.minutesView.appendChild(tick[0]); } } }, { key: "_handleAmPmClick", value: function _handleAmPmClick(e) { var $btnClicked = $(e.target); this.amOrPm = $btnClicked.hasClass('am-btn') ? 'AM' : 'PM'; this._updateAmPmView(); } }, { key: "_updateAmPmView", value: function _updateAmPmView() { if (this.options.twelveHour) { this.$amBtn.toggleClass('text-primary', this.amOrPm === 'AM'); this.$pmBtn.toggleClass('text-primary', this.amOrPm === 'PM'); } } }, { key: "_updateTimeFromInput", value: function _updateTimeFromInput() { // Get the time var value = ((this.el.value || this.options.defaultTime || '') + '').split(':'); if (this.options.twelveHour && !(typeof value[1] === 'undefined')) { if (value[1].toUpperCase().indexOf('AM') > 0) { this.amOrPm = 'AM'; } else { this.amOrPm = 'PM'; } value[1] = value[1].replace('AM', '').replace('PM', ''); } if (value[0] === 'now') { var now = new Date(+new Date() + this.options.fromNow); value = [now.getHours(), now.getMinutes()]; if (this.options.twelveHour) { this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM'; } } this.hours = +value[0] || 0; this.minutes = +value[1] || 0; this.spanHours.innerHTML = this.hours; this.spanMinutes.innerHTML = Timepicker._addLeadingZero(this.minutes); this._updateAmPmView(); } }, { key: "showView", value: function showView(view, delay) { if (view === 'minutes' && $(this.hoursView).css('visibility') === 'visible') { // raiseCallback(this.options.beforeHourSelect); } var isHours = view === 'hours', nextView = isHours ? this.hoursView : this.minutesView, hideView = isHours ? this.minutesView : this.hoursView; this.currentView = view; $(this.spanHours).toggleClass('text-primary', isHours); $(this.spanMinutes).toggleClass('text-primary', !isHours); // Transition view hideView.classList.add('timepicker-dial-out'); $(nextView).css('visibility', 'visible').removeClass('timepicker-dial-out'); // Reset clock hand this.resetClock(delay); // After transitions ended clearTimeout(this.toggleViewTimer); this.toggleViewTimer = setTimeout(function () { $(hideView).css('visibility', 'hidden'); }, this.options.duration); } }, { key: "resetClock", value: function resetClock(delay) { var view = this.currentView, value = this[view], isHours = view === 'hours', unit = Math.PI / (isHours ? 6 : 30), radian = value * unit, radius = isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius, x = Math.sin(radian) * radius, y = -Math.cos(radian) * radius, self = this; if (delay) { $(this.canvas).addClass('timepicker-canvas-out'); setTimeout(function () { $(self.canvas).removeClass('timepicker-canvas-out'); self.setHand(x, y); }, delay); } else { this.setHand(x, y); } } }, { key: "setHand", value: function setHand(x, y, roundBy5) { var _this60 = this; var radian = Math.atan2(x, -y), isHours = this.currentView === 'hours', unit = Math.PI / (isHours || roundBy5 ? 6 : 30), z = Math.sqrt(x * x + y * y), inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2, radius = inner ? this.options.innerRadius : this.options.outerRadius; if (this.options.twelveHour) { radius = this.options.outerRadius; } // Radian should in range [0, 2PI] if (radian < 0) { radian = Math.PI * 2 + radian; } // Get the round value var value = Math.round(radian / unit); // Get the round radian radian = value * unit; // Correct the hours or minutes if (this.options.twelveHour) { if (isHours) { if (value === 0) value = 12; } else { if (roundBy5) value *= 5; if (value === 60) value = 0; } } else { if (isHours) { if (value === 12) { value = 0; } value = inner ? value === 0 ? 12 : value : value === 0 ? 0 : value + 12; } else { if (roundBy5) { value *= 5; } if (value === 60) { value = 0; } } } // Once hours or minutes changed, vibrate the device if (this[this.currentView] !== value) { if (this.vibrate && this.options.vibrate) { // Do not vibrate too frequently if (!this.vibrateTimer) { navigator[this.vibrate](10); this.vibrateTimer = setTimeout(function () { _this60.vibrateTimer = null; }, 100); } } } this[this.currentView] = value; if (isHours) { this['spanHours'].innerHTML = value; } else { this['spanMinutes'].innerHTML = Timepicker._addLeadingZero(value); } // Set clock hand and others' position var cx1 = Math.sin(radian) * (radius - this.options.tickRadius), cy1 = -Math.cos(radian) * (radius - this.options.tickRadius), cx2 = Math.sin(radian) * radius, cy2 = -Math.cos(radian) * radius; this.hand.setAttribute('x2', cx1); this.hand.setAttribute('y2', cy1); this.bg.setAttribute('cx', cx2); this.bg.setAttribute('cy', cy2); } }, { key: "open", value: function open() { if (this.isOpen) { return; } this.isOpen = true; this._updateTimeFromInput(); this.showView('hours'); this.modal.open(); } }, { key: "close", value: function close() { if (!this.isOpen) { return; } this.isOpen = false; this.modal.close(); } /** * Finish timepicker selection. */ }, { key: "done", value: function done(e, clearValue) { // Set input value var last = this.el.value; var value = clearValue ? '' : Timepicker._addLeadingZero(this.hours) + ':' + Timepicker._addLeadingZero(this.minutes); this.time = value; if (!clearValue && this.options.twelveHour) { value = value + " " + this.amOrPm; } this.el.value = value; // Trigger change event if (value !== last) { this.$el.trigger('change'); } this.close(); this.el.focus(); } }, { key: "clear", value: function clear() { this.done(null, true); } }], [{ key: "init", value: function init(els, options) { return _get(Timepicker.__proto__ || Object.getPrototypeOf(Timepicker), "init", this).call(this, this, els, options); } }, { key: "_addLeadingZero", value: function _addLeadingZero(num) { return (num < 10 ? '0' : '') + num; } }, { key: "_createSVGEl", value: function _createSVGEl(name) { var svgNS = 'http://www.w3.org/2000/svg'; return document.createElementNS(svgNS, name); } /** * @typedef {Object} Point * @property {number} x The X Coordinate * @property {number} y The Y Coordinate */ /** * Get x position of mouse or touch event * @param {Event} e * @return {Point} x and y location */ }, { key: "_Pos", value: function _Pos(e) { if (e.targetTouches && e.targetTouches.length >= 1) { return { x: e.targetTouches[0].clientX, y: e.targetTouches[0].clientY }; } // mouse event return { x: e.clientX, y: e.clientY }; } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Timepicker; } }, { key: "defaults", get: function () { return _defaults; } }]); return Timepicker; }(Component); Timepicker._template = [''].join(''); M.Timepicker = Timepicker; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Timepicker, 'timepicker', 'M_Timepicker'); } })(cash); ;(function ($) { 'use strict'; var _defaults = {}; /** * @class * */ var CharacterCounter = function (_Component17) { _inherits(CharacterCounter, _Component17); /** * Construct CharacterCounter instance * @constructor * @param {Element} el * @param {Object} options */ function CharacterCounter(el, options) { _classCallCheck(this, CharacterCounter); var _this61 = _possibleConstructorReturn(this, (CharacterCounter.__proto__ || Object.getPrototypeOf(CharacterCounter)).call(this, CharacterCounter, el, options)); _this61.el.M_CharacterCounter = _this61; /** * Options for the character counter */ _this61.options = $.extend({}, CharacterCounter.defaults, options); _this61.isInvalid = false; _this61.isValidLength = false; _this61._setupCounter(); _this61._setupEventHandlers(); return _this61; } _createClass(CharacterCounter, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this.el.CharacterCounter = undefined; this._removeCounter(); } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { this._handleUpdateCounterBound = this.updateCounter.bind(this); this.el.addEventListener('focus', this._handleUpdateCounterBound, true); this.el.addEventListener('input', this._handleUpdateCounterBound, true); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('focus', this._handleUpdateCounterBound, true); this.el.removeEventListener('input', this._handleUpdateCounterBound, true); } /** * Setup counter element */ }, { key: "_setupCounter", value: function _setupCounter() { this.counterEl = document.createElement('span'); $(this.counterEl).addClass('character-counter').css({ float: 'right', 'font-size': '12px', height: 1 }); this.$el.parent().append(this.counterEl); } /** * Remove counter element */ }, { key: "_removeCounter", value: function _removeCounter() { $(this.counterEl).remove(); } /** * Update counter */ }, { key: "updateCounter", value: function updateCounter() { var maxLength = +this.$el.attr('data-length'), actualLength = this.el.value.length; this.isValidLength = actualLength <= maxLength; var counterString = actualLength; if (maxLength) { counterString += '/' + maxLength; this._validateInput(); } $(this.counterEl).html(counterString); } /** * Add validation classes */ }, { key: "_validateInput", value: function _validateInput() { if (this.isValidLength && this.isInvalid) { this.isInvalid = false; this.$el.removeClass('invalid'); } else if (!this.isValidLength && !this.isInvalid) { this.isInvalid = true; this.$el.removeClass('valid'); this.$el.addClass('invalid'); } } }], [{ key: "init", value: function init(els, options) { return _get(CharacterCounter.__proto__ || Object.getPrototypeOf(CharacterCounter), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_CharacterCounter; } }, { key: "defaults", get: function () { return _defaults; } }]); return CharacterCounter; }(Component); M.CharacterCounter = CharacterCounter; if (M.jQueryLoaded) { M.initializeJqueryWrapper(CharacterCounter, 'characterCounter', 'M_CharacterCounter'); } })(cash); ;(function ($) { 'use strict'; var _defaults = { duration: 200, // ms dist: -100, // zoom scale TODO: make this more intuitive as an option shift: 0, // spacing for center image padding: 0, // Padding between non center items numVisible: 5, // Number of visible items in carousel fullWidth: false, // Change to full width styles indicators: false, // Toggle indicators noWrap: false, // Don't wrap around and cycle through items. onCycleTo: null // Callback for when a new slide is cycled to. }; /** * @class * */ var Carousel = function (_Component18) { _inherits(Carousel, _Component18); /** * Construct Carousel instance * @constructor * @param {Element} el * @param {Object} options */ function Carousel(el, options) { _classCallCheck(this, Carousel); var _this62 = _possibleConstructorReturn(this, (Carousel.__proto__ || Object.getPrototypeOf(Carousel)).call(this, Carousel, el, options)); _this62.el.M_Carousel = _this62; /** * Options for the carousel * @member Carousel#options * @prop {Number} duration * @prop {Number} dist * @prop {Number} shift * @prop {Number} padding * @prop {Number} numVisible * @prop {Boolean} fullWidth * @prop {Boolean} indicators * @prop {Boolean} noWrap * @prop {Function} onCycleTo */ _this62.options = $.extend({}, Carousel.defaults, options); // Setup _this62.hasMultipleSlides = _this62.$el.find('.carousel-item').length > 1; _this62.showIndicators = _this62.options.indicators && _this62.hasMultipleSlides; _this62.noWrap = _this62.options.noWrap || !_this62.hasMultipleSlides; _this62.pressed = false; _this62.dragged = false; _this62.offset = _this62.target = 0; _this62.images = []; _this62.itemWidth = _this62.$el.find('.carousel-item').first().innerWidth(); _this62.itemHeight = _this62.$el.find('.carousel-item').first().innerHeight(); _this62.dim = _this62.itemWidth * 2 + _this62.options.padding || 1; // Make sure dim is non zero for divisions. _this62._autoScrollBound = _this62._autoScroll.bind(_this62); _this62._trackBound = _this62._track.bind(_this62); // Full Width carousel setup if (_this62.options.fullWidth) { _this62.options.dist = 0; _this62._setCarouselHeight(); // Offset fixed items when indicators. if (_this62.showIndicators) { _this62.$el.find('.carousel-fixed-item').addClass('with-indicators'); } } // Iterate through slides _this62.$indicators = $(''); _this62.$el.find('.carousel-item').each(function (el, i) { _this62.images.push(el); if (_this62.showIndicators) { var $indicator = $('
  • '); // Add active to first by default. if (i === 0) { $indicator[0].classList.add('active'); } _this62.$indicators.append($indicator); } }); if (_this62.showIndicators) { _this62.$el.append(_this62.$indicators); } _this62.count = _this62.images.length; // Cap numVisible at count _this62.options.numVisible = Math.min(_this62.count, _this62.options.numVisible); // Setup cross browser string _this62.xform = 'transform'; ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { var e = prefix + 'Transform'; if (typeof document.body.style[e] !== 'undefined') { _this62.xform = e; return false; } return true; }); _this62._setupEventHandlers(); _this62._scroll(_this62.offset); return _this62; } _createClass(Carousel, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this.el.M_Carousel = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { var _this63 = this; this._handleCarouselTapBound = this._handleCarouselTap.bind(this); this._handleCarouselDragBound = this._handleCarouselDrag.bind(this); this._handleCarouselReleaseBound = this._handleCarouselRelease.bind(this); this._handleCarouselClickBound = this._handleCarouselClick.bind(this); if (typeof window.ontouchstart !== 'undefined') { this.el.addEventListener('touchstart', this._handleCarouselTapBound); this.el.addEventListener('touchmove', this._handleCarouselDragBound); this.el.addEventListener('touchend', this._handleCarouselReleaseBound); } this.el.addEventListener('mousedown', this._handleCarouselTapBound); this.el.addEventListener('mousemove', this._handleCarouselDragBound); this.el.addEventListener('mouseup', this._handleCarouselReleaseBound); this.el.addEventListener('mouseleave', this._handleCarouselReleaseBound); this.el.addEventListener('click', this._handleCarouselClickBound); if (this.showIndicators && this.$indicators) { this._handleIndicatorClickBound = this._handleIndicatorClick.bind(this); this.$indicators.find('.indicator-item').each(function (el, i) { el.addEventListener('click', _this63._handleIndicatorClickBound); }); } // Resize var throttledResize = M.throttle(this._handleResize, 200); this._handleThrottledResizeBound = throttledResize.bind(this); window.addEventListener('resize', this._handleThrottledResizeBound); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { var _this64 = this; if (typeof window.ontouchstart !== 'undefined') { this.el.removeEventListener('touchstart', this._handleCarouselTapBound); this.el.removeEventListener('touchmove', this._handleCarouselDragBound); this.el.removeEventListener('touchend', this._handleCarouselReleaseBound); } this.el.removeEventListener('mousedown', this._handleCarouselTapBound); this.el.removeEventListener('mousemove', this._handleCarouselDragBound); this.el.removeEventListener('mouseup', this._handleCarouselReleaseBound); this.el.removeEventListener('mouseleave', this._handleCarouselReleaseBound); this.el.removeEventListener('click', this._handleCarouselClickBound); if (this.showIndicators && this.$indicators) { this.$indicators.find('.indicator-item').each(function (el, i) { el.removeEventListener('click', _this64._handleIndicatorClickBound); }); } window.removeEventListener('resize', this._handleThrottledResizeBound); } /** * Handle Carousel Tap * @param {Event} e */ }, { key: "_handleCarouselTap", value: function _handleCarouselTap(e) { // Fixes firefox draggable image bug if (e.type === 'mousedown' && $(e.target).is('img')) { e.preventDefault(); } this.pressed = true; this.dragged = false; this.verticalDragged = false; this.reference = this._xpos(e); this.referenceY = this._ypos(e); this.velocity = this.amplitude = 0; this.frame = this.offset; this.timestamp = Date.now(); clearInterval(this.ticker); this.ticker = setInterval(this._trackBound, 100); } /** * Handle Carousel Drag * @param {Event} e */ }, { key: "_handleCarouselDrag", value: function _handleCarouselDrag(e) { var x = void 0, y = void 0, delta = void 0, deltaY = void 0; if (this.pressed) { x = this._xpos(e); y = this._ypos(e); delta = this.reference - x; deltaY = Math.abs(this.referenceY - y); if (deltaY < 30 && !this.verticalDragged) { // If vertical scrolling don't allow dragging. if (delta > 2 || delta < -2) { this.dragged = true; this.reference = x; this._scroll(this.offset + delta); } } else if (this.dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } else { // Vertical scrolling. this.verticalDragged = true; } } if (this.dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } } /** * Handle Carousel Release * @param {Event} e */ }, { key: "_handleCarouselRelease", value: function _handleCarouselRelease(e) { if (this.pressed) { this.pressed = false; } else { return; } clearInterval(this.ticker); this.target = this.offset; if (this.velocity > 10 || this.velocity < -10) { this.amplitude = 0.9 * this.velocity; this.target = this.offset + this.amplitude; } this.target = Math.round(this.target / this.dim) * this.dim; // No wrap of items. if (this.noWrap) { if (this.target >= this.dim * (this.count - 1)) { this.target = this.dim * (this.count - 1); } else if (this.target < 0) { this.target = 0; } } this.amplitude = this.target - this.offset; this.timestamp = Date.now(); requestAnimationFrame(this._autoScrollBound); if (this.dragged) { e.preventDefault(); e.stopPropagation(); } return false; } /** * Handle Carousel CLick * @param {Event} e */ }, { key: "_handleCarouselClick", value: function _handleCarouselClick(e) { // Disable clicks if carousel was dragged. if (this.dragged) { e.preventDefault(); e.stopPropagation(); return false; } else if (!this.options.fullWidth) { var clickedIndex = $(e.target).closest('.carousel-item').index(); var diff = this._wrap(this.center) - clickedIndex; // Disable clicks if carousel was shifted by click if (diff !== 0) { e.preventDefault(); e.stopPropagation(); } this._cycleTo(clickedIndex); } } /** * Handle Indicator CLick * @param {Event} e */ }, { key: "_handleIndicatorClick", value: function _handleIndicatorClick(e) { e.stopPropagation(); var indicator = $(e.target).closest('.indicator-item'); if (indicator.length) { this._cycleTo(indicator.index()); } } /** * Handle Throttle Resize * @param {Event} e */ }, { key: "_handleResize", value: function _handleResize(e) { if (this.options.fullWidth) { this.itemWidth = this.$el.find('.carousel-item').first().innerWidth(); this.imageHeight = this.$el.find('.carousel-item.active').height(); this.dim = this.itemWidth * 2 + this.options.padding; this.offset = this.center * 2 * this.itemWidth; this.target = this.offset; this._setCarouselHeight(true); } else { this._scroll(); } } /** * Set carousel height based on first slide * @param {Booleam} imageOnly - true for image slides */ }, { key: "_setCarouselHeight", value: function _setCarouselHeight(imageOnly) { var _this65 = this; var firstSlide = this.$el.find('.carousel-item.active').length ? this.$el.find('.carousel-item.active').first() : this.$el.find('.carousel-item').first(); var firstImage = firstSlide.find('img').first(); if (firstImage.length) { if (firstImage[0].complete) { // If image won't trigger the load event var imageHeight = firstImage.height(); if (imageHeight > 0) { this.$el.css('height', imageHeight + 'px'); } else { // If image still has no height, use the natural dimensions to calculate var naturalWidth = firstImage[0].naturalWidth; var naturalHeight = firstImage[0].naturalHeight; var adjustedHeight = this.$el.width() / naturalWidth * naturalHeight; this.$el.css('height', adjustedHeight + 'px'); } } else { // Get height when image is loaded normally firstImage.one('load', function (el, i) { _this65.$el.css('height', el.offsetHeight + 'px'); }); } } else if (!imageOnly) { var slideHeight = firstSlide.height(); this.$el.css('height', slideHeight + 'px'); } } /** * Get x position from event * @param {Event} e */ }, { key: "_xpos", value: function _xpos(e) { // touch event if (e.targetTouches && e.targetTouches.length >= 1) { return e.targetTouches[0].clientX; } // mouse event return e.clientX; } /** * Get y position from event * @param {Event} e */ }, { key: "_ypos", value: function _ypos(e) { // touch event if (e.targetTouches && e.targetTouches.length >= 1) { return e.targetTouches[0].clientY; } // mouse event return e.clientY; } /** * Wrap index * @param {Number} x */ }, { key: "_wrap", value: function _wrap(x) { return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + x % this.count) : x; } /** * Tracks scrolling information */ }, { key: "_track", value: function _track() { var now = void 0, elapsed = void 0, delta = void 0, v = void 0; now = Date.now(); elapsed = now - this.timestamp; this.timestamp = now; delta = this.offset - this.frame; this.frame = this.offset; v = 1000 * delta / (1 + elapsed); this.velocity = 0.8 * v + 0.2 * this.velocity; } /** * Auto scrolls to nearest carousel item. */ }, { key: "_autoScroll", value: function _autoScroll() { var elapsed = void 0, delta = void 0; if (this.amplitude) { elapsed = Date.now() - this.timestamp; delta = this.amplitude * Math.exp(-elapsed / this.options.duration); if (delta > 2 || delta < -2) { this._scroll(this.target - delta); requestAnimationFrame(this._autoScrollBound); } else { this._scroll(this.target); } } } /** * Scroll to target * @param {Number} x */ }, { key: "_scroll", value: function _scroll(x) { var _this66 = this; // Track scrolling state if (!this.$el.hasClass('scrolling')) { this.el.classList.add('scrolling'); } if (this.scrollingTimeout != null) { window.clearTimeout(this.scrollingTimeout); } this.scrollingTimeout = window.setTimeout(function () { _this66.$el.removeClass('scrolling'); }, this.options.duration); // Start actual scroll var i = void 0, half = void 0, delta = void 0, dir = void 0, tween = void 0, el = void 0, alignment = void 0, zTranslation = void 0, tweenedOpacity = void 0, centerTweenedOpacity = void 0; var lastCenter = this.center; var numVisibleOffset = 1 / this.options.numVisible; this.offset = typeof x === 'number' ? x : this.offset; this.center = Math.floor((this.offset + this.dim / 2) / this.dim); delta = this.offset - this.center * this.dim; dir = delta < 0 ? 1 : -1; tween = -dir * delta * 2 / this.dim; half = this.count >> 1; if (this.options.fullWidth) { alignment = 'translateX(0)'; centerTweenedOpacity = 1; } else { alignment = 'translateX(' + (this.el.clientWidth - this.itemWidth) / 2 + 'px) '; alignment += 'translateY(' + (this.el.clientHeight - this.itemHeight) / 2 + 'px)'; centerTweenedOpacity = 1 - numVisibleOffset * tween; } // Set indicator active if (this.showIndicators) { var diff = this.center % this.count; var activeIndicator = this.$indicators.find('.indicator-item.active'); if (activeIndicator.index() !== diff) { activeIndicator.removeClass('active'); this.$indicators.find('.indicator-item').eq(diff)[0].classList.add('active'); } } // center // Don't show wrapped items. if (!this.noWrap || this.center >= 0 && this.center < this.count) { el = this.images[this._wrap(this.center)]; // Add active class to center item. if (!$(el).hasClass('active')) { this.$el.find('.carousel-item').removeClass('active'); el.classList.add('active'); } var transformString = alignment + " translateX(" + -delta / 2 + "px) translateX(" + dir * this.options.shift * tween * i + "px) translateZ(" + this.options.dist * tween + "px)"; this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); } for (i = 1; i <= half; ++i) { // right side if (this.options.fullWidth) { zTranslation = this.options.dist; tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1; } else { zTranslation = this.options.dist * (i * 2 + tween * dir); tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir); } // Don't show wrapped items. if (!this.noWrap || this.center + i < this.count) { el = this.images[this._wrap(this.center + i)]; var _transformString = alignment + " translateX(" + (this.options.shift + (this.dim * i - delta) / 2) + "px) translateZ(" + zTranslation + "px)"; this._updateItemStyle(el, tweenedOpacity, -i, _transformString); } // left side if (this.options.fullWidth) { zTranslation = this.options.dist; tweenedOpacity = i === half && delta > 0 ? 1 - tween : 1; } else { zTranslation = this.options.dist * (i * 2 - tween * dir); tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir); } // Don't show wrapped items. if (!this.noWrap || this.center - i >= 0) { el = this.images[this._wrap(this.center - i)]; var _transformString2 = alignment + " translateX(" + (-this.options.shift + (-this.dim * i - delta) / 2) + "px) translateZ(" + zTranslation + "px)"; this._updateItemStyle(el, tweenedOpacity, -i, _transformString2); } } // center // Don't show wrapped items. if (!this.noWrap || this.center >= 0 && this.center < this.count) { el = this.images[this._wrap(this.center)]; var _transformString3 = alignment + " translateX(" + -delta / 2 + "px) translateX(" + dir * this.options.shift * tween + "px) translateZ(" + this.options.dist * tween + "px)"; this._updateItemStyle(el, centerTweenedOpacity, 0, _transformString3); } // onCycleTo callback var $currItem = this.$el.find('.carousel-item').eq(this._wrap(this.center)); if (lastCenter !== this.center && typeof this.options.onCycleTo === 'function') { this.options.onCycleTo.call(this, $currItem[0], this.dragged); } // One time callback if (typeof this.oneTimeCallback === 'function') { this.oneTimeCallback.call(this, $currItem[0], this.dragged); this.oneTimeCallback = null; } } /** * Cycle to target * @param {Element} el * @param {Number} opacity * @param {Number} zIndex * @param {String} transform */ }, { key: "_updateItemStyle", value: function _updateItemStyle(el, opacity, zIndex, transform) { el.style[this.xform] = transform; el.style.zIndex = zIndex; el.style.opacity = opacity; el.style.visibility = 'visible'; } /** * Cycle to target * @param {Number} n * @param {Function} callback */ }, { key: "_cycleTo", value: function _cycleTo(n, callback) { var diff = this.center % this.count - n; // Account for wraparound. if (!this.noWrap) { if (diff < 0) { if (Math.abs(diff + this.count) < Math.abs(diff)) { diff += this.count; } } else if (diff > 0) { if (Math.abs(diff - this.count) < diff) { diff -= this.count; } } } this.target = this.dim * Math.round(this.offset / this.dim); // Next if (diff < 0) { this.target += this.dim * Math.abs(diff); // Prev } else if (diff > 0) { this.target -= this.dim * diff; } // Set one time callback if (typeof callback === 'function') { this.oneTimeCallback = callback; } // Scroll if (this.offset !== this.target) { this.amplitude = this.target - this.offset; this.timestamp = Date.now(); requestAnimationFrame(this._autoScrollBound); } } /** * Cycle to next item * @param {Number} [n] */ }, { key: "next", value: function next(n) { if (n === undefined || isNaN(n)) { n = 1; } var index = this.center + n; if (index >= this.count || index < 0) { if (this.noWrap) { return; } index = this._wrap(index); } this._cycleTo(index); } /** * Cycle to previous item * @param {Number} [n] */ }, { key: "prev", value: function prev(n) { if (n === undefined || isNaN(n)) { n = 1; } var index = this.center - n; if (index >= this.count || index < 0) { if (this.noWrap) { return; } index = this._wrap(index); } this._cycleTo(index); } /** * Cycle to nth item * @param {Number} [n] * @param {Function} callback */ }, { key: "set", value: function set(n, callback) { if (n === undefined || isNaN(n)) { n = 0; } if (n > this.count || n < 0) { if (this.noWrap) { return; } n = this._wrap(n); } this._cycleTo(n, callback); } }], [{ key: "init", value: function init(els, options) { return _get(Carousel.__proto__ || Object.getPrototypeOf(Carousel), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Carousel; } }, { key: "defaults", get: function () { return _defaults; } }]); return Carousel; }(Component); M.Carousel = Carousel; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Carousel, 'carousel', 'M_Carousel'); } })(cash); ;(function ($) { 'use strict'; var _defaults = { onOpen: undefined, onClose: undefined }; /** * @class * */ var TapTarget = function (_Component19) { _inherits(TapTarget, _Component19); /** * Construct TapTarget instance * @constructor * @param {Element} el * @param {Object} options */ function TapTarget(el, options) { _classCallCheck(this, TapTarget); var _this67 = _possibleConstructorReturn(this, (TapTarget.__proto__ || Object.getPrototypeOf(TapTarget)).call(this, TapTarget, el, options)); _this67.el.M_TapTarget = _this67; /** * Options for the select * @member TapTarget#options * @prop {Function} onOpen - Callback function called when feature discovery is opened * @prop {Function} onClose - Callback function called when feature discovery is closed */ _this67.options = $.extend({}, TapTarget.defaults, options); _this67.isOpen = false; // setup _this67.$origin = $('#' + _this67.$el.attr('data-target')); _this67._setup(); _this67._calculatePositioning(); _this67._setupEventHandlers(); return _this67; } _createClass(TapTarget, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this.el.TapTarget = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { this._handleDocumentClickBound = this._handleDocumentClick.bind(this); this._handleTargetClickBound = this._handleTargetClick.bind(this); this._handleOriginClickBound = this._handleOriginClick.bind(this); this.el.addEventListener('click', this._handleTargetClickBound); this.originEl.addEventListener('click', this._handleOriginClickBound); // Resize var throttledResize = M.throttle(this._handleResize, 200); this._handleThrottledResizeBound = throttledResize.bind(this); window.addEventListener('resize', this._handleThrottledResizeBound); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('click', this._handleTargetClickBound); this.originEl.removeEventListener('click', this._handleOriginClickBound); window.removeEventListener('resize', this._handleThrottledResizeBound); } /** * Handle Target Click * @param {Event} e */ }, { key: "_handleTargetClick", value: function _handleTargetClick(e) { this.open(); } /** * Handle Origin Click * @param {Event} e */ }, { key: "_handleOriginClick", value: function _handleOriginClick(e) { this.close(); } /** * Handle Resize * @param {Event} e */ }, { key: "_handleResize", value: function _handleResize(e) { this._calculatePositioning(); } /** * Handle Resize * @param {Event} e */ }, { key: "_handleDocumentClick", value: function _handleDocumentClick(e) { if (!$(e.target).closest('.tap-target-wrapper').length) { this.close(); e.preventDefault(); e.stopPropagation(); } } /** * Setup Tap Target */ }, { key: "_setup", value: function _setup() { // Creating tap target this.wrapper = this.$el.parent()[0]; this.waveEl = $(this.wrapper).find('.tap-target-wave')[0]; this.originEl = $(this.wrapper).find('.tap-target-origin')[0]; this.contentEl = this.$el.find('.tap-target-content')[0]; // Creating wrapper if (!$(this.wrapper).hasClass('.tap-target-wrapper')) { this.wrapper = document.createElement('div'); this.wrapper.classList.add('tap-target-wrapper'); this.$el.before($(this.wrapper)); this.wrapper.append(this.el); } // Creating content if (!this.contentEl) { this.contentEl = document.createElement('div'); this.contentEl.classList.add('tap-target-content'); this.$el.append(this.contentEl); } // Creating foreground wave if (!this.waveEl) { this.waveEl = document.createElement('div'); this.waveEl.classList.add('tap-target-wave'); // Creating origin if (!this.originEl) { this.originEl = this.$origin.clone(true, true); this.originEl.addClass('tap-target-origin'); this.originEl.removeAttr('id'); this.originEl.removeAttr('style'); this.originEl = this.originEl[0]; this.waveEl.append(this.originEl); } this.wrapper.append(this.waveEl); } } /** * Calculate positioning */ }, { key: "_calculatePositioning", value: function _calculatePositioning() { // Element or parent is fixed position? var isFixed = this.$origin.css('position') === 'fixed'; if (!isFixed) { var parents = this.$origin.parents(); for (var i = 0; i < parents.length; i++) { isFixed = $(parents[i]).css('position') == 'fixed'; if (isFixed) { break; } } } // Calculating origin var originWidth = this.$origin.outerWidth(); var originHeight = this.$origin.outerHeight(); var originTop = isFixed ? this.$origin.offset().top - M.getDocumentScrollTop() : this.$origin.offset().top; var originLeft = isFixed ? this.$origin.offset().left - M.getDocumentScrollLeft() : this.$origin.offset().left; // Calculating screen var windowWidth = window.innerWidth; var windowHeight = window.innerHeight; var centerX = windowWidth / 2; var centerY = windowHeight / 2; var isLeft = originLeft <= centerX; var isRight = originLeft > centerX; var isTop = originTop <= centerY; var isBottom = originTop > centerY; var isCenterX = originLeft >= windowWidth * 0.25 && originLeft <= windowWidth * 0.75; // Calculating tap target var tapTargetWidth = this.$el.outerWidth(); var tapTargetHeight = this.$el.outerHeight(); var tapTargetTop = originTop + originHeight / 2 - tapTargetHeight / 2; var tapTargetLeft = originLeft + originWidth / 2 - tapTargetWidth / 2; var tapTargetPosition = isFixed ? 'fixed' : 'absolute'; // Calculating content var tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth / 2 + originWidth; var tapTargetTextHeight = tapTargetHeight / 2; var tapTargetTextTop = isTop ? tapTargetHeight / 2 : 0; var tapTargetTextBottom = 0; var tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth / 2 - originWidth : 0; var tapTargetTextRight = 0; var tapTargetTextPadding = originWidth; var tapTargetTextAlign = isBottom ? 'bottom' : 'top'; // Calculating wave var tapTargetWaveWidth = originWidth > originHeight ? originWidth * 2 : originWidth * 2; var tapTargetWaveHeight = tapTargetWaveWidth; var tapTargetWaveTop = tapTargetHeight / 2 - tapTargetWaveHeight / 2; var tapTargetWaveLeft = tapTargetWidth / 2 - tapTargetWaveWidth / 2; // Setting tap target var tapTargetWrapperCssObj = {}; tapTargetWrapperCssObj.top = isTop ? tapTargetTop + 'px' : ''; tapTargetWrapperCssObj.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth + 'px' : ''; tapTargetWrapperCssObj.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight + 'px' : ''; tapTargetWrapperCssObj.left = isLeft ? tapTargetLeft + 'px' : ''; tapTargetWrapperCssObj.position = tapTargetPosition; $(this.wrapper).css(tapTargetWrapperCssObj); // Setting content $(this.contentEl).css({ width: tapTargetTextWidth + 'px', height: tapTargetTextHeight + 'px', top: tapTargetTextTop + 'px', right: tapTargetTextRight + 'px', bottom: tapTargetTextBottom + 'px', left: tapTargetTextLeft + 'px', padding: tapTargetTextPadding + 'px', verticalAlign: tapTargetTextAlign }); // Setting wave $(this.waveEl).css({ top: tapTargetWaveTop + 'px', left: tapTargetWaveLeft + 'px', width: tapTargetWaveWidth + 'px', height: tapTargetWaveHeight + 'px' }); } /** * Open TapTarget */ }, { key: "open", value: function open() { if (this.isOpen) { return; } // onOpen callback if (typeof this.options.onOpen === 'function') { this.options.onOpen.call(this, this.$origin[0]); } this.isOpen = true; this.wrapper.classList.add('open'); document.body.addEventListener('click', this._handleDocumentClickBound, true); document.body.addEventListener('touchend', this._handleDocumentClickBound); } /** * Close Tap Target */ }, { key: "close", value: function close() { if (!this.isOpen) { return; } // onClose callback if (typeof this.options.onClose === 'function') { this.options.onClose.call(this, this.$origin[0]); } this.isOpen = false; this.wrapper.classList.remove('open'); document.body.removeEventListener('click', this._handleDocumentClickBound, true); document.body.removeEventListener('touchend', this._handleDocumentClickBound); } }], [{ key: "init", value: function init(els, options) { return _get(TapTarget.__proto__ || Object.getPrototypeOf(TapTarget), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_TapTarget; } }, { key: "defaults", get: function () { return _defaults; } }]); return TapTarget; }(Component); M.TapTarget = TapTarget; if (M.jQueryLoaded) { M.initializeJqueryWrapper(TapTarget, 'tapTarget', 'M_TapTarget'); } })(cash); ;(function ($) { 'use strict'; var _defaults = { classes: '', dropdownOptions: {} }; /** * @class * */ var FormSelect = function (_Component20) { _inherits(FormSelect, _Component20); /** * Construct FormSelect instance * @constructor * @param {Element} el * @param {Object} options */ function FormSelect(el, options) { _classCallCheck(this, FormSelect); // Don't init if browser default version var _this68 = _possibleConstructorReturn(this, (FormSelect.__proto__ || Object.getPrototypeOf(FormSelect)).call(this, FormSelect, el, options)); if (_this68.$el.hasClass('browser-default')) { return _possibleConstructorReturn(_this68); } _this68.el.M_FormSelect = _this68; /** * Options for the select * @member FormSelect#options */ _this68.options = $.extend({}, FormSelect.defaults, options); _this68.isMultiple = _this68.$el.prop('multiple'); // Setup _this68.el.tabIndex = -1; _this68._keysSelected = {}; _this68._valueDict = {}; // Maps key to original and generated option element. _this68._setupDropdown(); _this68._setupEventHandlers(); return _this68; } _createClass(FormSelect, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this._removeDropdown(); this.el.M_FormSelect = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { var _this69 = this; this._handleSelectChangeBound = this._handleSelectChange.bind(this); this._handleOptionClickBound = this._handleOptionClick.bind(this); this._handleInputClickBound = this._handleInputClick.bind(this); $(this.dropdownOptions).find('li:not(.optgroup)').each(function (el) { el.addEventListener('click', _this69._handleOptionClickBound); }); this.el.addEventListener('change', this._handleSelectChangeBound); this.input.addEventListener('click', this._handleInputClickBound); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { var _this70 = this; $(this.dropdownOptions).find('li:not(.optgroup)').each(function (el) { el.removeEventListener('click', _this70._handleOptionClickBound); }); this.el.removeEventListener('change', this._handleSelectChangeBound); this.input.removeEventListener('click', this._handleInputClickBound); } /** * Handle Select Change * @param {Event} e */ }, { key: "_handleSelectChange", value: function _handleSelectChange(e) { this._setValueToInput(); } /** * Handle Option Click * @param {Event} e */ }, { key: "_handleOptionClick", value: function _handleOptionClick(e) { e.preventDefault(); var option = $(e.target).closest('li')[0]; var key = option.id; if (!$(option).hasClass('disabled') && !$(option).hasClass('optgroup') && key.length) { var selected = true; if (this.isMultiple) { // Deselect placeholder option if still selected. var placeholderOption = $(this.dropdownOptions).find('li.disabled.selected'); if (placeholderOption.length) { placeholderOption.removeClass('selected'); placeholderOption.find('input[type="checkbox"]').prop('checked', false); this._toggleEntryFromArray(placeholderOption[0].id); } selected = this._toggleEntryFromArray(key); } else { $(this.dropdownOptions).find('li').removeClass('selected'); $(option).toggleClass('selected', selected); } // Set selected on original select option // Only trigger if selected state changed var prevSelected = $(this._valueDict[key].el).prop('selected'); if (prevSelected !== selected) { $(this._valueDict[key].el).prop('selected', selected); this.$el.trigger('change'); } } e.stopPropagation(); } /** * Handle Input Click */ }, { key: "_handleInputClick", value: function _handleInputClick() { if (this.dropdown && this.dropdown.isOpen) { this._setValueToInput(); this._setSelectedStates(); } } /** * Setup dropdown */ }, { key: "_setupDropdown", value: function _setupDropdown() { var _this71 = this; this.wrapper = document.createElement('div'); $(this.wrapper).addClass('select-wrapper ' + this.options.classes); this.$el.before($(this.wrapper)); this.wrapper.appendChild(this.el); if (this.el.disabled) { this.wrapper.classList.add('disabled'); } // Create dropdown this.$selectOptions = this.$el.children('option, optgroup'); this.dropdownOptions = document.createElement('ul'); this.dropdownOptions.id = "select-options-" + M.guid(); $(this.dropdownOptions).addClass('dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')); // Create dropdown structure. if (this.$selectOptions.length) { this.$selectOptions.each(function (el) { if ($(el).is('option')) { // Direct descendant option. var optionEl = void 0; if (_this71.isMultiple) { optionEl = _this71._appendOptionWithIcon(_this71.$el, el, 'multiple'); } else { optionEl = _this71._appendOptionWithIcon(_this71.$el, el); } _this71._addOptionToValueDict(el, optionEl); } else if ($(el).is('optgroup')) { // Optgroup. var selectOptions = $(el).children('option'); $(_this71.dropdownOptions).append($('
  • ' + el.getAttribute('label') + '
  • ')[0]); selectOptions.each(function (el) { var optionEl = _this71._appendOptionWithIcon(_this71.$el, el, 'optgroup-option'); _this71._addOptionToValueDict(el, optionEl); }); } }); } this.$el.after(this.dropdownOptions); // Add input dropdown this.input = document.createElement('input'); $(this.input).addClass('select-dropdown dropdown-trigger'); this.input.setAttribute('type', 'text'); this.input.setAttribute('readonly', 'true'); this.input.setAttribute('data-target', this.dropdownOptions.id); if (this.el.disabled) { $(this.input).prop('disabled', 'true'); } this.$el.before(this.input); this._setValueToInput(); // Add caret var dropdownIcon = $(''); this.$el.before(dropdownIcon[0]); // Initialize dropdown if (!this.el.disabled) { var dropdownOptions = $.extend({}, this.options.dropdownOptions); // Add callback for centering selected option when dropdown content is scrollable dropdownOptions.onOpenEnd = function (el) { var selectedOption = $(_this71.dropdownOptions).find('.selected').first(); if (selectedOption.length) { // Focus selected option in dropdown M.keyDown = true; _this71.dropdown.focusedIndex = selectedOption.index(); _this71.dropdown._focusFocusedItem(); M.keyDown = false; // Handle scrolling to selected option if (_this71.dropdown.isScrollable) { var scrollOffset = selectedOption[0].getBoundingClientRect().top - _this71.dropdownOptions.getBoundingClientRect().top; // scroll to selected option scrollOffset -= _this71.dropdownOptions.clientHeight / 2; // center in dropdown _this71.dropdownOptions.scrollTop = scrollOffset; } } }; if (this.isMultiple) { dropdownOptions.closeOnClick = false; } this.dropdown = M.Dropdown.init(this.input, dropdownOptions); } // Add initial selections this._setSelectedStates(); } /** * Add option to value dict * @param {Element} el original option element * @param {Element} optionEl generated option element */ }, { key: "_addOptionToValueDict", value: function _addOptionToValueDict(el, optionEl) { var index = Object.keys(this._valueDict).length; var key = this.dropdownOptions.id + index; var obj = {}; optionEl.id = key; obj.el = el; obj.optionEl = optionEl; this._valueDict[key] = obj; } /** * Remove dropdown */ }, { key: "_removeDropdown", value: function _removeDropdown() { $(this.wrapper).find('.caret').remove(); $(this.input).remove(); $(this.dropdownOptions).remove(); $(this.wrapper).before(this.$el); $(this.wrapper).remove(); } /** * Setup dropdown * @param {Element} select select element * @param {Element} option option element from select * @param {String} type * @return {Element} option element added */ }, { key: "_appendOptionWithIcon", value: function _appendOptionWithIcon(select, option, type) { // Add disabled attr if disabled var disabledClass = option.disabled ? 'disabled ' : ''; var optgroupClass = type === 'optgroup-option' ? 'optgroup-option ' : ''; var multipleCheckbox = this.isMultiple ? "" : option.innerHTML; var liEl = $('
  • '); var spanEl = $(''); spanEl.html(multipleCheckbox); liEl.addClass(disabledClass + " " + optgroupClass); liEl.append(spanEl); // add icons var iconUrl = option.getAttribute('data-icon'); if (!!iconUrl) { var imgEl = $("\"\""); liEl.prepend(imgEl); } // Check for multiple type. $(this.dropdownOptions).append(liEl[0]); return liEl[0]; } /** * Toggle entry from option * @param {String} key Option key * @return {Boolean} if entry was added or removed */ }, { key: "_toggleEntryFromArray", value: function _toggleEntryFromArray(key) { var notAdded = !this._keysSelected.hasOwnProperty(key); var $optionLi = $(this._valueDict[key].optionEl); if (notAdded) { this._keysSelected[key] = true; } else { delete this._keysSelected[key]; } $optionLi.toggleClass('selected', notAdded); // Set checkbox checked value $optionLi.find('input[type="checkbox"]').prop('checked', notAdded); // use notAdded instead of true (to detect if the option is selected or not) $optionLi.prop('selected', notAdded); return notAdded; } /** * Set text value to input */ }, { key: "_setValueToInput", value: function _setValueToInput() { var values = []; var options = this.$el.find('option'); options.each(function (el) { if ($(el).prop('selected')) { var text = $(el).text(); values.push(text); } }); if (!values.length) { var firstDisabled = this.$el.find('option:disabled').eq(0); if (firstDisabled.length && firstDisabled[0].value === '') { values.push(firstDisabled.text()); } } this.input.value = values.join(', '); } /** * Set selected state of dropdown to match actual select element */ }, { key: "_setSelectedStates", value: function _setSelectedStates() { this._keysSelected = {}; for (var key in this._valueDict) { var option = this._valueDict[key]; var optionIsSelected = $(option.el).prop('selected'); $(option.optionEl).find('input[type="checkbox"]').prop('checked', optionIsSelected); if (optionIsSelected) { this._activateOption($(this.dropdownOptions), $(option.optionEl)); this._keysSelected[key] = true; } else { $(option.optionEl).removeClass('selected'); } } } /** * Make option as selected and scroll to selected position * @param {jQuery} collection Select options jQuery element * @param {Element} newOption element of the new option */ }, { key: "_activateOption", value: function _activateOption(collection, newOption) { if (newOption) { if (!this.isMultiple) { collection.find('li.selected').removeClass('selected'); } var option = $(newOption); option.addClass('selected'); } } /** * Get Selected Values * @return {Array} Array of selected values */ }, { key: "getSelectedValues", value: function getSelectedValues() { var selectedValues = []; for (var key in this._keysSelected) { selectedValues.push(this._valueDict[key].el.value); } return selectedValues; } }], [{ key: "init", value: function init(els, options) { return _get(FormSelect.__proto__ || Object.getPrototypeOf(FormSelect), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_FormSelect; } }, { key: "defaults", get: function () { return _defaults; } }]); return FormSelect; }(Component); M.FormSelect = FormSelect; if (M.jQueryLoaded) { M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect'); } })(cash); ;(function ($, anim) { 'use strict'; var _defaults = {}; /** * @class * */ var Range = function (_Component21) { _inherits(Range, _Component21); /** * Construct Range instance * @constructor * @param {Element} el * @param {Object} options */ function Range(el, options) { _classCallCheck(this, Range); var _this72 = _possibleConstructorReturn(this, (Range.__proto__ || Object.getPrototypeOf(Range)).call(this, Range, el, options)); _this72.el.M_Range = _this72; /** * Options for the range * @member Range#options */ _this72.options = $.extend({}, Range.defaults, options); _this72._mousedown = false; // Setup _this72._setupThumb(); _this72._setupEventHandlers(); return _this72; } _createClass(Range, [{ key: "destroy", /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this._removeThumb(); this.el.M_Range = undefined; } /** * Setup Event Handlers */ }, { key: "_setupEventHandlers", value: function _setupEventHandlers() { this._handleRangeChangeBound = this._handleRangeChange.bind(this); this._handleRangeMousedownTouchstartBound = this._handleRangeMousedownTouchstart.bind(this); this._handleRangeInputMousemoveTouchmoveBound = this._handleRangeInputMousemoveTouchmove.bind(this); this._handleRangeMouseupTouchendBound = this._handleRangeMouseupTouchend.bind(this); this._handleRangeBlurMouseoutTouchleaveBound = this._handleRangeBlurMouseoutTouchleave.bind(this); this.el.addEventListener('change', this._handleRangeChangeBound); this.el.addEventListener('mousedown', this._handleRangeMousedownTouchstartBound); this.el.addEventListener('touchstart', this._handleRangeMousedownTouchstartBound); this.el.addEventListener('input', this._handleRangeInputMousemoveTouchmoveBound); this.el.addEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound); this.el.addEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound); this.el.addEventListener('mouseup', this._handleRangeMouseupTouchendBound); this.el.addEventListener('touchend', this._handleRangeMouseupTouchendBound); this.el.addEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound); this.el.addEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound); this.el.addEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound); } /** * Remove Event Handlers */ }, { key: "_removeEventHandlers", value: function _removeEventHandlers() { this.el.removeEventListener('change', this._handleRangeChangeBound); this.el.removeEventListener('mousedown', this._handleRangeMousedownTouchstartBound); this.el.removeEventListener('touchstart', this._handleRangeMousedownTouchstartBound); this.el.removeEventListener('input', this._handleRangeInputMousemoveTouchmoveBound); this.el.removeEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound); this.el.removeEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound); this.el.removeEventListener('mouseup', this._handleRangeMouseupTouchendBound); this.el.removeEventListener('touchend', this._handleRangeMouseupTouchendBound); this.el.removeEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound); this.el.removeEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound); this.el.removeEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound); } /** * Handle Range Change * @param {Event} e */ }, { key: "_handleRangeChange", value: function _handleRangeChange() { $(this.value).html(this.$el.val()); if (!$(this.thumb).hasClass('active')) { this._showRangeBubble(); } var offsetLeft = this._calcRangeOffset(); $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); } /** * Handle Range Mousedown and Touchstart * @param {Event} e */ }, { key: "_handleRangeMousedownTouchstart", value: function _handleRangeMousedownTouchstart(e) { // Set indicator value $(this.value).html(this.$el.val()); this._mousedown = true; this.$el.addClass('active'); if (!$(this.thumb).hasClass('active')) { this._showRangeBubble(); } if (e.type !== 'input') { var offsetLeft = this._calcRangeOffset(); $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); } } /** * Handle Range Input, Mousemove and Touchmove */ }, { key: "_handleRangeInputMousemoveTouchmove", value: function _handleRangeInputMousemoveTouchmove() { if (this._mousedown) { if (!$(this.thumb).hasClass('active')) { this._showRangeBubble(); } var offsetLeft = this._calcRangeOffset(); $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); $(this.value).html(this.$el.val()); } } /** * Handle Range Mouseup and Touchend */ }, { key: "_handleRangeMouseupTouchend", value: function _handleRangeMouseupTouchend() { this._mousedown = false; this.$el.removeClass('active'); } /** * Handle Range Blur, Mouseout and Touchleave */ }, { key: "_handleRangeBlurMouseoutTouchleave", value: function _handleRangeBlurMouseoutTouchleave() { if (!this._mousedown) { var paddingLeft = parseInt(this.$el.css('padding-left')); var marginLeft = 7 + paddingLeft + 'px'; if ($(this.thumb).hasClass('active')) { anim.remove(this.thumb); anim({ targets: this.thumb, height: 0, width: 0, top: 10, easing: 'easeOutQuad', marginLeft: marginLeft, duration: 100 }); } $(this.thumb).removeClass('active'); } } /** * Setup dropdown */ }, { key: "_setupThumb", value: function _setupThumb() { this.thumb = document.createElement('span'); this.value = document.createElement('span'); $(this.thumb).addClass('thumb'); $(this.value).addClass('value'); $(this.thumb).append(this.value); this.$el.after(this.thumb); } /** * Remove dropdown */ }, { key: "_removeThumb", value: function _removeThumb() { $(this.thumb).remove(); } /** * morph thumb into bubble */ }, { key: "_showRangeBubble", value: function _showRangeBubble() { var paddingLeft = parseInt($(this.thumb).parent().css('padding-left')); var marginLeft = -7 + paddingLeft + 'px'; // TODO: fix magic number? anim.remove(this.thumb); anim({ targets: this.thumb, height: 30, width: 30, top: -30, marginLeft: marginLeft, duration: 300, easing: 'easeOutQuint' }); } /** * Calculate the offset of the thumb * @return {Number} offset in pixels */ }, { key: "_calcRangeOffset", value: function _calcRangeOffset() { var width = this.$el.width() - 15; var max = parseFloat(this.$el.attr('max')) || 100; // Range default max var min = parseFloat(this.$el.attr('min')) || 0; // Range default min var percent = (parseFloat(this.$el.val()) - min) / (max - min); return percent * width; } }], [{ key: "init", value: function init(els, options) { return _get(Range.__proto__ || Object.getPrototypeOf(Range), "init", this).call(this, this, els, options); } /** * Get Instance */ }, { key: "getInstance", value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Range; } }, { key: "defaults", get: function () { return _defaults; } }]); return Range; }(Component); M.Range = Range; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Range, 'range', 'M_Range'); } Range.init($('input[type=range]')); })(cash, M.anime); ================================================ FILE: resources/assets/css/app.css ================================================ body { background-color: lightgray; } ================================================ FILE: resources/assets/js/app.js ================================================ /* * Welcome to your app's main JavaScript file! * * We recommend including the built version of this JavaScript file * (and its CSS file) in your base layout (base.html.twig). */ // any CSS you require will output into a single css file (app.css in this case) require('../css/app.css'); // Need jQuery? Install it with "yarn add jquery", then uncomment to require it. // const $ = require('jquery'); console.log('Hello Webpack Encore! Edit me in assets/js/app.js'); ================================================ FILE: resources/templates/admin/command/list.twig ================================================ {# templates/admin/list.html.twig #} {% extends '@EasyAdmin/default/list.html.twig' %} {% block table_body %} {% for item in commandsWithCompany %} {% if item.id is not defined %} {{ item }} {% else %} {# the empty string concatenation is needed when the primary key is an object (e.g. an Uuid object) #} {% set _item_id = '' ~ attribute(item, _entity_config.primary_key_field_name) %} {% for field, metadata in fields %} {% set isSortingField = metadata.property == app.request.get('sortField') %} {% set _column_label = (metadata.label ?: field|humanize)|trans(_trans_parameters) %} {{ easyadmin_render_field_for_list_view(_entity_config.name, item, metadata) }} {% endfor %} {% endif %} {% else %} {{ 'search.no_results'|trans(_trans_parameters, 'EasyAdminBundle') }} {% endfor %} {% endblock table_body %} {% block content_footer %}
    {{ total }} résultats
    {% endblock %} ================================================ FILE: resources/templates/base_resto.html.twig ================================================ {% block title %}S'eat restaurant{% endblock %} {% block stylesheets %}{% endblock %}
    {% for label, flashes in app.session.flashbag.all %} {% for flash in flashes %} {% if label == 'success' %}
    check {{ flash|trans }}
    {% elseif label == 'warning' %}
    warning {{ flash|trans }}
    {% elseif label == 'error' %}
    error {{ flash|trans }}
    {% endif %} {% endfor %} {% endfor %} {% block body %}{% endblock %}
    {% if showBasketMobileMenu is defined and basket is defined and orderType is defined and orderType is not null and basket is not null and basket.products > 0 and orderType.error() == null %} {% endif %} {% block javascripts %}{% endblock %} ================================================ FILE: resources/templates/bundles/EasyAdminBundle/default/layout.html.twig ================================================ {# DO THIS: the '!' symbol tells Symfony to extend from the original template #} {% extends '@!EasyAdmin/default/layout.html.twig' %} ================================================ FILE: resources/templates/component/download.html.twig ================================================

    {{ pdf.text }}

    ================================================ FILE: resources/templates/default/registration_complete.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'registration-complete'|content }}
    {% endblock %} ================================================ FILE: resources/templates/form/field-new.html.twig ================================================ {{ form_widget(form[fieldName],{attr:{class:errors[fieldName] is defined ? 'invalid':''}}) }} {{ form_label(form[fieldName]) }} {% if errors[fieldName] is defined %} {% endif %} ================================================ FILE: resources/templates/form/field.html.twig ================================================ {{ form_widget(form[fieldName],{value: attribute(formValues, fieldName) ,attr:{class:errors[fieldName] ? 'invalid':''}}) }} {{ form_label(form[fieldName]) }} {% if errors[fieldName] %} {% endif %} ================================================ FILE: resources/templates/order/confirm-basket.html.twig ================================================ {#{% if orderType != null %}#} {# {% if orderType.error() == null %}#} {% if basket.count() > 0 %} {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }} {% endif %} {# {% else %}#} {#
    {{ orderType.error().getMessage()|trans }}
    #} {# {% endif %}#} {#{% endif %}#} ================================================ FILE: resources/templates/order/go-to-confirm-basket.html.twig ================================================ {% if orderType != null %} {% if orderType.error() == null %} {% if basket.products|length > 0 %} Commander {% endif %} {% else %}
    {{ orderType.error().getMessage()|trans }}
    {% endif %} {% endif %} ================================================ FILE: resources/templates/order/summary.html.twig ================================================ {% if basket.products|length > 0 %}
    Total
    {{ basket.totalPrice }} €
    {% endif %} ================================================ FILE: resources/templates/order/the-menu.html.twig ================================================
    {% verbatim %} {% endverbatim %}
    ================================================ FILE: resources/templates/page/basket.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {% include 'order/summary.html.twig' with { basket:basket } only %}
    Paiement
    Via facture
    Type de commande
    {{ form.orderTypeName.vars.value|trans }}
    {% if form.orderTypeName.vars.value %} {% include 'order/confirm-basket.html.twig' with { form:form, basket:basket } only %} {% endif %}
    {% endblock %} ================================================ FILE: resources/templates/page/business-lunch.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'business-lunch'|content }} {{ 'business-lunch-waterloo'|download }} {{ 'business-lunch-genval'|download }}
    {% endblock %} ================================================ FILE: resources/templates/page/contact.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'contact'|content }}
    {% endblock %} ================================================ FILE: resources/templates/page/home.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}

    {{ title }}

      {% for product in products %}
    • {% if product.isAvailable %} {{ product.name }} {% else %} {{ product.name }} {% endif %}
    • {% endfor %}
    {{ 'presentation'|raw }}
    {% endblock %} {% block javascripts %} {% endblock %} ================================================ FILE: resources/templates/page/login.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {% if error %}
    {{ error.messageKey|trans }}
    {% endif %}
    {% endblock %} ================================================ FILE: resources/templates/page/menu-salle.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'menu-salle'|content }} {{ 'menu-salle-waterloo'|download }} {{ 'menu-salle-genval'|download }}
    {% endblock %} ================================================ FILE: resources/templates/page/order-done.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'order-complete'|content }}
    {% endblock %} ================================================ FILE: resources/templates/page/register-complete.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'registration-complete'|content }}
    {% endblock %} ================================================ FILE: resources/templates/page/register.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body %}
    {{ 'register'|content }}
    {{ form_start(form, {'attr': {'class': 'col push-l2 l8 m12 s12','novalidate':'novalidate'} }) }}
    {{ form_widget(form.companyName,{attr:{class:viewModel.errors.companyName is defined ? 'invalid':''}}) }} {{ form_label(form.companyName) }} {% if viewModel.errors.companyName is defined %} {% endif %}
    {{ form_widget(form.firstName,{attr:{class:viewModel.errors.firstName is defined ? 'invalid':''}}) }} {{ form_label(form.firstName) }} {% if viewModel.errors.firstName is defined%} {% endif %}
    {{ form_widget(form.lastName,{attr:{class:viewModel.errors.lastName is defined ? 'invalid':''}}) }} {{ form_label(form.lastName) }} {% if viewModel.errors.lastName is defined%} {% endif %}
    {{ form_widget(form.email,{attr:{class:viewModel.errors.email is defined? 'invalid':''}}) }} {{ form_label(form.email) }} {% if viewModel.errors.email is defined %} {% endif %}
    {{ form_widget(form.phoneNumber,{attr:{class:viewModel.errors.phoneNumber is defined ? 'invalid':''}}) }} {{ form_label(form.phoneNumber) }} {% if viewModel.errors.phoneNumber is defined %} {% endif %}
    {{ form_widget(form.password,{attr:{class:viewModel.errors.password is defined ? 'invalid':''}}) }} {{ form_label(form.password) }} {% if viewModel.errors.password is defined %} {% endif %}
    {{ form_widget(form.store) }} {{ form_label(form.store) }}
    {{ form_end(form) }}
    {% endblock %} {% block javascripts %} {% endblock %} ================================================ FILE: resources/templates/page/take-away.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block javascripts %} {% verbatim %} {% endverbatim %} {% endblock %} {% block body %}
    {{ 'take-away'|content }}
    {% if app.user %}
    Votre panier {% if basket.products|length == 0 %}

    Votre panier est vide

    {% endif %} {% include 'order/summary.html.twig' with {basket:basket} only %} {% include 'order/go-to-confirm-basket.html.twig' with {orderType:orderType, basket:basket} only %}
    {% endif %}
    {% endblock %} ================================================ FILE: resources/templates/page/update-client.html.twig ================================================ {% extends 'base_resto.html.twig' %} {% block body -%}
    {{ form_start(form, {'attr': {'class': 'col push-l2 l8 m12 s12','novalidate':'novalidate'} }) }}
    {% include 'form/field-new.html.twig' with {form:form, 'errors': errors|default([]),'fieldName': 'firstName'} only %}
    {% include 'form/field-new.html.twig' with {form:form, 'errors':errors|default([]),'fieldName': 'lastName'} only %}
    {% include 'form/field-new.html.twig' with {form:form, 'errors':errors|default([]),'fieldName': 'email'} only %}
    {% include 'form/field-new.html.twig' with {form:form, 'errors':errors|default([]),'fieldName': 'phoneNumber'} only %}
    {% include 'form/field-new.html.twig' with {form:form, 'errors':errors|default([]),'fieldName': 'password'} only %}
    {{ form_end(form) }}
    {% endblock %} ================================================ FILE: resources/translations/EasyAdminBundle.fr.xlf ================================================
    search.no_results __search.no_results
    ================================================ FILE: resources/translations/messages.fr.yaml ================================================ "delivery": Livraison "take-away": À emporter "error-notEmpty": Ce champs est obligatoire "error-string": Ce champs doit être composé de lettres "error-choice": Choix invalide "invalid-email": E-mail invalide "unknown-company": Cette société n'existe pas "disabled-company": La société a été désactivée "email-already-used": Cet e-mail est déjà utilisé "unknown-client": Le client n'existe pas "unknown-email": L'utilisateur n'existe pas "invalid-password": Mot de passe incorrect "disabled-user": L'utilisateur a été désactivé "unknown-supplement": Un des suppléments sélectionné n'existe plus "unknown-product": Ce produit n'existe plus "unknown-option": L'option sélectionnée n'existe plus "my-info-updated": Vos informations ont bien été mises à jour "new-password-login-needed": Vos informations ont bien été mises à jour. Veuillez vous reconnecter avec votre nouveau mot de passe "wrong-check-sum": Le panier a été modifé entre temps. Veuillez réessayer "empty-basket": Impossible de commander car votre panier est vide "Delivery not available": La livraison n'est pas disponible "Order too late": Il est trop tard pour faire une commande "Take away not available": L'option "à emporter" est indisponible "Take away too late": Il est trop tard pour commander "à emporter" "Company name": Société "First name": Prénom "Last name": Nom "Email": E-mail "Phone number": Téléphone "Password": Mot de passe "La hulpe": La hulpe "Waterloo": Waterloo "Store": Restaurant # Admin "Quantity": Quantité "Name": Nom "Comment": Commentaires "Order type string": "Type" ================================================ FILE: src/Seat/Domain/Basket/Entity/Basket.php ================================================ userId = $userId; } public function totalPrice() { $price = 0; /** @var BasketProduct $basketProduct */ foreach ($this as $basketProduct) { $price += $basketProduct->totalPrice(); } return $price; } public function userId(): string { return $this->userId; } public function isEmpty() { return $this->count() === 0; } public function checkSum() { $content = ''; /** @var BasketProduct $basketProduct */ foreach ($this as $basketProduct) { $content .= '|'.$basketProduct->id(); } $json = [ 'price' => $this->totalPrice(), 'content' => $content, ]; return sha1(json_encode($json)); } } ================================================ FILE: src/Seat/Domain/Basket/Entity/BasketRepository.php ================================================ id = $id; $this->name = $name; $this->price = $price; $this->option = $option; $this->supplements = $supplements; $this->comment = $comment; $this->quantity = $quantity; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } public function option(): ?BasketProductOption { return $this->option; } /** * @return BasketProductSupplement[] */ public function supplements(): array { return $this->supplements; } public function comment(): string { return $this->comment; } public function quantity(): int { return $this->quantity; } public function totalPrice() { $productPrice = $this->price(); if ($this->option()) { $productPrice += $this->option()->price(); } foreach ($this->supplements() as $supplement) { $productPrice += $supplement->price(); } return $productPrice * $this->quantity(); } } ================================================ FILE: src/Seat/Domain/Basket/Model/BasketProductOption.php ================================================ name = $name; $this->price = $price; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } } ================================================ FILE: src/Seat/Domain/Basket/Model/BasketProductSupplement.php ================================================ name = $name; $this->price = $price; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } } ================================================ FILE: src/Seat/Domain/Basket/Model/OrderType.php ================================================ take-away-time: 12:00:00 private $name; private $time; public static function takeAwayFor($time) { return new OrderType('take-away', $time); } public static function delivery() { return new OrderType('delivery'); } public static function fromString($orderType, $takeAwayTime = null) { switch ($orderType) { case OrderTypeName::$takeAway: return OrderType::takeAwayFor($takeAwayTime); case OrderTypeName::$delivery: return OrderType::delivery(); } throw new \Exception('Invalid order type'); } public function __construct(string $name, ?string $time = null) { $this->name = $name; $this->time = $time; } public function name(): string { return $this->name; } public function time(): ?string { return $this->time; } public function isDelivery() { return $this->name === OrderTypeName::$delivery; } public function isTakeAway() { return $this->name === OrderTypeName::$takeAway; } } ================================================ FILE: src/Seat/Domain/Basket/Model/OrderTypeName.php ================================================ name = $name; $this->range = $range; $this->error = $error; } public function name(): string { return $this->name; } public function range(): ?TimeRange { return $this->range; } public function error(): ?\Exception { return $this->error; } } ================================================ FILE: src/Seat/Domain/Basket/Service/Error/DeliveryNotAvailable.php ================================================ companyRepository = $companyRepository; $this->clientRepository = $clientRepository; $this->clock = $clock; } public function getPossibleOrderType(string $userId): PossibleOrderType { $client = $this->clientRepository->getClientById($userId); if ($client === null) { throw new \Exception('Unknown client'); } return $this->getPossibleOrderTypeForCompany($client->companyId()); } private function getPossibleOrderTypeForCompany(?string $companyId) { $confirmationTime = $this->clock->now()->setTimezone(new DateTimeZone('Europe/Brussels')); $company = null; if ($companyId !== null) { $company = $this->companyRepository->getCompanyById($companyId); } if ($company && $company->canBeDelivered()) { if ($confirmationTime->format('H:i:s') < $company->maxOrderTimeForDelivery()) { return new PossibleOrderType(OrderTypeName::$delivery, null, null); } return new PossibleOrderType(OrderTypeName::$delivery, null, new OrderTooLate()); } else { if ($confirmationTime->format('H:i:s') > self::MAX_TAKE_AWAY_ORDER_HOUR) { return new PossibleOrderType(OrderTypeName::$takeAway, null, new OrderTooLate()); } $currentTime = $confirmationTime->add(DateInterval::createFromDateString('30 minutes')); $timeRange = (new TimeRange('10:30:00', '14:00:00'))->delayFromDate($currentTime, 15); if (count($timeRange->getRoundedStep(15)) === 0) { return new PossibleOrderType(OrderTypeName::$takeAway, null, new TakeAwayTooLate()); } return new PossibleOrderType(OrderTypeName::$takeAway, $timeRange, null); } } /** * @throws DeliveryNotAvailable * @throws OrderTooLate * @throws TakeAwayTooLate * @throws TakeAwayNotAvailable */ public function checkPossibleOrderType(OrderType $orderType, ?string $companyId) { $possibleOrderType = $this->getPossibleOrderTypeForCompany($companyId); if ($orderType->isDelivery() && $possibleOrderType->name() === OrderTypeName::$takeAway) { throw new DeliveryNotAvailable(); } if ($orderType->isTakeAway() && $possibleOrderType->name() === OrderTypeName::$delivery) { throw new TakeAwayNotAvailable(); } if ($possibleOrderType->error()) { throw $possibleOrderType->error(); } if ($orderType->isTakeAway() && $orderType->time() > $possibleOrderType->range()->to()) { throw new TakeAwayTooLate(); } } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/AddProductToBasket/AddProductToBasket.php ================================================ basketRepository = $basketRepository; $this->productRepository = $productRepository; $this->productOptionRepository = $productOptionRepository; $this->productSupplementRepository = $productSupplementRepository; } /** @throws */ public function execute(AddProductToBasketRequest $request, AddProductToBasketPresenter $presenter) { $response = new AddProductToBasketResponse(); $isValid = $this->checkRequest($request, $response); if ($isValid) { $product = $this->getProduct($request, $response); if ($product) { $option = $this->getOption($request, $response, $product); $supplements = $this->getSupplements($request, $response, $product); if (!$response->notification()->hasError()) { $basketProduct = new BasketProduct( Uuid::uuid4()->toString(), $request->quantity, $product->name(), $product->price(), $option, $supplements, (string)$request->comment ); $this->basketRepository->addToBasket($request->userId, $basketProduct); $response->setBasketProduct($basketProduct); } } } $presenter->present($response); } private function getProduct(AddProductToBasketRequest $basketData, AddProductToBasketResponse $response) { $product = $this->productRepository->get($basketData->productId); if ($product === null) { $response->addError('productId', 'unknown-product'); } return $product; } private function getSupplements(AddProductToBasketRequest $basketData, AddProductToBasketResponse $response, Product $product): array { $basketProductSupplements = []; foreach ($basketData->supplementIds as $supplementId) { $supplement = $this->productSupplementRepository->get($supplementId); if ($supplement === null) { $response->addError('supplementIds', 'unknown-supplement'); return []; } if ($supplement->categoryId() !== $product->categoryId()) { $response->addError('supplementIds', 'unknown-supplement'); return []; } $basketProductSupplements[] = new BasketProductSupplement($supplement->name(), $supplement->price()); } return $basketProductSupplements; } private function getOption(AddProductToBasketRequest $basketData, AddProductToBasketResponse $response, Product $product) { if ($basketData->optionId === null) { return null; } $productOption = $this->productOptionRepository->get($basketData->optionId); if ($productOption === null || $productOption->categoryId() !== $product->categoryId()) { $response->addError('optionId', 'unknown-option'); return null; } return new BasketProductOption($productOption->name(), $productOption->price()); } private function checkRequest(AddProductToBasketRequest $request, AddProductToBasketResponse $response): bool { try { Assert::lazy() ->that($request->quantity, 'quantity')->notEmpty('error-notEmpty')->integer('error-integer') ->that($request->userId, 'userId')->notEmpty('error-notEmpty')->string('error-string') ->that($request->productId, 'productId')->notEmpty('error-notEmpty')->string('error-string') ->that($request->optionId, 'optionId')->nullOr()->string('error-string') ->that($request->supplementIds, 'supplementIds')->isArray() ->that($request->comment, 'comment')->nullOr()->string('error-string') ->verifyNow(); return true; } catch (LazyAssertionException $e) { foreach ($e->getErrorExceptions() as $error) { $response->addError($error->getPropertyPath(), $error->getMessage()); } return false; } } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/AddProductToBasket/AddProductToBasketPresenter.php ================================================ quantity = (int)$quantity; $request->userId = $userId; $request->productId = $productId; $request->optionId = $optionId; $request->supplementIds = $supplementIds; $request->comment = $comment; return $request; } public function withUserId(string $userId) { $this->userId = $userId; return $this; } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/AddProductToBasket/AddProductToBasketResponse.php ================================================ notification = new Notification(); } public function addError(string $fieldName, string $error) { $this->notification->addError($fieldName, $error); } public function notification(): Notification { return $this->notification; } public function setBasketProduct(BasketProduct $basketProduct) { $this->basketProduct = $basketProduct; } public function basketProduct(): ?BasketProduct { return $this->basketProduct; } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/RemoveFromBasket/RemoveFromBasket.php ================================================ basketRepository = $basketRepository; } public function execute(RemoveFromBasketRequest $request, RemoveFromBasketPresenter $presenter) { $response = new RemoveFromBasketResponse(); $this->basketRepository->delete($request->basketId, $request->userId); $response->setIsDone(true); $presenter->present($response); } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/RemoveFromBasket/RemoveFromBasketPresenter.php ================================================ userId = $userId; $this->basketId = $basketId; } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/RemoveFromBasket/RemoveFromBasketResponse.php ================================================ isDone; } public function setIsDone($isDone) { $this->isDone = $isDone; return $this; } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/ShowBasket/ShowBasket.php ================================================ basketRepository = $basketRepository; } public function execute(ShowBasketRequest $request, ShowBasketPresenter $presenter) { $response = new ShowBasketResponse(); $basket = $this->basketRepository->getUserBasket($request->userId); $response->setBasket($basket); $presenter->present($response); } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/ShowBasket/ShowBasketPresenter.php ================================================ userId = $userId; } } ================================================ FILE: src/Seat/Domain/Basket/UseCase/ShowBasket/ShowBasketResponse.php ================================================ basket = $basket; return $this; } public function basket(): ?Basket { return $this->basket; } } ================================================ FILE: src/Seat/Domain/Client/Entity/Client.php ================================================ id = $id; $this->firstName = $firstName; $this->lastName = $lastName; $this->phoneNumber = $phoneNumber; $this->email = $email; $this->password = $password; $this->store = $store; $this->companyId = $companyId; $this->role = $role; $this->isEnabled = $isEnabled; } public function firstName(): string { return $this->firstName; } public function lastName(): string { return $this->lastName; } public function phoneNumber(): string { return $this->phoneNumber; } public function id(): string { return $this->id; } public function email(): string { return $this->email; } public function password(): string { return $this->password; } public function store(): string { return $this->store; } public function companyId(): ?string { return $this->companyId; } public function hasCompany() { return $this->companyId !== null; } public function role(): string { return $this->role; } public function isEnabled(): bool { return $this->isEnabled; } } ================================================ FILE: src/Seat/Domain/Client/Entity/ClientRepository.php ================================================ id = $id; $this->name = $name; $this->maxOrderTimeForDelivery = $maxOrderTimeForDelivery; $this->hasInvoice = $hasInvoice; $this->store = $store; $this->isEnabled = $isEnabled; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function maxOrderTimeForDelivery(): ?string { return $this->maxOrderTimeForDelivery; } public function canBeDelivered(): bool { return $this->maxOrderTimeForDelivery !== null; } public function hasInvoice(): bool { return $this->hasInvoice; } public function store(): string { return $this->store; } public function isEnabled(): bool { return $this->isEnabled; } } ================================================ FILE: src/Seat/Domain/Client/Entity/CompanyRepository.php ================================================ clientRepository = $clientRepository; } public function execute(GetClientRequest $request, GetClientPresenter $presenter) { $client = $this->clientRepository->getClientById($request->clientId); $response = new GetClientResponse(); if ($client !== null) { $response->setClient($client); } $presenter->present($response); } } ================================================ FILE: src/Seat/Domain/Client/UseCase/GetClient/GetClientPresenter.php ================================================ clientId = $clientId; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/GetClient/GetClientResponse.php ================================================ client; } public function setClient(Client $client) { $this->client = $client; return $this; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/Login/Login.php ================================================ clientRepository = $clientRepository; $this->passwordHasher = $passwordHasher; $this->companyRepository = $companyRepository; } /** * throws DisabledUser * throws DisabledCompany * throws UnknownUser * throws WrongPassword */ public function execute(LoginRequest $request, LoginPresenter $presenter) { $response = new LoginResponse(); $client = $this->clientRepository->getClientByEmail($request->email); $isValid = $this->checkClient($client, $response); $isValid = $isValid && $this->checkPassword($request, $client, $response); $isValid = $isValid && $this->checkClientEnabled($client, $response); $isValid = $isValid && $this->checkCompanyEnabled($client, $response); if($isValid){ $response->setClient($client); } return $presenter->present($response); } private function checkClient(?Client $client, LoginResponse $response): bool { if ($client === null) { $response->addError('email', 'unknown-email'); return false; } return true; } private function checkPassword(LoginRequest $request, Client $client, LoginResponse $response): bool { if (!$this->passwordHasher->isPasswordValid($client->password(), $request->password)) { $response->addError('password', 'invalid-password'); return false; } return true; } private function checkClientEnabled(Client $client, LoginResponse $response): bool { if (!$client->isEnabled()) { $response->addError('email', 'disabled-user'); return false; } return true; } private function checkCompanyEnabled(Client $client, LoginResponse $response): bool { if ($client->hasCompany()) { $company = $this->companyRepository->getCompanyById($client->companyId()); if (!$company->isEnabled()) { $response->addError('email', 'disabled-company'); return false; } } return true; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/Login/LoginPresenter.php ================================================ email = $email; $this->password = $password; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/Login/LoginResponse.php ================================================ notification = new Notification(); } public function addError(string $fieldName, string $error) { $this->notification->addError($fieldName, $error); } public function notification(): Notification { return $this->notification; } public function setClient(Client $client) { $this->client = $client; } public function client(): ?Client { return $this->client; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/Register/Register.php ================================================ clientRepository = $clientRepository; $this->idGenerator = $idGenerator; $this->passwordHasher = $passwordHasher; $this->companyRepository = $companyRepository; } public function execute(RegisterRequest $request): void { $response = new RegisterResponse(); if ($request->isPosted) { $this->register($request, $response); } $presenter->present($response); } private function register(RegisterRequest $request, RegisterResponse $response) { $isValid = $this->validateRequest($request, $response); $isValid = $this->validateCompany($request, $response, $company) && $isValid; $isValid = $this->validateClient($request, $response) && $isValid; if ($isValid) { $this->saveClient($request, $response, $company); } } private function validateClient(RegisterRequest $request, RegisterResponse $response): bool { if ($request->email === null) { return false; } $existingClient = $this->clientRepository->getClientByEmail((string)$request->email); if ($existingClient !== null) { $response->addError('email', 'email-already-used'); return false; } return true; } private function validateCompany(RegisterRequest $request, RegisterResponse $response, &$company): bool { $company = null; if ($request->companyName !== null) { $company = $this->companyRepository->getCompanyNamed($request->companyName); if ($company === null) { $response->addError('companyName', 'unknown-company'); return false; } if (!$company->isEnabled()) { $response->addError('companyName', 'disabled-company'); return false; } } return true; } private function saveClient(RegisterRequest $request, RegisterResponse $response, ?Company $company): void { $hashedPassword = $this->passwordHasher->hash($request->password); $client = new Client( $this->idGenerator->next(), $request->firstName, $request->lastName, $request->email, $request->phoneNumber, $hashedPassword, $company ? $company->store() : $request->store, Role::$client, true, $company ? $company->id() : null ); $this->clientRepository->addClient($client); $response->setRegisteredClient($client); } private function validateRequest(RegisterRequest $request, RegisterResponse $response) { try { Assert::lazy() ->that($request->firstName, 'firstName')->notEmpty('error-notEmpty')->string('error-string') ->that($request->lastName, 'lastName')->notEmpty('error-notEmpty')->string('error-string') ->that($request->email, 'email')->notEmpty('error-notEmpty')->email('invalid-email') ->that($request->phoneNumber, 'phoneNumber')->notEmpty('error-notEmpty') ->that($request->password, 'password')->notEmpty('error-notEmpty')->string('error-string') ->that($request->companyName, 'companyName') ->that($request->store, 'store')->notEmpty('error-notEmpty')->choice(Store::$all, 'error-choice') ->verifyNow(); return true; } catch (LazyAssertionException $e) { foreach ($e->getErrorExceptions() as $error) { $response->addError($error->getPropertyPath(), $error->getMessage()); } return false; } } } ================================================ FILE: src/Seat/Domain/Client/UseCase/Register/RegisterPresenter.php ================================================ note = new Notification(); } public function addError(string $fieldName, string $error) { $this->note->addError($fieldName, $error); } public function notification(): Notification { return $this->note; } public function setRegisteredClient(Client $client) { $this->client = $client; return $this; } public function client(): ?Client { return $this->client; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/UpdateClient/UpdateClient.php ================================================ clientRepository = $clientRepository; $this->passwordHasher = $passwordHasher; } public function execute(UpdateClientRequest $request, UpdateClientPresenter $presenter) { $response = new UpdateClientResponse(); $response->setRequest($request); /** @var Client $client */ $isValid = $this->validateClient($request, $response, $client); $isValid = $this->validateRequest($request, $response) && $isValid; if ($isValid) { $client = new Client( $client->id(), $request->firstName, $request->lastName, $request->email, $request->phoneNumber, $request->password ? $this->passwordHasher->hash($request->password) : $client->password(), $client->store(), $client->role(), $client->isEnabled(), $client->companyId() ); $this->clientRepository->updateClient($client); $response->setUpdatedClient($client); } $presenter->present($response); } private function validateRequest(UpdateClientRequest $request, UpdateClientResponse $response) { try { Assert::lazy() ->that($request->clientId, 'clientId')->notEmpty('error-notEmpty')->string('string') ->that($request->firstName, 'firstName')->notEmpty('error-notEmpty')->string('string') ->that($request->lastName, 'lastName')->notEmpty('error-notEmpty')->string('string') ->that($request->email, 'email')->notEmpty('error-notEmpty')->email('invalid-email') ->that($request->phoneNumber, 'phoneNumber')->notEmpty('error-notEmpty') ->that($request->password, 'password')->nullOr()->string('string') ->verifyNow(); return true; } catch (LazyAssertionException $e) { foreach ($e->getErrorExceptions() as $error) { $response->addError($error->getPropertyPath(), $error->getMessage()); } return false; } } private function validateClient(UpdateClientRequest $request, UpdateClientResponse $response, ?Client &$client) { if ($request->clientId === null) { return false; } $client = $this->clientRepository->getClientById($request->clientId); if ($client === null) { $response->addError('clientId', 'unknown-client'); return false; } $response->setOriginalClient($client); return true; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/UpdateClient/UpdateClientPresenter.php ================================================ firstName = $nullableRequest->firstName; $request->lastName = $nullableRequest->lastName; $request->password = $nullableRequest->password; $request->phoneNumber = $nullableRequest->phoneNumber; $request->email = $nullableRequest->email; $request->clientId = $nullableRequest->clientId; return $request; } public function byClientId(string $clientId) { $this->clientId = $clientId; return $this; } } ================================================ FILE: src/Seat/Domain/Client/UseCase/UpdateClient/UpdateClientResponse.php ================================================ note = new Notification(); } public function addError(string $fieldName, string $error) { $this->note->addError($fieldName, $error); } public function notification(): Notification { return $this->note; } public function setUpdatedClient(Client $client) { $this->updatedClient = $client; $this->hasPasswordChanged = $client->password() !== $this->originalClient->password(); return $this; } public function hasPasswordChanged(): bool { return $this->hasPasswordChanged; } public function updatedClient(): ?Client { return $this->updatedClient; } public function setOriginalClient(?Client $originalClient) { $this->originalClient = $originalClient; } public function originalClient(): ?Client { return $this->originalClient; } public function request(): ?UpdateClientRequest { return $this->request; } public function setRequest(UpdateClientRequest $request) { $this->request = $request; return $this; } } ================================================ FILE: src/Seat/Domain/Cms/Entity/HtmlContent.php ================================================ name = $name; $this->html = $html; } public function name() { return $this->name; } public function html() { return $this->html; } } ================================================ FILE: src/Seat/Domain/Cms/Entity/HtmlContentRepository.php ================================================ id = $id; $this->name = $name; $this->description = $description; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function description(): ?string { return $this->description; } } ================================================ FILE: src/Seat/Domain/Menu/Entity/CategoryRepository.php ================================================ id = $id; $this->name = $name; $this->description = $description; $this->price = $price; $this->categoryId = $categoryId; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function description(): string { return $this->description; } public function price(): float { return $this->price; } public function categoryId(): string { return $this->categoryId; } } ================================================ FILE: src/Seat/Domain/Menu/Entity/ProductOption.php ================================================ id = $id; $this->name = $name; $this->price = $price; $this->categoryId = $categoryId; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } public function categoryId(): string { return $this->categoryId; } } ================================================ FILE: src/Seat/Domain/Menu/Entity/ProductOptionRepository.php ================================================ id = $id; $this->name = $name; $this->price = $price; $this->categoryId = $categoryId; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } public function categoryId(): string { return $this->categoryId; } } ================================================ FILE: src/Seat/Domain/Menu/Entity/ProductSupplementRepository.php ================================================ name = $name; $this->description = $description; $this->options = $options; $this->supplements = $supplements; $this->products = $products; } public function name(): string { return $this->name; } public function description(): ?string { return $this->description; } /** * @return MenuOption[] */ public function options(): array { return $this->options; } /** * @return MenuSupplement[] */ public function supplements(): array { return $this->supplements; } public function products() { return $this->products; } } ================================================ FILE: src/Seat/Domain/Menu/Model/MenuOption.php ================================================ id = $id; $this->name = $name; $this->price = $price; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } } ================================================ FILE: src/Seat/Domain/Menu/Model/MenuProduct.php ================================================ id = $id; $this->name = $name; $this->price = $price; $this->description = $description; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } public function description(): ?string { return $this->description; } } ================================================ FILE: src/Seat/Domain/Menu/Model/MenuSupplement.php ================================================ id = $id; $this->name = $name; $this->price = $price; } public function id(): string { return $this->id; } public function name(): string { return $this->name; } public function price(): float { return $this->price; } } ================================================ FILE: src/Seat/Domain/Menu/UseCase/GetMenu/GetMenu.php ================================================ categoryRepository = $categoryRepository; $this->optionRepository = $optionRepository; $this->supplementRepository = $supplementRepository; $this->productRepository = $productRepository; } public function execute(GetMenuPresenter $presenter) { $menu = []; foreach ($this->categoryRepository->getCategories() as $category) { $menu[] = new MenuLine( $category->name(), $category->description(), $this->getProductsOf($category), $this->getOptionsOf($category), $this->getSupplementsOf($category) ); } $presenter->present(new GetMenuResponse($menu)); } private function getOptionsOf(Category $category): array { $options = $this->optionRepository->getByCategoryId($category->id()); $transformToMenuOption = function (ProductOption $option) { return new MenuOption($option->id(), $option->name(), $option->price()); }; return array_map($transformToMenuOption, $options); } private function getProductsOf(Category $category): array { $products = $this->productRepository->getByCategoryId($category->id()); $transformToMenuProduct = function (Product $product) { return new MenuProduct($product->id(), $product->name(), $product->description(), $product->price()); }; return array_map($transformToMenuProduct, $products); } private function getSupplementsOf(Category $category): array { $supplements = $this->supplementRepository->getByCategoryId($category->id()); $transformToMenuSupplement = function (ProductSupplement $supplement) { return new MenuSupplement($supplement->id(), $supplement->name(), $supplement->price()); }; return array_map($transformToMenuSupplement, $supplements); } } ================================================ FILE: src/Seat/Domain/Menu/UseCase/GetMenu/GetMenuPresenter.php ================================================ menuLines = $menuLines; } } ================================================ FILE: src/Seat/Domain/Order/Entity/Command.php ================================================ id = $id; $this->userId = $userId; $this->basket = $basket; $this->date = $date; $this->orderType = $orderType; } public function id(): string { return $this->id; } public function userId(): string { return $this->userId; } public function basket(): Basket { return $this->basket; } public function date(): DateTimeImmutable { return $this->date; } public function orderType(): OrderType { return $this->orderType; } } ================================================ FILE: src/Seat/Domain/Order/Entity/CommandRepository.php ================================================ commandRepository = $commandRepository; $this->basketRepository = $basketRepository; $this->clientRepository = $clientRepository; $this->orderTypeChecker = $orderTypeChecker; } public function execute(ConfirmBasketRequest $request, ConfirmBasketPresenter $presenter) { $response = new ConfirmBasketResponse(); $this->doExecute($request, $response); $presenter->present($response); } private function doExecute(ConfirmBasketRequest $request, ConfirmBasketResponse $response) { $client = $this->checkClient($request, $response); if ($client === null) { return; } $basket = $this->checkBasket($request, $response); if ($basket === null) { return; } $orderType = $this->checkOrderType($request, $response, $client); if ($orderType === null) { return; } $this->saveBasketToCommand($orderType, $basket, $client); } private function saveBasketToCommand(OrderType $orderType, Basket $basket, Client $client): void { $command = new Command( Uuid::uuid4()->toString(), $client->id(), $orderType, $basket, new DateTimeImmutable() ); $this->commandRepository->add($command); $this->basketRepository->emptyBasketFor($client->id()); } private function checkClient(ConfirmBasketRequest $request, ConfirmBasketResponse $response) { if ($request->userId === null) { $response->addError('userId', 'unknown-client'); return null; } $client = $this->clientRepository->getClientById($request->userId); if ($client === null) { $response->addError('userId', 'unknown-client'); return null; } return $client; } private function checkBasket(ConfirmBasketRequest $request, ConfirmBasketResponse $response): ?Basket { $basket = $this->basketRepository->getUserBasket($request->userId); if ($basket->isEmpty()) { $response->addError('userId', 'empty-basket'); return null; } if ($request->checkSum !== $basket->checkSum()) { $response->addError('checkSum', 'wrong-check-sum'); return null; } return $basket; } private function checkOrderType(ConfirmBasketRequest $request, ConfirmBasketResponse $response, Client $client): ?OrderType { try { $orderType = OrderType::fromString($request->orderTypeName, $request->takeAwayTime); } catch (Exception $e) { $response->addError('orderTypeName', $e->getMessage()); return null; } try { $this->orderTypeChecker->checkPossibleOrderType($orderType, $client->companyId()); } catch (Exception $e) { $response->addError('orderTypeName', $e->getMessage()); return null; } return $orderType; } } ================================================ FILE: src/Seat/Domain/Order/UseCase/ConfirmBasket/ConfirmBasketPresenter.php ================================================ userId = $userId; return $this; } public function withCheckSum($checkSum) { $this->checkSum = $checkSum; return $this; } } ================================================ FILE: src/Seat/Domain/Order/UseCase/ConfirmBasket/ConfirmBasketResponse.php ================================================ notification = new Notification(); } public function addError(string $fieldName, string $error) { $this->notification->addError($fieldName, $error); } public function notification(): Notification { return $this->notification; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/AddToBasketController.php ================================================ execute($nullableRequest->withUserId($user->getId()), $presenter); return $view->generateView($presenter->viewModel()); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/AdminController.php ================================================ listen(); return parent::listAction(); } protected function listCommandWaterlooAction() { $this->listen(); return parent::listAction(); } private function listen() { $this->get('event_dispatcher')->addListener( EasyAdminEvents::POST_LIST, function (GenericEvent $event) { $paginator = $event->getSubject(); $userIds = []; /** @var Command $command */ foreach ($paginator as $command) { $userIds[] = $command->userId(); } } ); return parent::listAction(); } public function renderCommandWaterlooTemplate($type, $twigPath, $parameters) { return $this->renderCommandOfTodayTemplate($type, $twigPath, $parameters, 'waterloo'); } public function renderCommandLaHulpeTemplate($type, $twigPath, $parameters) { return $this->renderCommandOfTodayTemplate($type, $twigPath, $parameters, 'la-hulpe'); } protected function renderCommandOfTodayTemplate($type, $twigPath, $parameters, $store): Response { if ($type !== 'list') { return $this->renderTemplate($type, $twigPath, $parameters); } $commands = []; /** @var Command $commandOfUser */ foreach ($parameters['paginator'] as $commandOfUser) { if (!isset($commands[$commandOfUser->userId()])) { $commands[$commandOfUser->userId()] = []; } $commands[$commandOfUser->userId()][] = $commandOfUser; } $total = 0; $companies = $this->em->createQueryBuilder() ->select(['c.id', 'c.name', 't.name as tourneeName', 'c.canBeDelivered', 'u.id as user_id']) ->from('App:Company', 'c') ->join('App:User', 'u', Join::WITH, 'c.id = u.company') ->join('App:Tournee', 't', Join::WITH, 'c.tournee = t.id') ->where('u.id in (:userIds)') ->andWhere('c.store = :store') ->orderBy('c.name', 'ASC') ->setParameter('userIds', array_keys($commands)) ->setParameter('store', $store) ->getQuery() ->getResult(); $companiesWithUsers = []; foreach ($companies as $company) { if (!isset($companiesWithUsers[$company['id']])) { $orderType = $company['canBeDelivered'] ? 'Livraison "'.$company['tourneeName'].'"' : 'À emporter'; $companiesWithUsers[$company['id']] = [ 'name' => $company['name'].' ('.$orderType.')', 'users' => [], ]; } $companiesWithUsers[$company['id']]['users'][] = $company['user_id']; } $commandsWithCompany = []; foreach ($companiesWithUsers as $company) { $commandsWithCompany[] = $company['name']; foreach ($company['users'] as $userId) { foreach ($commands[$userId] as $commandOfUser) { $commandsWithCompany[] = $commandOfUser; $total++; } unset($commands[$userId]); } } if (!empty($commands)) { $userStore = $this->em->createQueryBuilder() ->select(['u.id', 'u.store']) ->from('App:User', 'u', 'u.id') ->where('u.id in (:userIds)') ->setParameter('userIds', array_keys($commands)) ->getQuery() ->getResult(); $userCommands = []; foreach ($commands as $commandOfUser) { foreach ($commandOfUser as $command) { if ($userStore[$command->userId()]['store'] === $store) { $userCommands[] = $command; $total++; } } } if (!empty($userCommands)) { $commandsWithCompany[] = 'Client sans société'; array_push($commandsWithCompany, ...$userCommands); } } return $this->renderTemplate($type, $twigPath, array_merge($parameters, ['commandsWithCompany' => $commandsWithCompany, 'total' => $total])); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/BusinessLunchController.php ================================================ render('page/business-lunch.html.twig')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/ContactController.php ================================================ render('page/contact.html.twig')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/HomeController.php ================================================ render('page/home.html.twig', ['images' => $images]) ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/LoginCheckController.php ================================================ getLastAuthenticationError(); // last username entered by the user $lastUsername = $authenticationUtils->getLastUsername(); $response = $twig->render( 'page/login.html.twig', [ 'last_username' => $lastUsername, 'error' => $error, ] ); return new Response($response); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/LogoutController.php ================================================ render('page/menu-salle.html.twig')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/RegisterCompleteController.php ================================================ render('page/register-complete.html.twig')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/RegisterController.php ================================================ email = $request->request->get('email'); $registerRequest->password = $request->request->get('password'); $registerUseCase->execute($registerRequest); //... return $view->generateView($form2request, $presenter->viewModel()); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/RemoveFromBasketController.php ================================================ execute(new RemoveFromBasketRequest($user->getId(), $basketId), $presenter); return $view->generateView($request->request->get('redirect'), $presenter->viewModel()); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/ShowBasketController.php ================================================ execute(new ShowBasketRequest($user->getId()), $showBasketPresenter); return $showBasketView->generateView($showBasketPresenter->viewModel()); } $confirmBasket->execute($nullableRequest->withUserId($user->getId()), $presenter); return $view->generateView($presenter->viewModel()); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/ShowOrderMenuController.php ================================================ getId() : ''; $getMenu->execute($presenter); return $view->generateView($presenter->viewModel(), $userId); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Controller/UpdateClientController.php ================================================ execute(new GetClientRequest($user->getId()), $getClientPresenter); return $view->generateViewBeforePost($getClientPresenter->viewModel()); } $request = UpdateClientRequest::fromEditable($nullableRequest)->byClientId($user->getId()); $updateClient->execute($request, $updatePresenter); return $view->generateViewAfterPost($request, $updatePresenter->viewModel()); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/DependencyInjection/Compiler/AdminFilterRolePass.php ================================================ authorizationChecker = $authorizationChecker; $this->tokenStorage = $tokenStorage; } public function process(array $backendConfig) { $entities = []; $user = $this->tokenStorage->getToken()->getUser(); foreach ($backendConfig['entities'] as $class => $entity) { if (isset($entity['role']) && $this->authorizationChecker->isGranted($entity['role'], $user)) { $entities[$class] = $entity; } } $backendConfig['entities'] = $entities; return $backendConfig; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/DependencyInjection/Compiler/AutowireSeatPass.php ================================================ findTaggedServiceIds('seat.autowire'); foreach (array_keys($ids) as $className) { $rf = new ReflectionClass($className); foreach ($rf->getInterfaces() as $interface) { if (strpos($interface->getName(), 'Seat') === 0) { $container->autowire($interface->getName(), $className); } } } } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Basket.php ================================================ id; } public function setId($id) { $this->id = $id; } public function userId(): string { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; } public function content(): array { return $this->content; } public function setContent(array $content) { $this->content = $content; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/BasketProductJson.php ================================================ $basketProduct->id(), 'quantity' => $basketProduct->quantity(), 'comment' => $basketProduct->comment(), 'name' => $basketProduct->name(), 'price' => $basketProduct->price(), ]; if ($basketProduct->option()) { $json['option'] = [ 'name' => $basketProduct->option()->name(), 'price' => $basketProduct->option()->price(), ]; } if (count($basketProduct->supplements()) > 0) { $supplementToJson = function (BasketProductSupplement $supplement) { return [ 'name' => $supplement->name(), 'price' => $supplement->price(), ]; }; $json['supplements'] = array_map($supplementToJson, $basketProduct->supplements()); } return new BasketProductJson($json); } public function __construct(array $json) { $this->json = $json; } public function json() { return $this->json; } public function basketProduct(string $basketId) { $json = $this->json; $supplementsToObjects = function (array $supplement) { return new BasketProductSupplement($supplement['name'], $supplement['price']); }; return new BasketProduct( $basketId, $json['quantity'], $json['name'], $json['price'], isset($json['option']) ? new BasketProductOption($json['option']['name'], $json['option']['price']) : null, isset($json['supplements']) ? array_map($supplementsToObjects, $json['supplements']) : [], $json['comment'] ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Category.php ================================================ options = new ArrayCollection(); $this->supplements = new ArrayCollection(); } /** * @return mixed */ public function getId() { return $this->id; } /** * @param mixed $id */ public function setId($id) { $this->id = $id; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name * * @return Category */ public function setName($name) { $this->name = $name; return $this; } /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description */ public function setDescription($description) { $this->description = $description; } /** * @return string */ public function getOrder() { return $this->order; } /** * @param string $order */ public function setOrder($order) { $this->order = $order; } public function __toString() { return $this->name; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/CategoryOption.php ================================================ id; } /** * @param mixed $id */ public function setId($id) { $this->id = $id; } /** * @return Category */ public function getCategory() { return $this->category; } /** * @param Category $category */ public function setCategory($category) { $this->category = $category; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return int */ public function getPrice() { return $this->price; } /** * @param int $price */ public function setPrice($price) { $this->price = $price; } /** * @return string */ public function __toString() { return $this->name.' ('.($this->price).' €)'; } /** * @return int */ public function getOrder() { return $this->order; } /** * @param int $order */ public function setOrder($order) { $this->order = $order; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/CategorySupplement.php ================================================ id; } /** * @param mixed $id */ public function setId($id) { $this->id = $id; } /** * @return Category */ public function getCategory() { return $this->category; } /** * @param Category $category */ public function setCategory($category) { $this->category = $category; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return int */ public function getPrice() { return $this->price; } /** * @param int $price */ public function setPrice($price) { $this->price = $price; } /** * @return string */ public function __toString() { return $this->name.' ('.($this->price).' €)'; } /** * @return int */ public function getOrder() { return $this->order; } /** * @param int $order */ public function setOrder($order) { $this->order = $order; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Command.php ================================================ id; } public function setId($id) { $this->id = $id; } public function userId(): string { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; } public function content(): array { return $this->content; } public function setContent($content) { $this->content = $content; } public function date() { return $this->date; } public function setDate(\DateTimeImmutable $date) { $this->date = $date->setTimezone(new \DateTimeZone('Europe/Brussels')); } public function setOrderType(OrderType $orderType) { $this->orderType = ['name' => $orderType->name(), 'time' => $orderType->time()]; } public function getOrderTypeString() { $str = $this->orderType['name']; if (!empty($this->orderType['time'])) { $str .= ' ('.substr($this->orderType['time'], 0, -3).')'; } return $str; } public function getName() { return $this->content['name']; } public function getOption() { if (!empty($this->content['option'])) { return $this->content['option']['name']; } return '-'; } public function getSupplements() { $supplementNames = []; $supplements = $this->content['supplements'] ?? []; foreach ($supplements as $supplement) { $supplementNames[] = $supplement['name']; } $str = join(', ', $supplementNames); return !empty($str) ? $str : '-'; } public function getComment() { return !empty($this->content['comment']) ? $this->content['comment'] : '-'; } public function getQuantity() { return $this->content['quantity']; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Company.php ================================================ id; } /** * @param mixed $id */ public function setId($id) { $this->id = $id; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return string */ public function getVat() { return $this->vat; } /** * @param string $vat */ public function setVat($vat) { $this->vat = $vat; } public function getSlug() { return $this->slug; } public function setSlug($slug) { $this->slug = $slug; } /** * @return string */ public function getStreet() { return $this->street; } /** * @param string $street */ public function setStreet($street) { $this->street = $street; } /** * @return string */ public function getStreetNumber() { return $this->streetNumber; } /** * @param string $streetNumber */ public function setStreetNumber($streetNumber) { $this->streetNumber = $streetNumber; } /** * @return string */ public function getZipCode() { return $this->zipCode; } /** * @param string $zipCode */ public function setZipCode($zipCode) { $this->zipCode = $zipCode; } /** * @return string */ public function getCity() { return $this->city; } /** * @param string $city */ public function setCity($city) { $this->city = $city; } /** * @return string */ public function getPhoneNumber() { return $this->phoneNumber; } /** * @param string $phoneNumber */ public function setPhoneNumber($phoneNumber) { $this->phoneNumber = $phoneNumber; } /** * @return string */ public function getOrderDeliveryDeadLine() { return $this->orderDeliveryDeadLine; } /** * @param string $orderDeliveryDeadLine */ public function setOrderDeliveryDeadLine($orderDeliveryDeadLine) { $this->orderDeliveryDeadLine = $orderDeliveryDeadLine; } /** * @return boolean */ public function canBeDelivered() { return $this->canBeDelivered; } /** * @param boolean $canBeDelivered */ public function setCanBeDelivered($canBeDelivered) { $this->canBeDelivered = $canBeDelivered; } /** * @return string */ public function getTournee() { return $this->tournee; } /** * @param string $tournee */ public function setTournee($tournee) { $this->tournee = $tournee; } public function __toString() { return $this->name; } /** * @return boolean */ public function isEnabled() { return $this->isEnabled; } /** * @param boolean $isEnabled */ public function setIsEnabled($isEnabled) { $this->isEnabled = $isEnabled; } /** * @return string */ public function getComment() { return $this->comment; } /** * @param string $comment */ public function setComment($comment) { $this->comment = $comment; } /** * @return mixed */ public function getContactEmail() { return $this->contactEmail; } /** * @param mixed $contactEmail */ public function setContactEmail($contactEmail) { $this->contactEmail = $contactEmail; } public function setAdminCommandBefore(?\DateTimeInterface $date) { if ($date) { $this->orderDeliveryDeadLine = $date->format('H:i:s'); } else { $this->orderDeliveryDeadLine = null; } } public function getAdminCommandBefore() { if ($this->orderDeliveryDeadLine) { $time = \DateTimeImmutable::createFromFormat('H:i:s', $this->orderDeliveryDeadLine); if ($time !== false) { return $time; } } return null; } public function store(): string { return $this->store; } public function setStore($store) { $this->store = $store; } public function hasInvoice(): bool { return $this->hasInvoice; } public function setHasInvoice($hasInvoice) { $this->hasInvoice = $hasInvoice; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineBasketRepository.php ================================================ setId($basketProduct->id()); $basketEntity->setUserId($userId); $basketEntity->setContent(BasketProductJson::fromBasketProduct($basketProduct)->json()); $this->getEntityManager()->persist($basketEntity); $this->getEntityManager()->flush($basketEntity); } public function getUserBasket(string $userId): Basket { /** @var BasketEntity[] $basketProducts */ $basketProducts = $this->findBy(['userId' => $userId]); $convertToObject = function (BasketEntity $basket) { return (new BasketProductJson($basket->content()))->basketProduct($basket->id().''); }; $lines = array_map($convertToObject, $basketProducts); return new Basket($userId, $lines); } public function emptyBasketFor(string $userId): void { $this->createQueryBuilder('b') ->delete() ->where('b.userId = :userId') ->setParameter('userId', $userId) ->getQuery() ->getResult(); } public function delete(string $basketId, string $userId): void { $this->createQueryBuilder('b') ->delete() ->where('b.userId = :userId') ->andWhere('b.id = :basketId') ->setParameter('userId', $userId) ->setParameter('basketId', $basketId) ->getQuery() ->getResult(); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineCategoryRepository.php ================================================ findBy([], array('order' => 'ASC')); return array_map( function (CategoryEntity $category) { return new Category($category->getId().'', $category->getName(), $category->getDescription()); }, $categories ); } public function addCategory(Category $category) { throw new Error('Method "'.__METHOD__.'" to implement'); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineClientRepository.php ================================================ setId($client->id()); $user->setEmail($client->email()); $user->setFirstName($client->firstName()); $user->setLastName($client->lastName()); $user->setPhoneNumber($client->phoneNumber()); $user->setPassword($client->password()); $user->setStore($client->store()); $user->setRole($client->role()); $user->setIsEnabled($client->isEnabled()); if ($client->hasCompany()) { $companyForeign = $this->getEntityManager()->getReference(Company::class, $client->companyId()); $user->setCompany($companyForeign); } $this->getEntityManager()->persist($user); $this->getEntityManager()->flush($user); } public function getClientByEmail(string $email): ?Client { /** @var User $user */ $user = $this->findOneBy(['email' => $email]); if ($user === null) { return null; } $companyId = $user->getCompany() === null ? null : $this->getEntityManager()->getUnitOfWork()->getEntityIdentifier($user->getCompany())['id'].''; return new Client( $user->id(), $user->firstName(), $user->lastName(), $user->email(), $user->phoneNumber(), $user->password(), $user->store(), $user->role(), $user->isEnabled(), $companyId ); } public function getClientById(string $id): ?Client { /** @var User $user */ $user = $this->findOneBy(['id' => $id]); if ($user === null) { return null; } $companyId = $user->getCompany() === null ? null : $this->getEntityManager()->getUnitOfWork()->getEntityIdentifier($user->getCompany())['id'].''; return new Client( $user->id(), $user->firstName(), $user->lastName(), $user->email(), $user->phoneNumber(), $user->password(), $user->store(), $user->role(), $user->isEnabled(), $companyId ); } public function updateClient(Client $client): void { $user = $this->findOneBy(['id' => $client->id()]); $user->setEmail($client->email()); $user->setFirstName($client->firstName()); $user->setLastName($client->lastName()); $user->setPhoneNumber($client->phoneNumber()); $user->setPassword($client->password()); $this->getEntityManager()->persist($user); $this->getEntityManager()->flush($user); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineCommandRepository.php ================================================ basket() as $basketProduct) { $commandEntity = new CommandEntity(); $commandEntity->setId(Uuid::uuid4()->toString()); $commandEntity->setUserId($command->userId()); $commandEntity->setDate($command->date()); $commandEntity->setOrderType($command->orderType()); $commandEntity->setContent(BasketProductJson::fromBasketProduct($basketProduct)->json()); $this->getEntityManager()->persist($commandEntity); } $this->getEntityManager()->flush(); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineCompanyRepository.php ================================================ findOneBy(['name' => $companyName]); if ($company === null) { return null; } return new Company( $company->getId().'', $company->getName(), $company->hasInvoice(), $company->store(), $company->isEnabled(), $company->getOrderDeliveryDeadLine() ); } public function addCompany(Company $company): void { $companyEntity = new CompanyEntity(); $companyEntity->setId($company->id()); $companyEntity->setName($company->name()); $this->getEntityManager()->persist($companyEntity); $this->getEntityManager()->flush($companyEntity); } public function getCompanyById(?string $companyId): ?Company { /** @var CompanyEntity $company */ $company = $this->findOneBy(['id' => $companyId]); if ($company === null) { return null; } return new Company( $company->getId().'', $company->getName(), $company->hasInvoice(), $company->store(), $company->isEnabled(), $company->getOrderDeliveryDeadLine() ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineHtmlContentRepository.php ================================================ createQueryBuilder('p') ->where('p.name = :name') ->setParameter('name', $name) ->getQuery() ->getSingleResult(); return new HtmlContent($htmlContent->getName(), $htmlContent->getHtml()); } catch (Exception $e) { return new HtmlContent($name, ''); } } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineProductOptionRepository.php ================================================ find($productOptionId); if ($option === null) { return null; } return new ProductOption( $option->getId().'', $option->getCategory()->getId().'', $option->getName(), $option->getPrice() ); } public function add(ProductOption $productOption): void { throw new Error('Method "'.__METHOD__.'" to implement'); } /** * @return ProductOption[] */ public function getByCategoryId(string $categoryId): array { /** @var CategoryOption $option */ $options = $this->findBy(['category' => $categoryId], array('order' => 'ASC')); return array_map( function (CategoryOption $option) { return new ProductOption( $option->getId().'', $option->getCategory()->getId().'', $option->getName(), $option->getPrice() ); }, $options ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineProductRepository.php ================================================ find($id); if ($productEntity === null) { return null; } return new Product( $productEntity->getId().'', $productEntity->getCategory()->getId().'', $productEntity->getName(), $productEntity->getDescription().'', $productEntity->getPrice() ); } /** * @return Product[] */ public function getByCategoryId(string $categoryId): array { /** @var ProductEntity[] $products */ $products = $this->findBy(['category' => $categoryId]); return array_map( function (ProductEntity $product) { return new Product( $product->getId().'', $product->getCategory()->getId().'', $product->getName(), $product->getDescription().'', $product->getPrice() ); }, $products ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/DoctrineProductSupplementRepository.php ================================================ find($supplementId); if ($supplement === null) { return null; } return new ProductSupplement( $supplement->getId().'', $supplement->getCategory()->getId().'', $supplement->getName(), $supplement->getPrice() ); } public function add(ProductSupplement $supplement): void { throw new Error('Method "'.__METHOD__.'" to implement'); } /** * @return ProductSupplement[] */ public function getByCategoryId(string $categoryId): array { /** @var CategorySupplement $option */ $supplements = $this->findBy(['category' => $categoryId], array('order' => 'ASC')); return array_map( function (CategorySupplement $supplement) { return new ProductSupplement( $supplement->getId().'', $supplement->getCategory()->getId().'', $supplement->getName(), $supplement->getPrice() ); }, $supplements ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/HtmlContent.php ================================================ name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } /** * @return string */ public function getHtml() { return $this->html; } /** * @param string $html */ public function setHtml($html) { $this->html = $html; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Pdf.php ================================================ id; } public function setId($id) { $this->id = $id; } public function text() { return $this->text; } public function setText($text) { $this->text = $text; } public function pdf(): ?string { return $this->pdf; } public function setPdf($pdf) { $this->pdf = $pdf; } public function pdfFile(): ?File { return $this->pdfFile; } public function setPdfFile($pdfFile) { $this->pdfFile = $pdfFile; if($this->pdfFile){ $this->setPdf($this->pdfFile->getFilename()); } } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Product.php ================================================ name; } /** * @return mixed */ public function getId() { return $this->id; } /** * @param mixed $id * * @return $this */ public function setId($id) { $this->id = $id; return $this; } /** * @return Category */ public function getCategory() { return $this->category; } /** * @param Category $category * * @return $this */ public function setCategory($category) { $this->category = $category; return $this; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name * * @return $this */ public function setName($name) { $this->name = $name; return $this; } /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description * * @return $this */ public function setDescription($description) { $this->description = $description; return $this; } /** * @return int */ public function getPrice() { return $this->price; } /** * @param int $price * * @return $this */ public function setPrice($price) { $this->price = $price; return $this; } /** * @return int */ public function getOrder() { return $this->order; } /** * @param int $order * * @return $this */ public function setOrder($order) { $this->order = $order; return $this; } /** * @return boolean */ public function isEnabled() { return $this->isEnabled; } /** * @param boolean $isEnabled * * @return $this */ public function setIsEnabled($isEnabled) { $this->isEnabled = $isEnabled; return $this; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/Tournee.php ================================================ name; } /** * @return mixed */ public function getId() { return $this->id; } /** * @param mixed $id */ public function setId($id) { $this->id = $id; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name) { $this->name = $name; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Doctrine/User.php ================================================ id; } public function setId($id) { $this->id = $id; } public function getCompany() { return $this->company; } public function setCompany($company) { $this->company = $company; } public function firstName(): ?string { return $this->firstName; } public function setFirstName($firstName) { $this->firstName = $firstName; } public function lastName(): ?string { return $this->lastName; } public function setLastName($lastName) { $this->lastName = $lastName; } public function phoneNumber(): ?string { return $this->phoneNumber; } public function setPhoneNumber($phoneNumber) { $this->phoneNumber = $phoneNumber; } public function password(): string { return $this->password; } public function setPassword($password) { $this->password = $password; } public function email(): ?string { return $this->email; } public function setEmail($email) { $this->email = $email; } public function store(): string { return $this->store; } public function setStore($store) { $this->store = $store; } public function role(): string { return $this->role; } public function setRole($role) { $this->role = $role; } public function isEnabled() { return $this->isEnabled; } public function setIsEnabled($isEnabled) { $this->isEnabled = $isEnabled; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Form/BasketConfirmationType.php ================================================ orderTypeChecker = $orderTypeChecker; $this->userId = is_string($tokenStorage->getToken()->getUser()) ? '' : $tokenStorage->getToken()->getUser()->getId(); } public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('checkSum', HiddenType::class); try { $possibleOrderType = $this->orderTypeChecker->getPossibleOrderType($this->userId); $builder->add('orderTypeName', HiddenType::class, ['data' => $possibleOrderType->name()]); $this->buildForOrderType($builder, $possibleOrderType); } catch (\Exception $e) { //Can explode when the user is unknown } } private function buildForOrderType(FormBuilderInterface $builder, PossibleOrderType $possibleOrderType): void { if ($possibleOrderType->name() == OrderTypeName::$takeAway) { $roundedSteps = array_reduce( $possibleOrderType->range()->getRoundedStep(15), function ($list, $time) { $list[substr($time, 0, 5)] = $time; return $list; }, [] ); $builder->add('takeAwayTime', ChoiceType::class, ['choices' => $roundedSteps]); } } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults( [ 'data_class' => ConfirmBasketRequest::class, 'userId' => '', 'csrf_protection' => false, 'possibleOrderType' => null, ] ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Form/BasketType.php ================================================ add('productId') ->add('optionId', TextType::class) ->add('comment') ->add( 'supplementIds', CollectionType::class, [ 'entry_type' => TextType::class, 'empty_data' => [], 'by_reference' => false, 'allow_add' => true, ] ) ->add('quantity', IntegerType::class); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults( [ 'data_class' => AddProductToBasketRequest::class, 'csrf_protection' => false, ] ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Form/FormHelper.php ================================================ formFactory = $formFactory; } public function getFormData(Request $request, string $typeClass, $options = []) { $formBuilder = $this->formFactory->createBuilder($typeClass, null, $options); $form = $formBuilder->getForm(); $form->handleRequest($request); return $form->getData(); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Form/RegisterType.php ================================================ add('isPosted', HiddenType::class, ['data' => true]) ->add('companyName') ->add('firstName', null, ['required' => true]) ->add('lastName', null, ['required' => true]) ->add('email', null, ['required' => true]) ->add('phoneNumber', null, ['required' => true]) ->add('password', PasswordType::class) ->add( 'store', ChoiceType::class, [ 'required' => true, 'choices' => [ 'La hulpe' => Store::$laHulpe, 'Waterloo' => Store::$waterloo, ], ] ); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults( [ 'data_class' => RegisterRequest::class, ] ); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Form/UpdateClientType.php ================================================ add('firstName') ->add('lastName') ->add('email') ->add('phoneNumber') ->add('password', PasswordType::class, ['required' => false]); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(['data_class' => EditableClient::class]); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Kernel.php ================================================ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony4; use Symfony4\DependencyInjection\Compiler\AutowireSeatPass; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\RouteCollectionBuilder; class Kernel extends BaseKernel { use MicroKernelTrait; const CONFIG_EXTS = '.{php,xml,yaml,yml}'; public function getCacheDir() { return $this->getProjectDir().'/var/cache/'.$this->environment; } public function getLogDir() { return $this->getProjectDir().'/var/log'; } public function registerBundles() { $contents = require $this->getProjectDir().'/config/bundles.php'; foreach ($contents as $class => $envs) { if ($envs[$this->environment] ?? $envs['all'] ?? false) { yield new $class(); } } } protected function build(ContainerBuilder $container) { $container->addCompilerPass(new AutowireSeatPass()); } protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); $container->setParameter('container.dumper.inline_class_loader', true); $confDir = $this->getProjectDir().'/config'; $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); } protected function configureRoutes(RouteCollectionBuilder $routes) { $confDir = $this->getProjectDir().'/config'; $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/ParamConverter/FormToNullableRequestConverter.php ================================================ formHelper = $formHelper; } /** * Stores the object in the request. * * @param ParamConverter $configuration Contains the name, class and options of the object * * @return bool True if the object has been successfully set, else false */ public function apply(Request $request, ParamConverter $configuration) { $specificRequest = $this->formHelper->getFormData($request, $configuration->getOptions()['form']); $request->attributes->set($configuration->getName(), $specificRequest); return true; } /** * Checks if the object is supported. * * @return bool True if the object is supported, else false */ public function supports(ParamConverter $configuration) { return !empty($configuration->getOptions()['form']) && $configuration->getName() === 'nullableRequest'; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/ParamConverter/FormToRequestConverter.php ================================================ formHelper = $formHelper; } /** * Stores the object in the request. * * @param ParamConverter $configuration Contains the name, class and options of the object * * @return bool True if the object has been successfully set, else false */ public function apply(Request $request, ParamConverter $configuration) { $specificRequest = $this->formHelper->getFormData($request, $configuration->getOptions()['form']); if ($specificRequest === null) { return false; } $request->attributes->set($configuration->getName(), $specificRequest); return true; } /** * Checks if the object is supported. * * @return bool True if the object is supported, else false */ public function supports(ParamConverter $configuration) { return !empty($configuration->getOptions()['form']) && $configuration->getName() === 'form2request'; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Security/Service/ClientUserProvider.php ================================================ clientRepository = $clientRepository; } /** * Loads the user for the given username. * * This method must throw UsernameNotFoundException if the user is not * found. * * @param string $username The username * * @return UserInterface * * @throws UsernameNotFoundException if the user is not found */ public function loadUserByUsername($username) { $client = $this->clientRepository->getClientByEmail($username); if ($client === null || !$client->isEnabled()) { throw new UsernameNotFoundException(); } return new User($client); } public function refreshUser(UserInterface $user) { $client = $this->clientRepository->getClientByEmail($user->getUsername()); if ($client === null || !$client->isEnabled()) { throw new UsernameNotFoundException(); } return $user; } /** * Whether this provider supports the given user class. * * @param string $class * * @return bool */ public function supportsClass($class) { return User::class === $class; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Security/Service/FormAuthenticator.php ================================================ router = $router; $this->passwordHasher = $passwordHasher; $this->login = $login; } /** * {@inheritdoc} */ public function getCredentials(Request $request) { return [ 'email' => $this->getEmail($request), 'password' => $request->request->get('password', ''), ]; } /** * {@inheritdoc} */ public function getUser($credentials, UserProviderInterface $userProvider) { $this->login->execute(new LoginRequest($credentials['email'], $credentials['password']), $this); if ($this->response->notification()->hasError()) { throw new CustomUserMessageAuthenticationException( $this->response->notification()->getErrors()[0]->message() ); } return new User($this->response->client()); } /** * {@inheritdoc} */ public function checkCredentials($credentials, UserInterface $user) { //All the checks are done in getUser return true; } /** * {@inheritdoc} */ public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { return new RedirectResponse($this->router->generate('home')); } /** * {@inheritdoc} */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); $request->getSession()->set(Security::LAST_USERNAME, $this->getEmail($request)); $url = $this->router->generate('login'); return new RedirectResponse($url); } /** * {@inheritdoc} */ public function start(Request $request, AuthenticationException $authException = null) { return new RedirectResponse($this->router->generate('login')); } /** * {@inheritdoc} */ public function supportsRememberMe() { return true; } private function getEmail(Request $request): string { return $request->request->get('email', ''); } /** * Does the authenticator support the given Request? * * If this returns false, the authenticator will be skipped. * * @param Request $request * * @return bool */ public function supports(Request $request) { return $request->getPathInfo() === '/login-check' && $request->isMethod('POST'); } public function present(LoginResponse $response) { $this->response = $response; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Security/User.php ================================================ client = $client; } /** * Returns the roles granted to the user. * * public function getRoles() * { * return ['ROLE_USER']; * } * * Alternatively, the roles might be stored on a ``roles`` property, * and populated in any number of different ways when the user object * is created. * * @return (Role|string)[] The user roles * @throws \Exception */ public function getRoles() { switch ($this->client->role()) { case Role::$client: return ['ROLE_CLIENT']; case Role::$sandwich: return ['ROLE_SANDWICH']; case Role::$admin: return ['ROLE_ADMIN']; } throw new \Exception('No role for client '.$this->client->id()); } /** * Returns the password used to authenticate the user. * * This should be the encoded password. On authentication, a plain-text * password will be salted, encoded, and then compared to this value. * * @return string The password */ public function getPassword() { return $this->client->password(); } /** * Returns the salt that was originally used to encode the password. * * This can return null if the password was not encoded using a salt. * * @return string|null The salt */ public function getSalt() { return ''; } /** * Returns the username used to authenticate the user. * * @return string The username */ public function getUsername() { return $this->client->email(); } /** * Removes sensitive data from the user. * * This is important if, at any given point, sensitive information like * the plain-text password is stored on this object. */ public function eraseCredentials() { } public function getId() { return $this->client->id(); } public function fullName() { return $this->client->firstName().' '.$this->client->lastName(); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Twig/ContentExtension.php ================================================ entityManager = $entityManager; $this->logger = $logger; } /** * @return array */ public function getFilters() { return [ new \Twig_SimpleFilter('content', [$this, 'getContent'], ['is_safe' => ['html']]), ]; } /** * @param string $slug * * @return string */ public function getContent($slug) { try { $htmlContent = $this->entityManager->getRepository('App:HtmlContent')->findOneBy( [ 'name' => $slug, ] ); if ($htmlContent === null) { $this->logger->error(sprintf('No content for "%s"', $slug)); return ''; } return $htmlContent->getHtml(); } catch (\Exception $ex) { $this->logger->error(sprintf('Exception "%s" content for "%s"', $ex->getMessage(), $slug)); return ''; } } /** * @return string */ public function getName() { return 'content_extension'; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/Twig/DownloadExtension.php ================================================ entityManager = $entityManager; $this->twig = $twig; $this->logger = $logger; } /** * @return array */ public function getFilters() { return [ new \Twig_SimpleFilter('download', [$this, 'getDownload'], ['is_safe' => ['html']]), ]; } public function getDownload($slug) { try { $pdf = $this->entityManager->getRepository('App:Pdf')->find($slug); if ($pdf === null) { $this->logger->error(sprintf('No pdf for "%s"', $slug)); return ''; } return $this->twig->render('component/download.html.twig', ['pdf' => $pdf]); } catch (\Exception $ex) { $this->logger->error(sprintf('Exception "%s" content for "%s"', $ex->getMessage(), $slug), ['error' => $ex]); return ''; } } /** * @return string */ public function getName() { return 'download_extension'; } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/AddProductToBasketView.php ================================================ router = $router; $this->session = $session; } public function generateView(AddProductToBasketHtmlViewModel $viewModel) { foreach ($viewModel->notifications as $notification) { $this->session->getFlashBag()->add($notification['type'], $notification['message']); } return new RedirectResponse($this->router->generate('menu.show')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/ConfirmBasketView.php ================================================ twig = $twig; $this->session = $session; $this->router = $router; } /** @throws */ public function generateView(ConfirmBasketHtmlViewModel $viewModel) { if (empty($viewModel->errors)) { return new Response($this->twig->render('page/order-done.html.twig')); } foreach ($viewModel->errors as $error) { $this->session->getFlashBag()->add('error', $error); } return new RedirectResponse($this->router->generate('basket')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/GetMenuView.php ================================================ twig = $twig; $this->formFactory = $formFactory; $this->basketRepository = $basketRepository; $this->orderTypeChecker = $orderTypeChecker; } /** @throws */ public function generateView(GetMenuHtmlViewModel $viewModel, string $userId) { $html = $this->twig->render( 'page/take-away.html.twig', [ 'newForm' => $this->formFactory->createBuilder(BasketType::class)->getForm()->createView(), 'showBasketMobileMenu' => true, 'basket' => BasketViewModel::fromBasket($this->basketRepository->getUserBasket($userId)), 'menu' => $viewModel->menu, 'orderType' => $userId ? $this->orderTypeChecker->getPossibleOrderType($userId) : null, ] ); return new Response($html); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/RegisterView.php ================================================ twig = $twig; $this->formFactory = $formFactory; $this->router = $router; } /** * @throws */ public function generateView(RegisterRequest $registerRequest, RegisterHtmlViewModel $viewModel): Response { if ($viewModel->clientSaved) { return new RedirectResponse($this->router->generate('register-complete')); } $form = $this->formFactory->createBuilder(RegisterType::class, $registerRequest)->getForm(); return new Response($this->twig->render('page/register.html.twig', ['form' => $form->createView(), 'viewModel' => $viewModel])); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/RemoveFromBasketView.php ================================================ router = $router; } public function generateView(?string $redirect, RemoveFromBasketHtmlViewModel $viewModel) { return new RedirectResponse($redirect ?? $this->router->generate('menu.show')); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/ShowBasketView.php ================================================ twig = $twig; $this->formFactory = $formFactory; $this->userId = is_string($tokenStorage->getToken()->getUser()) ? '' : $tokenStorage->getToken()->getUser()->getId(); $this->tokenStorage = $tokenStorage; $this->router = $router; } public function generateView(ShowBasketHtmlViewModel $viewModel) { if ($viewModel->mustRedirectToMenu) { return new RedirectResponse($this->router->generate('menu.show')); } $confirmBasketRequest = (new ConfirmBasketRequest())->withCheckSum($viewModel->basket->checkSum); $form = $this->formFactory ->createBuilder(BasketConfirmationType::class, $confirmBasketRequest, ['userId' => $this->userId]) ->getForm()->createView(); return new Response($this->twig->render('page/basket.html.twig', ['form' => $form, 'basket' => $viewModel->basket])); } } ================================================ FILE: src/Seat/Infrastructure/Symfony4/View/UpdateClientView.php ================================================ twig = $twig; $this->formFactory = $formFactory; $this->router = $router; $this->session = $session; } public function generateViewAfterPost(UpdateClientRequest $request, UpdateClientHtmlViewModel $viewModel) { if ($viewModel->notificationMessage && $viewModel->notificationType) { $this->session->getFlashBag()->add($viewModel->notificationType, $viewModel->notificationMessage); } if ($viewModel->redirectToLogout) { return new RedirectResponse($this->router->generate('logout')); } if ($viewModel->redirectToThankYouPage) { return new RedirectResponse($this->router->generate('user.my-info')); } return $this->generateView($request, $viewModel->errors); } public function generateViewBeforePost(GetClientHtmlViewModel $viewModel) { return $this->generateView($viewModel->editableClient()); } private function generateForm(EditableClient $editableClient): FormInterface { return $this->formFactory->createBuilder(UpdateClientType::class, $editableClient)->getForm(); } /** @throws */ private function generateView(EditableClient $editableClient, $errors = []): Response { return new Response( $this->twig->render( 'page/update-client.html.twig', [ 'form' => $this->generateForm($editableClient)->createView(), 'errors' => $errors, ] ) ); } } ================================================ FILE: src/Seat/Presentation/Basket/AddProductToBasketHtmlPresenter.php ================================================ viewModel = new AddProductToBasketHtmlViewModel(); foreach ($response->notification()->getErrors() as $error) { $this->viewModel->addNotification('error', $error->message()); } } public function viewModel(): AddProductToBasketHtmlViewModel { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Basket/AddProductToBasketHtmlViewModel.php ================================================ notifications[] = ['type' => $type, 'message' => $message]; } } ================================================ FILE: src/Seat/Presentation/Basket/Model/BasketViewModel.php ================================================ totalPrice = $totalPrice; $this->checkSum = $checkSum; $this->products = $products; } public static function fromBasket(Basket $basket) { $lines = []; /** @var BasketProduct $basketProduct */ foreach ($basket as $basketProduct) { $lines[] = [ 'id' => $basketProduct->id(), 'quantity' => $basketProduct->quantity(), 'name' => $basketProduct->name(), 'totalPrice' => $basketProduct->totalPrice(), 'option' => $basketProduct->option() ? $basketProduct->option()->name() : null, 'comment' => $basketProduct->comment(), 'supplements' => array_map( function (BasketProductSupplement $supplement) { return $supplement->name(); }, $basketProduct->supplements() ), ]; } return new BasketViewModel( $basket->totalPrice(), $basket->checkSum(), $lines ); } public function count() { return count($this->products); } public function totalPrice() { return $this->totalPrice; } } ================================================ FILE: src/Seat/Presentation/Basket/RemoveFromBasketHtmlPresenter.php ================================================ viewModel = new RemoveFromBasketHtmlViewModel(); } public function viewModel(): RemoveFromBasketHtmlViewModel { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Basket/RemoveFromBasketHtmlViewModel.php ================================================ viewModel = new ShowBasketHtmlViewModel(); if ($response->basket()->isEmpty()) { $this->viewModel->mustRedirectToMenu = true; } else { $this->viewModel->basket = BasketViewModel::fromBasket($response->basket()); } } public function viewModel(): ShowBasketHtmlViewModel { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Basket/ShowBasketHtmlViewModel.php ================================================ viewModel = new GetClientHtmlViewModel(); $this->viewModel->makeEditableClient( $response->client()->firstName(), $response->client()->lastName(), $response->client()->email(), $response->client()->phoneNumber() ); } public function viewModel() { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Client/GetClientHtmlViewModel.php ================================================ editableClient; } public function makeEditableClient(string $firstName, string $lastName, string $email, string $phoneNumber) { $this->editableClient = new EditableClient(); $this->editableClient->firstName = $firstName; $this->editableClient->lastName = $lastName; $this->editableClient->email = $email; $this->editableClient->phoneNumber = $phoneNumber; } } ================================================ FILE: src/Seat/Presentation/Client/RegisterHtmlPresenter.php ================================================ viewModel = new RegisterHtmlViewModel(); $this->viewModel->clientSaved = $response->client() !== null; foreach ($response->notification()->getErrors() as $error) { $this->viewModel->errors[$error->fieldName()] = $error->message(); } } public function viewModel() { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Client/RegisterHtmlViewModel.php ================================================ viewModel = new UpdateClientHtmlViewModel(); } public function present(UpdateClientResponse $response) { $this->viewModel = new UpdateClientHtmlViewModel(); if ($response->updatedClient() !== null) { $this->viewModel->redirectToThankYouPage = true; $this->viewModel->displayNotification('success', 'my-info-updated'); $this->viewModel->redirectToLogout = $response->hasPasswordChanged(); if ($this->viewModel->redirectToLogout) { $this->viewModel->displayNotification('warning', 'new-password-login-needed'); } } foreach ($response->notification()->getErrors() as $error) { $this->viewModel->errors[$error->fieldName()] = $error->message(); } } public function viewModel() { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Client/UpdateClientHtmlViewModel.php ================================================ notificationType = $type; $this->notificationMessage = $message; } } ================================================ FILE: src/Seat/Presentation/Menu/GetMenuHtmlPresenter.php ================================================ viewModel = new GetMenuHtmlViewModel(); $this->viewModel->menu = MenuViewModel::fromMenuLines($response->menuLines); } public function viewModel(): GetMenuHtmlViewModel { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Menu/GetMenuHtmlViewModel.php ================================================ name()] = [ 'description' => $menuLine->description(), 'products' => array_map( function (MenuProduct $product) { return [ 'value' => $product->id(), 'name' => $product->name(), 'description' => $product->description(), 'price' => $product->price(), ]; }, $menuLine->products() ), 'options' => array_map( function (MenuOption $option) { return [ 'value' => $option->id(), 'text' => $option->name().' ('.$option->price().' €)', ]; }, $menuLine->options() ), 'supplements' => array_map( function (MenuSupplement $supplement) { return [ 'value' => $supplement->id(), 'text' => $supplement->name().' ('.$supplement->price().' €)', ]; }, $menuLine->supplements() ), ]; } return new MenuViewModel($categories); } public function __construct(array $categories) { $this->categories = $categories; } public function categories(): array { return $this->categories; } public function json() { return json_encode($this->categories); } } ================================================ FILE: src/Seat/Presentation/Order/ConfirmBasketHtmlPresenter.php ================================================ viewModel = new ConfirmBasketHtmlViewModel(); if ($response->notification()->hasError()) { foreach ($response->notification()->getErrors() as $error) { $this->viewModel->errors[] = $error->message(); } } } public function viewModel(): ConfirmBasketHtmlViewModel { return $this->viewModel; } } ================================================ FILE: src/Seat/Presentation/Order/ConfirmBasketHtmlViewModel.php ================================================ fieldName = $fieldName; $this->message = $message; } public function __toString() { return $this->fieldName.':'.$this->message; } public function fieldName(): string { return $this->fieldName; } public function message(): string { return $this->message; } } ================================================ FILE: src/Seat/SharedKernel/Error/Notification.php ================================================ errors[] = new Error($fieldName, $error); return $this; } /** * @return Error[] */ public function getErrors(): array { return $this->errors; } public function hasError() { return count($this->errors) > 0; } } ================================================ FILE: src/Seat/SharedKernel/Model/TimeRange.php ================================================ from = $from; $this->to = $to; } public function getRoundedStep(int $minuteStep) { $interval = DateInterval::createFromDateString($minuteStep.' minutes'); $current = DateTimeImmutable::createFromFormat('H:i:s', $this->from); $steps = []; do { $steps[] = $current->format('H:i:s'); $current = $current->add($interval); } while ($current->format('H:i:s') <= $this->to); return $steps; } public function delayFromDate(DateTimeImmutable $delay, ?int $minuteStep = null) { $newFrom = $delay->format('H:i:s'); if ($newFrom < $this->from) { return $this; } if ($minuteStep === null) { return new TimeRange($newFrom, $this->to); } $diffWithNextGoodMinute = $delay->getTimestamp() % ($minuteStep * 60); $newFromTimeStamp = ($diffWithNextGoodMinute === 0) ? $delay->getTimestamp() : $delay->getTimestamp() - $diffWithNextGoodMinute + ($minuteStep * 60); $newFrom = (new DateTimeImmutable())->setTimestamp($newFromTimeStamp); return new TimeRange($newFrom->format('H:i:s'), $this->to); } public function from(): string { return $this->from; } public function to(): string { return $this->to; } } ================================================ FILE: src/Seat/SharedKernel/Service/Base64PasswordHasher.php ================================================ toString(); } } ================================================ FILE: src/Seat/SharedKernel/Service/NativePasswordHasher.php ================================================ id = $id; return $this; } public function name(string $name) { $this->name = $name; return $this; } public function description(string $description) { $this->description = $description; return $this; } public function price(float $price) { $this->price = $price; return $this; } public function categoryId(string $categoryId) { $this->categoryId = $categoryId; return $this; } public function build() { return new Product($this->id, $this->categoryId, $this->name, $this->description, $this->price); } } ================================================ FILE: tests/unit/Seat/Domain/Basket/Service/OrderTypeCheckerTest.php ================================================ companyRepository = new InMemoryCompanyRepository(); $this->clientRepository = new InMemoryClientRepository(); $this->clock = $this->createMock(Clock::class); $this->checker = new OrderTypeChecker($this->companyRepository, $this->clientRepository, $this->clock); $this->company = CompanyBuilder::aCompany()->deliverable('10:00:00')->build(); $this->companyWithoutDelivery = CompanyBuilder::aCompany()->build(); $this->companyRepository->addCompany($this->company); $this->companyRepository->addCompany($this->companyWithoutDelivery); } private function nowIs(string $hourMinuteSecond) { $this->clock->method('now')->willReturn( DateTimeImmutable::createFromFormat('H:i:s', $hourMinuteSecond, new \DateTimeZone('Europe/Brussels')) ); return ''; } public function test_order_delivery_must_be_before_the_company_max_order_time() { $this->nowIs('09:59:59'); $this->assertNull( $this->checker->checkPossibleOrderType(OrderType::delivery(), $this->company->id()) ); } public function test_take_away_must_be_ordered_before_11h10() { $this->nowIs('11:10:00'); $this->assertNull( $this->checker->checkPossibleOrderType(OrderType::takeAwayFor('00:00:00'), null) ); } public function test_take_away_is_possible_until_14h() { $this->nowIs('11:10:00'); $this->assertNull( $this->checker->checkPossibleOrderType(OrderType::takeAwayFor('14:00:00'), null) ); } /** * @expectedException \Seat\Domain\Basket\Service\Error\DeliveryNotAvailable */ public function test_a_user_without_a_company_can_not_choose_delivery() { $this->nowIs('09:00:00'); $this->checker->checkPossibleOrderType(OrderType::delivery(), null); } /** * @expectedException \Seat\Domain\Basket\Service\Error\DeliveryNotAvailable */ public function test_impossible_to_delivery_on_a_company_that_does_not_accept_delivery() { $this->nowIs('09:00:00'); $this->checker->checkPossibleOrderType(OrderType::delivery(), $this->companyWithoutDelivery->id()); } /** * @expectedException \Seat\Domain\Basket\Service\Error\OrderTooLate */ public function test_take_away_can_not_be_ordered_after_11h10() { $this->nowIs('11:10:01'); $this->checker->checkPossibleOrderType(OrderType::takeAwayFor('00:00:00'), null); } /** * @expectedException \Seat\Domain\Basket\Service\Error\OrderTooLate */ public function test_impossible_to_order_a_delivery_after_the_company_max_order_time() { $this->nowIs('10:00:01'); $this->checker->checkPossibleOrderType(OrderType::delivery(), $this->company->id()); } /** * @expectedException \Seat\Domain\Basket\Service\Error\TakeAwayTooLate */ public function test_impossible_to_order_a_take_away_for_14h() { $this->nowIs('10:00:01'); $this->checker->checkPossibleOrderType(OrderType::takeAwayFor('14:00:01'), $this->companyWithoutDelivery->id()); } /** * @expectedException \Seat\Domain\Basket\Service\Error\TakeAwayNotAvailable */ public function test_a_daliverable_company_can_not_take_out() { $this->nowIs('10:00:00'); $this->checker->checkPossibleOrderType(OrderType::takeAwayFor('12:00:00'), $this->company->id()); } /** * @expectedException \Exception * @expectedExceptionMessage Unknown client */ public function test_an_unknown_client_has_no_delivery() { $this->nowIs('10:00:00'); $this->assertNull($this->checker->getPossibleOrderType('unknown-client')); } } ================================================ FILE: tests/unit/Seat/Domain/Basket/UseCase/AddProductToBasket/AddProductToBasketTest.php ================================================ product1 = ProductBuilder::aProduct()->build(); $this->product2 = ProductBuilder::aProduct()->categoryId('category-2')->id('product-2')->name('product2')->price(1)->build(); $this->userId = 'user-id'; $this->productOption1 = new ProductOption('option-1', $this->product1->categoryId(), 'Option 1', 0.5); $this->productOption2 = new ProductOption('option-2', $this->product2->categoryId(), 'Option 2', 1.5); $this->productSupplement1a = new ProductSupplement('sup-1a', $this->product1->categoryId(), 'Supp 1a', 0.26); $this->productSupplement2a = new ProductSupplement('sup-2a', $this->product2->categoryId(), 'Supp 2a', 0.52); $this->productRepository = new InMemoryProductRepository(); $this->basketRepository = new InMemoryBasketRepository(); $this->productOptionRepository = new InMemoryProductOptionRepository(); $this->productSupplementRepository = new InMemoryProductSupplementRepository(); $this->productRepository->add($this->product1); $this->productRepository->add($this->product2); $this->productOptionRepository->add($this->productOption1); $this->productOptionRepository->add($this->productOption2); $this->productSupplementRepository->add($this->productSupplement1a); $this->productSupplementRepository->add($this->productSupplement2a); $this->addToBasket = new AddProductToBasket( $this->basketRepository, $this->productRepository, $this->productOptionRepository, $this->productSupplementRepository ); } public function present(AddProductToBasketResponse $response): void { $this->response = $response; } public function test_it_adds_a_product_in_the_basket() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id()), $this); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(1, $basket); $this->assertSame($this->product1->name(), $basket[0]->name()); $this->assertSame($this->product1->price(), $basket[0]->price()); } public function test_it_calculate_the_total_price() { $firstBasketPrice = 1.2; $this->basketRepository->addToBasket($this->userId, new BasketProduct('basket-1', 1, 'first product', $firstBasketPrice, null, [], '')); $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id()), $this); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(2, $basket); $this->assertSame($firstBasketPrice + $this->product1->price(), $basket->totalPrice()); } public function test_impossible_to_add_a_non_existing_product() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, 'unknown product id'), $this); $this->assertEquals( (new Notification())->addError('productId', 'unknown-product'), $this->response->notification() ); $this->assertNull($this->response->basketProduct()); } public function test_can_add_a_product_with_an_option_to_the_basket() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), $this->productOption1->id()), $this); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(1, $basket); $this->assertSame($this->product1->price() + $this->productOption1->price(), $basket->totalPrice()); } public function test_throws_a_error_when_the_option_does_not_exist() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), 'unknown option id'), $this); $this->assertEquals( (new Notification())->addError('optionId', 'unknown-option'), $this->response->notification() ); $this->assertNull($this->response->basketProduct()); } public function test_throws_a_error_when_the_option_is_not_linked_to_the_category_of_the_product() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), $this->productOption2->id()), $this); $this->assertEquals( (new Notification())->addError('optionId', 'unknown-option'), $this->response->notification() ); } public function test_can_add_supplements_on_product() { $this->addToBasket->execute( AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), null, [$this->productSupplement1a->id()]), $this ); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(1, $basket); $this->assertSame($this->product1->price() + $this->productSupplement1a->price(), $basket->totalPrice()); } public function test_throws_an_error_when_a_supplement_is_unknown() { $this->addToBasket->execute(AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), null, ['unknown supplement']), $this); $this->assertEquals( (new Notification())->addError('supplementIds', 'unknown-supplement'), $this->response->notification() ); $this->assertNull($this->response->basketProduct()); } public function test_throws_an_error_when_a_supplement_is_not_linked_to_the_category_of_the_product() { $this->addToBasket->execute( AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), null, [$this->productSupplement2a->id()]), $this ); $this->assertEquals( (new Notification())->addError('supplementIds', 'unknown-supplement'), $this->response->notification() ); $this->assertNull($this->response->basketProduct()); } public function test_it_is_possible_to_add_a_comment() { $this->addToBasket->execute( AddProductToBasketRequest::fromAll(1, $this->userId, $this->product1->id(), null, [], 'This is a comment'), $this ); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(1, $basket); $this->assertSame('This is a comment', $basket[0]->comment()); } public function test_it_is_possible_to_add_a_quantity() { $quantity = 3; $this->addToBasket->execute( AddProductToBasketRequest::fromAll( $quantity, $this->userId, $this->product1->id(), $this->productOption1->id(), [$this->productSupplement1a->id()], 'No comment' ), $this ); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertCount(1, $basket); $this->assertSame(11.88, $basket->totalPrice()); } } ================================================ FILE: tests/unit/Seat/Domain/Basket/UseCase/RemoveFromBasket/RemoveFromBasketTest.php ================================================ basketRepository = new InMemoryBasketRepository(); $this->basketRepository->addToBasket($this->userId, new BasketProduct('basket-id', 1, ',', 2, null, [], '')); $removeFromBasket = new RemoveFromBasket($this->basketRepository); $removeFromBasket->execute(new RemoveFromBasketRequest($this->userId, 'basket-id'), $this); $basket = $this->basketRepository->getUserBasket($this->userId); $this->assertTrue($basket->isEmpty()); $this->assertTrue($this->response->isDone()); } public function present(RemoveFromBasketResponse $response): void { $this->response = $response; } } ================================================ FILE: tests/unit/Seat/Domain/Client/Entity/ClientBuilder.php ================================================ firstName = $firstName; return $this; } public function withLastName($lastName) { $this->lastName = $lastName; return $this; } public function withPhoneNumber($phoneNumber) { $this->phoneNumber = $phoneNumber; return $this; } public function withId($id) { $this->id = $id; return $this; } public function withEmail($email) { $this->email = $email; return $this; } public function withPassword($password) { $this->password = $password; return $this; } public function withStore(string $store) { $this->store = $store; return $this; } public function withCompanyId(string $companyId) { $this->companyId = $companyId; return $this; } public function withRole(string $role) { $this->role = $role; return $this; } public function withDisabled() { $this->isEnabled = false; return $this; } public function build() { $id = $this->id ?? Uuid::uuid4()->toString(); return new Client( $id, $this->firstName, $this->lastName, $this->email, $this->phoneNumber, $this->password, $this->store, $this->role, $this->isEnabled, $this->companyId ); } public static function aClient() { return new ClientBuilder(); } } ================================================ FILE: tests/unit/Seat/Domain/Client/Entity/CompanyBuilder.php ================================================ name = $name; return $this; } public function invoiced() { $this->hasInvoice = true; return $this; } public function store($store) { $this->store = $store; return $this; } public function deliverable($maxOrderTimeForDelivery) { $this->maxOrderTimeForDelivery = $maxOrderTimeForDelivery; return $this; } public function build() { $id = $this->id ?? Uuid::uuid4()->toString(); $store = $this->store ?? Store::$laHulpe; return new Company($id, $this->name, $this->hasInvoice, $store, $this->isEnabled, $this->maxOrderTimeForDelivery); } public static function aCompany() { return new CompanyBuilder(); } public function disabled() { $this->isEnabled = false; return $this; } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/GetClient/GetClientTest.php ================================================ clientRepository = new InMemoryClientRepository(); $this->client = ClientBuilder::aClient()->withId(self::CLIENT_ID)->build(); $this->clientRepository->addClient($this->client); $this->getClient = new GetClient($this->clientRepository); } public function present(GetClientResponse $response): void { $this->response = $response; } public function test_it_returns_a_client() { $this->getClient->execute(new GetClientRequest(self::CLIENT_ID), $this); $this->assertNotNull($this->response->client()); $this->assertSame($this->client->firstName(), $this->response->client()->firstName()); } public function test_it_returns_no_client_when_he_does_not_exist() { $this->getClient->execute(new GetClientRequest('unknown-client'), $this); $this->assertNull($this->response->client()); } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/Login/LoginTest.php ================================================ clientRepository = new InMemoryClientRepository(); $this->companyRepository = new InMemoryCompanyRepository(); $this->passwordHasher = new Base64PasswordHasher(); $this->login = new Login($this->clientRepository, $this->companyRepository, $this->passwordHasher); $this->registeredClient = ClientBuilder::aClient()->withPassword($this->passwordHasher->hash(self::PASSWORD))->build(); } public function present(LoginResponse $response) { $this->response = $response; } public function test_it_saves_the_logged_client_in_the_response() { $this->clientRepository->addClient($this->registeredClient); $this->login->execute(new LoginRequest($this->registeredClient->email(), self::PASSWORD), $this); $this->assertNotNull($this->response->client()); $this->assertSame($this->registeredClient->email(), $this->response->client()->email()); $this->assertSame($this->registeredClient->firstName(), $this->response->client()->firstName()); } public function test_an_error_when_the_password_is_wrong() { $this->clientRepository->addClient($this->registeredClient); $this->login->execute(new LoginRequest($this->registeredClient->email(), 'wrong password'), $this); $this->assertEquals((new Notification())->addError('password', 'invalid-password'), $this->response->notification()); } public function test_throws_an_error_when_user_does_not_exist() { $this->login->execute(new LoginRequest('unknown user', 'wrong password'), $this); $this->assertEquals((new Notification())->addError('email', 'unknown-email'), $this->response->notification()); } public function test_throws_an_error_when_the_user_is_disabled() { $client = ClientBuilder::aClient()->withPassword($this->passwordHasher->hash(self::PASSWORD))->withDisabled()->build(); $this->clientRepository->addClient($client); $this->login->execute(new LoginRequest($client->email(), self::PASSWORD), $this); $this->assertEquals((new Notification())->addError('email', 'disabled-user'), $this->response->notification()); } public function test_throws_an_error_when_his_company_is_disabled() { $company = CompanyBuilder::aCompany()->disabled()->build(); $this->companyRepository->addCompany($company); $client = ClientBuilder::aClient()->withPassword($this->passwordHasher->hash(self::PASSWORD))->withCompanyId($company->id())->build(); $this->clientRepository->addClient($client); $this->login->execute(new LoginRequest($client->email(), self::PASSWORD), $this); $this->assertEquals((new Notification())->addError('email', 'disabled-company'), $this->response->notification()); } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/Register/RegisterRequestBuilder.php ================================================ isPosted = true; $request->firstName = self::FIRST_NAME; $request->lastName = self::LAST_NAME; $request->store = self::STORE; $request->password = self::PASSWORD; $request->phoneNumber = self::PHONE_NUMBER; $request->email = self::EMAIL; return $request; } public function build() { $request = new RegisterRequest(); $request->isPosted = $this->isPosted; $request->firstName = $this->firstName; $request->lastName = $this->lastName; $request->store = $this->store; $request->password = $this->password; $request->phoneNumber = $this->phoneNumber; $request->email = $this->email; $request->companyName = $this->companyName; return $request; } public function empty() { $this->isPosted = false; $this->firstName = null; $this->lastName = null; $this->store = null; $this->password = null; $this->phoneNumber = null; $this->email = null; return $this; } public function withIsPosted($isPosted) { $this->isPosted = $isPosted; return $this; } public function withFirstName($firstName) { $this->firstName = $firstName; return $this; } public function withLastName($lastName) { $this->lastName = $lastName; return $this; } public function withStore($store) { $this->store = $store; return $this; } public function withPassword($password) { $this->password = $password; return $this; } public function withPhoneNumber($phoneNumber) { $this->phoneNumber = $phoneNumber; return $this; } public function withEmail($email) { $this->email = $email; return $this; } public function withCompanyName($companyName) { $this->companyName = $companyName; return $this; } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/Register/RegisterTest.php ================================================ response = $response; } protected function setUp() { $this->clientRepository = new InMemoryClientRepository(); $this->companyRepository = new InMemoryCompanyRepository(); $this->idGenerator = new IdGeneratorMock(); $this->passwordHasher = new Base64PasswordHasher(); $this->register = new Register( $this->idGenerator, $this->clientRepository, $this->companyRepository, $this->passwordHasher ); } public function test_saves_the_client_in_the_database_with_a_hashed_password() { $request = RegisterRequestBuilder::aRequest()->build(); $this->register->execute($request, $this); $this->assertEquals( ClientBuilder::aClient() ->withId($this->idGenerator->lastId) ->withFirstName($request->firstName) ->withLastName($request->lastName) ->withEmail($request->email) ->withPhoneNumber($request->phoneNumber) ->withPassword(base64_encode($request->password)) ->withStore($request->store) ->build(), $this->clientRepository->getClientByEmail($request->email) ); } public function test_fails_when_email_already_exist() { $request = RegisterRequestBuilder::aRequest()->build(); $this->clientRepository->addClient(ClientBuilder::aClient()->withEmail($request->email)->build()); $this->register->execute($request, $this); $shouldBe = (new Notification())->addError('email', 'email-already-used'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_a_user_can_not_be_linked_to_an_missing_company() { $request = RegisterRequestBuilder::aRequest()->withCompanyName('Missing company')->build(); $this->register->execute($request, $this); $shouldBe = (new Notification())->addError('companyName', 'unknown-company'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_a_user_can_be_linked_to_an_existing_company() { $company = CompanyBuilder::aCompany()->build(); $this->companyRepository->addCompany($company); $request = RegisterRequestBuilder::aRequest()->withCompanyName($company->name())->build(); $this->register->execute($request, $this); $this->assertNotNull($this->response->client()); $this->assertSame($company->id(), $this->response->client()->companyId()); $this->assertEquals( ClientBuilder::aClient() ->withId($this->idGenerator->lastId) ->withFirstName($request->firstName) ->withLastName($request->lastName) ->withEmail($request->email) ->withPhoneNumber($request->phoneNumber) ->withPassword(base64_encode($request->password)) ->withStore($request->store) ->withCompanyId($company->id()) ->build(), $this->clientRepository->getClientByEmail($request->email) ); } public function test_when_a_company_is_linked_the_user_inherits_from_its_store() { $company = CompanyBuilder::aCompany()->store('waterloo')->build(); $this->companyRepository->addCompany($company); $request = RegisterRequestBuilder::aRequest()->withCompanyName($company->name())->withStore('la-hulpe')->build(); $this->register->execute($request, $this); $this->assertNotNull($this->response->client()); $this->assertSame($company->store(), $this->response->client()->store()); } public function test_a_user_can_not_register_in_a_disabled_company() { $company = CompanyBuilder::aCompany()->disabled()->build(); $this->companyRepository->addCompany($company); $request = RegisterRequestBuilder::aRequest()->withCompanyName($company->name())->build(); $this->register->execute($request, $this); $shouldBe = (new Notification())->addError('companyName', 'disabled-company'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_the_request_is_validated() { $request = RegisterRequestBuilder::aRequest()->empty()->withIsPosted(true)->build(); $this->register->execute($request, $this); $shouldBe = (new Notification()) ->addError('firstName', 'error-notEmpty') ->addError('lastName', 'error-notEmpty') ->addError('email', 'error-notEmpty') ->addError('phoneNumber', 'error-notEmpty') ->addError('password', 'error-notEmpty') ->addError('store', 'error-notEmpty'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_firstname_lastname_and_password_must_be_a_string() { $request = RegisterRequestBuilder::aRequest() ->withFirstName(1)->withLastName(1)->withEmail(1)->withPassword(1)->withStore(1)->build(); $this->register->execute($request, $this); $shouldBe = (new Notification()) ->addError('firstName', 'error-string') ->addError('lastName', 'error-string') ->addError('email', 'invalid-email') ->addError('password', 'error-string') ->addError('store', 'error-choice'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_email_must_be_valid() { $request = RegisterRequestBuilder::aRequest()->withEmail('invalid-email')->build(); $this->register->execute($request, $this); $shouldBe = (new Notification())->addError('email', 'invalid-email'); $this->assertEquals($shouldBe, $this->response->notification()); } public function test_invalid_store_throws_an_error() { $request = RegisterRequestBuilder::aRequest()->withStore('invalid')->build(); $this->register->execute($request, $this); $shouldBe = (new Notification())->addError('store', 'error-choice'); $this->assertEquals($shouldBe, $this->response->notification()); } /** * @dataProvider stores */ public function test_store_must_be_la_hulpe_or_waterloo($store) { $request = RegisterRequestBuilder::aRequest()->withStore($store)->build(); $this->register->execute($request, $this); $this->assertFalse($this->response->notification()->hasError()); } public function stores(): array { return [['la-hulpe'], ['waterloo']]; } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/UpdateClient/UpdateClientRequestBuilder.php ================================================ firstName = self::FIRST_NAME; $request->lastName = self::LAST_NAME; $request->password = self::PASSWORD; $request->phoneNumber = self::PHONE_NUMBER; $request->email = self::EMAIL; $request->clientId = self::CLIENT_ID; return $request; } public function build() { $request = new UpdateClientRequest(); $request->firstName = $this->firstName; $request->lastName = $this->lastName; $request->password = $this->password; $request->phoneNumber = $this->phoneNumber; $request->email = $this->email; $request->clientId = $this->clientId; return $request; } public function empty() { $this->firstName = null; $this->lastName = null; $this->password = null; $this->phoneNumber = null; $this->email = null; $this->clientId = null; return $this; } public function withClientId($clientId) { $this->clientId = $clientId; return $this; } public function withPassword($password) { $this->password = $password; return $this; } public function withFirstName($firstName) { $this->firstName = $firstName; return $this; } public function withLastName($lastName) { $this->lastName = $lastName; return $this; } public function withEmail($email) { $this->email = $email; return $this; } public function withPhoneNumber($phoneNumber) { $this->phoneNumber = $phoneNumber; return $this; } } ================================================ FILE: tests/unit/Seat/Domain/Client/UseCase/UpdateClient/UpdateClientTest.php ================================================ clientRepository = new InMemoryClientRepository(); $this->passwordHasher = new Base64PasswordHasher(); $this->existingClient = ClientBuilder::aClient()->build(); $this->clientRepository->addClient($this->existingClient); $this->updateClient = new UpdateClient($this->clientRepository, $this->passwordHasher); } public function present(UpdateClientResponse $response) { $this->response = $response; } public function test_it_updates_a_client() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest()->withClientId($this->existingClient->id())->build(), $this ); $client = $this->clientRepository->getClientById($this->existingClient->id()); $this->assertNotNull($client); $this->assertSame('Nicolas', $client->firstName()); $this->assertSame('De Boose', $client->lastName()); $this->assertSame('nicolas@email.com', $client->email()); $this->assertSame('0474474747', $client->phoneNumber()); } public function test_it_fills_the_response() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest() ->withClientId($this->existingClient->id()) ->withFirstName('new first name') ->withLastName('new last name') ->withPhoneNumber('0474451232') ->withEmail('new@email.com') ->withPassword('new-password') ->build(), $this ); $this->assertNotNull($this->response); $this->assertInstanceOf(Client::class, $this->response->originalClient()); $this->assertSame('Nicolas', $this->response->originalClient()->firstName()); $this->assertNotNull($this->response->updatedClient()); $this->assertSame('new first name', $this->response->updatedClient()->firstName()); } public function test_it_checks_fields_validity() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest()->empty()->build(), $this ); $this->assertEquals( (new Notification()) ->addError('clientId', 'error-notEmpty') ->addError('firstName', 'error-notEmpty') ->addError('lastName', 'error-notEmpty') ->addError('email', 'error-notEmpty') ->addError('phoneNumber', 'error-notEmpty'), $this->response->notification() ); } public function test_it_checks_email_validity() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest()->withClientId($this->existingClient->id())->withEmail('invalid')->build(), $this ); $this->assertEquals( (new Notification()) ->addError('email', 'invalid-email'), $this->response->notification() ); } public function test_it_may_not_update_the_password() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest() ->withClientId($this->existingClient->id()) ->withPassword(null) ->build(), $this ); $client = $this->clientRepository->getClientById($this->existingClient->id()); $this->assertNotNull($client); $this->assertSame($this->existingClient->password(), $client->password()); } public function test_it_hashes_the_password() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest() ->withClientId($this->existingClient->id()) ->withPassword('new-password') ->build(), $this ); $client = $this->clientRepository->getClientById($this->existingClient->id()); $this->assertNotNull($client); $this->assertSame($this->passwordHasher->hash('new-password'), $client->password()); $this->assertTrue($this->response->hasPasswordChanged()); } public function test_it_fails_when_the_client_does_not_exist() { $this->updateClient->execute( UpdateClientRequestBuilder::aRequest()->withClientId('unknown-client-id')->build(), $this ); $this->assertEquals( (new Notification())->addError('clientId', 'unknown-client'), $this->response->notification() ); } } ================================================ FILE: tests/unit/Seat/Domain/Menu/UseCase/GetMenu/GetMenuTest.php ================================================ categoryRepository = new InMemoryCategoryRepository(); $this->optionRepository = new InMemoryProductOptionRepository(); $this->supplementRepository = new InMemoryProductSupplementRepository(); $this->productRepository = new InMemoryProductRepository(); $this->category1 = new Category('category-1', 'Cat 1', 'My first category'); $this->category2 = new Category('category-2', 'Cat 2', 'My second category'); $this->categoryRepository->addCategory($this->category1); $this->categoryRepository->addCategory($this->category2); $this->getMenu = new GetMenu( $this->categoryRepository, $this->optionRepository, $this->supplementRepository, $this->productRepository ); } public function present(GetMenuResponse $response): void { $this->response = $response; } public function test_it_returns_a_list_of_category() { $this->getMenu->execute($this); $this->assertCount(2, $this->response->menuLines); $this->assertSame($this->category1->name(), $this->response->menuLines[0]->name()); $this->assertSame($this->category1->description(), $this->response->menuLines[0]->description()); $this->assertSame($this->category2->name(), $this->response->menuLines[1]->name()); $this->assertSame($this->category2->description(), $this->response->menuLines[1]->description()); } public function test_the_list_may_contains_options() { $option1a = new ProductOption('option-1a', $this->category1->id(), 'Option 1a', 1); $option1b = new ProductOption('option-1b', $this->category1->id(), 'Option 1b', 1); $this->optionRepository->add($option1a); $this->optionRepository->add($option1b); $this->getMenu->execute($this); $this->assertCount(2, $this->response->menuLines[0]->options()); $this->assertSame($option1a->id(), $this->response->menuLines[0]->options()[0]->id()); $this->assertSame($option1a->name(), $this->response->menuLines[0]->options()[0]->name()); $this->assertSame($option1a->price(), $this->response->menuLines[0]->options()[0]->price()); $this->assertSame($option1b->id(), $this->response->menuLines[0]->options()[1]->id()); $this->assertSame($option1b->name(), $this->response->menuLines[0]->options()[1]->name()); $this->assertSame($option1b->price(), $this->response->menuLines[0]->options()[1]->price()); } public function test_the_list_may_contains_supplements() { $supplement1a = new ProductSupplement('supplement-1a', $this->category1->id(), 'Supplement 1a', 1); $supplement1b = new ProductSupplement('supplement-1b', $this->category1->id(), 'Supplement 1b', 1); $this->supplementRepository->add($supplement1a); $this->supplementRepository->add($supplement1b); $this->getMenu->execute($this); $this->assertCount(2, $this->response->menuLines[0]->supplements()); $this->assertSame($supplement1a->id(), $this->response->menuLines[0]->supplements()[0]->id()); $this->assertSame($supplement1a->name(), $this->response->menuLines[0]->supplements()[0]->name()); $this->assertSame($supplement1a->price(), $this->response->menuLines[0]->supplements()[0]->price()); $this->assertSame($supplement1b->id(), $this->response->menuLines[0]->supplements()[1]->id()); $this->assertSame($supplement1b->name(), $this->response->menuLines[0]->supplements()[1]->name()); $this->assertSame($supplement1b->price(), $this->response->menuLines[0]->supplements()[1]->price()); } public function test_the_list_may_contains_products() { $product1a = new Product('product-1a', $this->category1->id(), 'Product 1a', 'Product 1a desc', 1); $product1b = new Product('product-1b', $this->category1->id(), 'Product 1b', 'Product 1b desc', 1); $this->productRepository->add($product1a); $this->productRepository->add($product1b); $this->getMenu->execute($this); $this->assertCount(2, $this->response->menuLines[0]->products()); $this->assertSame($product1a->id(), $this->response->menuLines[0]->products()[0]->id()); $this->assertSame($product1a->name(), $this->response->menuLines[0]->products()[0]->name()); $this->assertSame($product1a->price(), $this->response->menuLines[0]->products()[0]->price()); $this->assertSame($product1a->description(), $this->response->menuLines[0]->products()[0]->description()); $this->assertSame($product1b->id(), $this->response->menuLines[0]->products()[1]->id()); $this->assertSame($product1b->name(), $this->response->menuLines[0]->products()[1]->name()); $this->assertSame($product1b->price(), $this->response->menuLines[0]->products()[1]->price()); $this->assertSame($product1b->description(), $this->response->menuLines[0]->products()[1]->description()); } } ================================================ FILE: tests/unit/Seat/Domain/Order/UseCase/ConfirmBasket/ConfirmBasketRequestBuilder.php ================================================ userId = $this->userId; $request->checkSum = $this->checkSum; $request->orderTypeName = $this->orderTypeName; $request->takeAwayTime = $this->takeAwayTime; return $request; } public function withUserId($userId) { $this->userId = $userId; return $this; } public function withCheckSum($checkSum) { $this->checkSum = $checkSum; return $this; } public function withOrderTypeName($orderTypeName) { $this->orderTypeName = $orderTypeName; return $this; } public function withTakeAwayTime($takeAwayTime) { $this->takeAwayTime = $takeAwayTime; return $this; } public function forBasket(Basket $basket) { $this->checkSum = $basket->checkSum(); return $this; } public function takeAwayAt(string $takeAwayTime) { $this->orderTypeName = 'take-away'; $this->takeAwayTime = $takeAwayTime; return $this; } public function forClient(Client $client) { $this->userId = $client->id(); return $this; } } ================================================ FILE: tests/unit/Seat/Domain/Order/UseCase/ConfirmBasket/ConfirmBasketTest.php ================================================ commandRepository = new InMemoryCommandRepository(); $this->basketRepository = new InMemoryBasketRepository(); $this->clientRepository = new InMemoryClientRepository(); $this->companyRepository = new InMemoryCompanyRepository(); $this->company = CompanyBuilder::aCompany()->deliverable('11:00:00')->build(); $this->deliveredClient = ClientBuilder::aClient()->withCompanyId($this->company->id())->build(); $this->takeAwayClient = ClientBuilder::aClient()->build(); $this->clientWithoutBasket = ClientBuilder::aClient()->withCompanyId($this->company->id())->build(); $this->clientRepository->addClient($this->deliveredClient); $this->clientRepository->addClient($this->takeAwayClient); $this->clientRepository->addClient($this->clientWithoutBasket); $this->companyRepository->addCompany($this->company); $this->basketProduct = new BasketProduct('product-id', 1, 'Product 1', 2, null, [], ''); $this->basket = new Basket('_not_used_', [$this->basketProduct]); $this->basketRepository->addToBasket($this->deliveredClient->id(), $this->basketProduct); $this->basketRepository->addToBasket($this->takeAwayClient->id(), $this->basketProduct); $this->clock = $this->createMock(Clock::class); $this->confirmBasket = new ConfirmBasket( $this->commandRepository, $this->basketRepository, $this->clientRepository, new OrderTypeChecker($this->companyRepository, $this->clientRepository, $this->clock) ); } public function present(ConfirmBasketResponse $response): void { $this->response = $response; } private function nowIs(string $hourMinute) { $this->clock->method('now')->willReturn( DateTimeImmutable::createFromFormat('H:i', $hourMinute, new \DateTimeZone('Europe/Brussels')) ); } public function test_it_saves_take_away_into_a_command() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->takeAwayAt('10:00') ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->build(); $this->confirmBasket->execute($request, $this); $commands = $this->commandRepository->getTodayList(); $this->assertCount(1, $commands); $this->assertSame('take-away', $commands[0]->orderType()->name()); $this->assertSame($this->takeAwayClient->id(), $commands[0]->userId()); $this->assertSame($this->basket->totalPrice(), $commands[0]->basket()->totalPrice()); } public function test_it_saves_delivery_into_a_command() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket()->forBasket($this->basket)->forClient($this->deliveredClient)->build(); $this->confirmBasket->execute($request, $this); $commands = $this->commandRepository->getTodayList(); $this->assertCount(1, $commands); $this->assertSame('delivery', $commands[0]->orderType()->name()); $this->assertSame($this->deliveredClient->id(), $commands[0]->userId()); } public function test_a_delivery_company_can_not_take_away() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->takeAwayAt('10:00') ->forBasket($this->basket) ->forClient($this->deliveredClient) ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Take away not available'), $this->response->notification() ); } public function test_a_take_away_client_can_not_deliver() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Delivery not available'), $this->response->notification() ); } public function test_it_fails_when_the_given_check_sum_is_not_correct() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket()->withCheckSum('wrong')->forClient($this->deliveredClient)->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('checkSum', 'wrong-check-sum'), $this->response->notification() ); } public function test_an_empty_basket_can_not_be_confirmed() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket()->forClient($this->clientWithoutBasket)->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('userId', 'empty-basket'), $this->response->notification() ); } public function test_it_empties_the_basket() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->takeAwayAt('10:00') ->build(); $this->confirmBasket->execute($request, $this); $basket = $this->basketRepository->getUserBasket($this->takeAwayClient->id()); $this->assertTrue($basket->isEmpty()); } public function test_throws_an_error_when_the_client_is_unknown() { $this->nowIs('10:00'); $request = ConfirmBasketRequestBuilder::aConfirmBasket()->withUserId('unknown client')->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('userId', 'unknown-client'), $this->response->notification() ); } public function test_a_deliver_must_be_done_before_company_limit_time() { $this->nowIs('11:30'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->deliveredClient) ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Order too late'), $this->response->notification() ); } public function test_a_take_away_done_at_11h11_is_too_late() { $this->nowIs('11:11'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->takeAwayAt('14:00') ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Order too late'), $this->response->notification() ); } public function test_a_take_away_time_14h01_is_too_late() { $this->nowIs('11:10'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->takeAwayAt('14:01') ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Take away too late'), $this->response->notification() ); } public function test_a_take_away_time_can_be_set_to_maximum_14h00() { $this->nowIs('11:10'); $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->takeAwayClient) ->takeAwayAt('14:00') ->build(); $this->confirmBasket->execute($request, $this); $this->assertCount(1, $this->commandRepository->getTodayList()); } public function test_it_notifies_when_the_type_is_unknown() { $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->forBasket($this->basket) ->forClient($this->deliveredClient) ->withOrderTypeName('fake order type') ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('orderTypeName', 'Invalid order type'), $this->response->notification() ); } public function test_a_null_client_is_considered_unknown() { $request = ConfirmBasketRequestBuilder::aConfirmBasket() ->withUserId(null) ->build(); $this->confirmBasket->execute($request, $this); $this->assertEquals( (new Notification())->addError('userId', 'unknown-client'), $this->response->notification() ); } } ================================================ FILE: tests/unit/Seat/SharedKernel/Model/TimeRangeTest.php ================================================ assertSame(['10:00:00', '10:15:00', '10:30:00', '10:45:00', '11:00:00'], $timeRange->getRoundedStep(15)); } public function test_from_can_be_delayed() { $timeRange = new TimeRange('10:00:00', '11:00:00'); $delay = DateTimeImmutable::createFromFormat('H:i:s', '10:26:21'); $timeRange = $timeRange->delayFromDate($delay); $this->assertSame(['10:26:21', '10:41:21', '10:56:21',], $timeRange->getRoundedStep(15)); } public function test_from_can_be_delayed_and_rounded() { $timeRange = new TimeRange('10:00:00', '11:00:00'); $delay = DateTimeImmutable::createFromFormat('H:i:s', '10:20:21'); $timeRange = $timeRange->delayFromDate($delay, 10); $this->assertSame(['10:30:00', '10:45:00', '11:00:00'], $timeRange->getRoundedStep(15)); } public function test_can_not_delay_before_the_current_from_time() { $timeRange = new TimeRange('10:00:00', '11:00:00'); $delay = DateTimeImmutable::createFromFormat('H:i:s', '09:30:00'); $timeRange = $timeRange->delayFromDate($delay, 10); $this->assertSame(['10:00:00', '10:15:00', '10:30:00', '10:45:00', '11:00:00'], $timeRange->getRoundedStep(15)); } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Basket/Entity/InMemoryBasketRepository.php ================================================ baskets)) { $this->baskets[$userId] = []; } $this->baskets[$userId][] = $basketProduct; } public function getUserBasket(string $userId): Basket { if (!array_key_exists($userId, $this->baskets) || count($this->baskets[$userId]) === 0) { return new Basket($userId, []); } return new Basket($userId, $this->baskets[$userId]); } public function emptyBasketFor(string $userId): void { unset($this->baskets[$userId]); } public function delete(string $basketId, string $userId): void { for ($i = 0; $i < count($this->baskets[$userId]); $i++) { if ($this->baskets[$userId][$i]->id() === $basketId) { array_splice($this->baskets[$userId], $i, 1); return; } } } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Client/Entity/InMemoryClientRepository.php ================================================ clients[] = $client; } public function getRegisterClient(string $email, string $password): ?Client { $find = function (Client $client) use ($email, $password) { return $client->email() === $email && $client->password() === $password; }; $clientsFound = array_values(array_filter($this->clients, $find)); if (count($clientsFound) === 1) { return $clientsFound[0]; } return null; } public function getClientByEmail(string $email): ?Client { $find = function (Client $client) use ($email) { return $client->email() === $email; }; $clientsFound = array_values(array_filter($this->clients, $find)); if (count($clientsFound) === 1) { return $clientsFound[0]; } return null; } public function getClientById(string $id): ?Client { $find = function (Client $client) use ($id) { return $client->id() === $id; }; $clientsFound = array_values(array_filter($this->clients, $find)); if (count($clientsFound) === 1) { return $clientsFound[0]; } return null; } public function updateClient(Client $client): void { for ($i = 0; $i < count($this->clients); $i++) { if ($this->clients[$i]->id() === $client->id()) { $this->clients[$i] = $client; break; } } } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Client/Entity/InMemoryCompanyRepository.php ================================================ name() === $companyName; }; $foundCompanies = array_values(array_filter($this->companies, $find)); if (count($foundCompanies) === 1) { return $foundCompanies[0]; } return null; } public function addCompany(Company $company): void { $this->companies[] = $company; } public function getCompanyById(?string $companyId): ?Company { $find = function (Company $company) use ($companyId) { return $company->id() === $companyId; }; $foundCompanies = array_values(array_filter($this->companies, $find)); if (count($foundCompanies) === 1) { return $foundCompanies[0]; } return null; } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Menu/Entity/InMemoryCategoryRepository.php ================================================ categories; } public function addCategory(Category $category) { $this->categories[] = $category; } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Menu/Entity/InMemoryProductOptionRepository.php ================================================ options[$productOptionId] ?? null; } public function add(ProductOption $productOption): void { $this->options[$productOption->id()] = $productOption; } /** * @return ProductOption[] */ public function getByCategoryId(string $categoryId): array { return array_values( array_filter( $this->options, function (ProductOption $productOption) use ($categoryId) { return $productOption->categoryId() === $categoryId; } ) ); } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Menu/Entity/InMemoryProductRepository.php ================================================ products[$product->id()] = $product; } public function get(string $id): ?Product { return $this->products[$id] ?? null; } /** * @return Product[] */ public function getByCategoryId(string $categoryId): array { return array_values( array_filter( $this->products, function (Product $product) use ($categoryId) { return $product->categoryId() === $categoryId; } ) ); } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Menu/Entity/InMemoryProductSupplementRepository.php ================================================ supplements[$supplementId] ?? null; } public function add(ProductSupplement $supplement): void { $this->supplements[$supplement->id()] = $supplement; } /** * @return ProductSupplement[] */ public function getByCategoryId(string $categoryId): array { return array_values( array_filter( $this->supplements, function (ProductSupplement $supplement) use ($categoryId) { return $supplement->categoryId() === $categoryId; } ) ); } } ================================================ FILE: tests/unit/Seat/_Mock/Domain/Order/Entity/InMemoryCommandRepository.php ================================================ commands[] = $command; } /** * @return Command[] */ public function getTodayList(): array { $today = date('Y-m-d'); return array_filter( $this->commands, function (Command $command) use ($today) { return $command->date()->format('Y-m-d') === $today; } ); } } ================================================ FILE: tests/unit/Seat/_Mock/Seat/SharedKernel/Service/IdGeneratorMock.php ================================================ lastId = (string)++$this->id; return $this->lastId; } } ================================================ FILE: webpack.config.js ================================================ var Encore = require('@symfony/webpack-encore'); Encore // directory where compiled assets will be stored .setOutputPath('public/build/') // public path used by the web server to access the output path .setPublicPath('/build') // only needed for CDN's or sub-directory deploy //.setManifestKeyPrefix('build/') /* * ENTRY CONFIG * * Add 1 entry for each "page" of your app * (including one that's included on every page - e.g. "app") * * Each entry will result in one JavaScript file (e.g. app.js) * and one CSS file (e.g. app.css) if you JavaScript imports CSS. */ .addEntry('app', './resources/assets/js/app.js') //.addEntry('page1', './assets/js/page1.js') //.addEntry('page2', './assets/js/page2.js') // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() // will require an extra script tag for runtime.js // but, you probably want this, unless you're building a single-page app .enableSingleRuntimeChunk() /* * FEATURE CONFIG * * Enable & configure other features below. For a full * list of features, see: * https://symfony.com/doc/current/frontend.html#adding-more-features */ .cleanupOutputBeforeBuild() .enableBuildNotifications() .enableSourceMaps(!Encore.isProduction()) // enables hashed filenames (e.g. app.abc123.css) .enableVersioning(Encore.isProduction()) // enables @babel/preset-env polyfills .configureBabel(() => {}, { useBuiltIns: 'usage', corejs: 3 }) // enables Sass/SCSS support //.enableSassLoader() // uncomment if you use TypeScript //.enableTypeScriptLoader() // uncomment to get integrity="..." attributes on your script & link tags // requires WebpackEncoreBundle 1.4 or higher //.enableIntegrityHashes() // uncomment if you're having problems with a jQuery plugin //.autoProvidejQuery() // uncomment if you use API Platform Admin (composer req api-admin) //.enableReactPreset() //.addEntry('admin', './assets/js/admin.js') ; module.exports = Encore.getWebpackConfig();