diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 6c171d1..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 CakeManager - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/README.md b/README.md index 0894267..7f403f4 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,36 @@ -# CakeAdmin plugin for CakePHP +# Bakkerij/CakeAdmin plugin for CakePHP -> Note: This is a non-stable plugin for CakePHP 3.x at this time. It is currently under development and should be considered experimental. +## Install CakePHP + +Note: This is only required if you do not already have a project started. + +``` +$ composer self-update && composer create-project --prefer-dist cakephp/app {your new project name} +``` ## Installation -You can find the installation-guide here: http://cakemanager.org/docs/cakeadmin/1.0/installation/. +You can install this plugin into your CakePHP application using [composer](http://getcomposer.org). + +The recommended way to install composer packages is: + +``` +$ composer require bakkerij/cakeadmin:dev-rewrite +``` + +## Load Plugin -## Documentation +``` +$ bin/cake plugin load -b -r Bakkerij/CakeAdmin +``` -Documentation is available at http://cakemanager.org/docs/cakeadmin/1.0/. +## Update Database Info -## Strategy +Navigate to the new project's config/app.php and update your Datasources username, password, and database. -We are working on this version. Wanna read more about our strategy? Read the following post: http://cakemanager.org/new-cakeadmin-plugin-announced/ +## Load CakeAdmin Tables +``` +$ bin/cake migrations migrate -p Bakkerij/CakeAdmin +``` -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cakemanager/cakephp-cakeadmin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) \ No newline at end of file diff --git a/composer.json b/composer.json index b5eb63f..a905b1b 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,25 @@ { - "name": "cakemanager/cakephp-cakeadmin", - "description": "CakeAdmin plugin for CakePHP", + "name": "bakkerij/cakeadmin", + "description": "Admin plugin for CakePHP", "type": "cakephp-plugin", "require": { "php": ">=5.4.16", - "cakephp/cakephp": "~3.1", - "cakemanager/cakephp-utils": "dev-master", - "cakemanager/cakephp-notifier": "dev-master", - "cakemanager/cakephp-settings": "dev-master", - "cakemanager/cakeadmin-lightstrap": "dev-master" + "cakephp/cakephp": "~3.0", + "friendsofcake/crud": "^4.3", + "gourmet/knp-menu": "~0.4" }, "require-dev": { - "phpunit/phpunit": " 4.1.*@dev", - "cakephp/cakephp-codesniffer": "2.*" + "phpunit/phpunit": "*" }, "autoload": { "psr-4": { - "CakeAdmin\\": "src" + "Bakkerij\\CakeAdmin\\": "src" } }, "autoload-dev": { "psr-4": { - "CakeAdmin\\Test\\": "tests", + "Bakkerij\\CakeAdmin\\Test\\": "tests", "Cake\\Test\\": "./vendor/cakephp/cakephp/tests" } - }, - "minimum-stability": "dev" + } } diff --git a/config/Migrations/20150611195820_cakeadmin_initial.php b/config/Migrations/20150611195820_cakeadmin_initial.php deleted file mode 100644 index df8aa50..0000000 --- a/config/Migrations/20150611195820_cakeadmin_initial.php +++ /dev/null @@ -1,70 +0,0 @@ -hasTable('users')) { - $table = $this->table('users'); - if (!$table->hasColumn('cakeadmin')) { - $table - ->addColumn('cakeadmin', 'integer', [ - 'default' => 0, - 'limit' => 11, - 'null' => true, - ]) - ->save(); - } - if (!$table->hasColumn('request_key')) { - $table - ->addColumn('request_key', 'string', [ - 'default' => null, - 'limit' => 255, - 'null' => true, - ]) - ->save(); - } - } else { - $table = $this->table('users'); - $table - ->addColumn('email', 'string', [ - 'default' => null, - 'limit' => 50, - 'null' => true, - ]) - ->addColumn('password', 'string', [ - 'default' => null, - 'limit' => 255, - 'null' => true, - ]) - ->addColumn('cakeadmin', 'integer', [ - 'default' => 0, - 'limit' => 11, - 'null' => true, - ]) - ->addColumn('request_key', 'string', [ - 'default' => null, - 'limit' => 255, - 'null' => true, - ]) - ->addColumn('created', 'datetime') - ->addColumn('modified', 'datetime') - ->create(); - } - } -} diff --git a/config/Migrations/20160716113123_Initial.php b/config/Migrations/20160716113123_Initial.php new file mode 100644 index 0000000..fbdd87c --- /dev/null +++ b/config/Migrations/20160716113123_Initial.php @@ -0,0 +1,51 @@ +table('cakeadmin_administrators', ['id' => false, 'primary_key' => ['id']]); + $table + ->addColumn('id', 'uuid', [ + 'default' => null, + 'limit' => null, + 'null' => false, + ]) + ->addColumn('name', 'string', [ + 'default' => null, + 'limit' => 150, + 'null' => false, + ]) + ->addColumn('email', 'string', [ + 'default' => null, + 'limit' => 50, + 'null' => true, + ]) + ->addColumn('password', 'string', [ + 'default' => null, + 'limit' => 255, + 'null' => true, + ]) + ->addColumn('active', 'integer', [ + 'default' => 0, + 'limit' => 1, + 'null' => true, + ]) + ->addColumn('request_key', 'string', [ + 'default' => null, + 'limit' => 255, + 'null' => true, + ]) + ->addColumn('created', 'datetime') + ->addColumn('modified', 'datetime') + ->create(); + } +} diff --git a/config/Migrations/schema-dump-default.lock b/config/Migrations/schema-dump-default.lock new file mode 100644 index 0000000..5d98ea9 Binary files /dev/null and b/config/Migrations/schema-dump-default.lock differ diff --git a/config/bootstrap.php b/config/bootstrap.php index 0c1fa1b..2062978 100644 --- a/config/bootstrap.php +++ b/config/bootstrap.php @@ -1,67 +1,33 @@ true, 'routes' => true]); -Plugin::load('Notifier', ['bootstrap' => true, 'routes' => true]); +// Load Crud plugin +if(!Plugin::loaded('Crud')) { + Plugin::load('Crud'); +} +// Load Knp plugin +if(!Plugin::loaded('Gourmet/KnpMenu')) { + Plugin::load('Gourmet/KnpMenu'); +} -# Configurations +// Sessions timeout Configure::write('Session.timeout', 4320); -Configure::write('CA.theme', 'CakeAdmin'); -Configure::write('CA.viewClass', null); - -Configure::write('CA.layout.default', 'CakeAdmin.default'); -Configure::write('CA.layout.login', 'CakeAdmin.login'); - +// Configure login fields Configure::write('CA.fields', [ 'username' => 'email', 'password' => 'password' ]); -Configure::write('CA.email.from', ['admin@cakemanager.org' => 'Bob | CakeManager']); - -Configure::write('CA.email.transport', 'default'); - -Configure::write('CA.Menu.main', []); - -Configure::write('Settings.Prefixes.CA', 'CakeAdmin'); - -Configure::write('CA.PostTypes', []); - -Configure::write('CA.Models.administrators', 'CakeAdmin.Administrators'); - - -# Settings -Setting::register('App.Name', 'CakeAdmin Application'); - -# Theming -Plugin::load('LightStrap', ['bootstrap' => true, 'routes' => true]); - +// Registered PostTypes +//Configure::write('CA.postTypes', [ +// 'bookmarks' => 'Bookmarks' +//]); -# Notification Templates -NotificationManager::instance()->addTemplate('newAdministrator', [ - 'title' => 'New administrator has been registered', - 'body' => ':email has been registered as administrator at :created' +// Custom menu items +Configure::write('CA.menu', [ + 'main' => [] ]); \ No newline at end of file diff --git a/config/init/CakeAdmin.default.php b/config/init/CakeAdmin.default.php new file mode 100644 index 0000000..915eb05 --- /dev/null +++ b/config/init/CakeAdmin.default.php @@ -0,0 +1,15 @@ +connect( - '/', [ - 'plugin' => 'CakeAdmin', - 'controller' => 'Users', - 'action' => 'login' - ] - ); - $routes->fallbacks('InflectedRoute'); + }); -Router::plugin('CakeAdmin', ['path' => '/'], function ($routes) { +Router::plugin('Bakkerij/CakeAdmin', ['path' => '/', '_namePrefix' => 'cakeadmin:'], function (RouteBuilder $routes) { $routes->prefix('admin', function ($routes) { + // User routes $routes->connect( - '/login', ['controller' => 'Users', 'action' => 'login'] + '/login', + [ + 'controller' => 'Users', + 'action' => 'login', + ], + [ + '_name' => 'login' + ] ); - $routes->connect( - '/logout', ['controller' => 'Users', 'action' => 'logout'] + '/logout', + [ + 'controller' => 'Users', + 'action' => 'logout', + ], + [ + '_name' => 'logout' + ] ); + // Default admin route $routes->connect( - '/posttypes/:type/:action/*', ['controller' => 'PostTypes'], ['pass' => ['type']] + '/', + ['controller' => 'Dashboard'] ); + // PostType routes $routes->connect( - '/', ['controller' => 'Users', 'action' => 'login'] + '/posttype/:type/', + ['controller' => 'PostTypes', 'action' => 'index'], + ['_name' => 'posttype:index', 'pass' => ['type']] ); - $routes->connect( - '/users/:action/*', ['controller' => 'Users'] + '/posttype/:type/index', + ['controller' => 'PostTypes', 'action' => 'index'], + ['pass' => ['type']] ); - $routes->connect( - '/dashboard', ['controller' => 'Dashboard'] + '/posttype/:type/add', + ['controller' => 'PostTypes', 'action' => 'add'], + ['_name' => 'posttype:add', 'pass' => ['type']] ); - $routes->connect( - '/notifications/**', ['controller' => 'Notifications'] + '/posttype/:type/edit/:id', + ['controller' => 'PostTypes', 'action' => 'edit'], + ['_name' => 'posttype:edit', 'pass' => ['id', 'type']] + ); + $routes->connect( + '/posttype/:type/view/:id', + ['controller' => 'PostTypes', 'action' => 'view'], + ['_name' => 'posttype:view', 'pass' => ['id', 'type']] ); - $routes->connect( - '/settings/**', ['controller' => 'Settings'] + '/posttype/:type/delete/:id', + ['controller' => 'PostTypes', 'action' => 'delete'], + ['_name' => 'posttype:delete', 'pass' => ['id', 'type']] ); - $routes->fallbacks('InflectedRoute'); + $routes->fallbacks('DashedRoute'); }); diff --git a/couscous.yml b/couscous.yml new file mode 100644 index 0000000..c66e4e3 --- /dev/null +++ b/couscous.yml @@ -0,0 +1,49 @@ +template: + url: https://github.com/CouscousPHP/Template-Light.git + index: index.md + +include: + - docs + +exclude: + - vendor + - website + - some/dir + - %gitignore% + +branch: gh-pages + +title: CakeAdmin +subTitle: Manage your CakePHP Application with ease. + +baseUrl: http://bakkerij.github.io/cakeadmin + +menu: + items: + introduction: + text: Introduction + relativeUrl: index.html + installation: + text: Installation + relativeUrl: installation.html + quik-start: + text: Quick Start + relativeUrl: quick-start.html + cakeadmin-class: + text: CakeAdmin Class + relativeUrl: cakeadmin-class.html + configuration: + text: Configuration + relativeUrl: configuration.html + posttypes: + text: PostTypes + relativeUrl: posttypes.html + commands: + text: Commands + relativeUrl: commands.html + custom-controllers: + text: Custom Controllers + relativeUrl: custom-controllers.html + events: + text: Events + relativeUrl: events.html diff --git a/docs/cakeadmin-class.md b/docs/cakeadmin-class.md new file mode 100644 index 0000000..849c532 --- /dev/null +++ b/docs/cakeadmin-class.md @@ -0,0 +1,158 @@ +CakeAdmin Class +=============== + +The CakeAdmin class is a class located in `/src/CakeAdmin.php` to make hooking into CakeAdmin much easier. This class will only be executed when a page of CakeAdmin is +requested, so your own controller classes won't be hurt. + +After generating the class with `$ bin/cake cakeadmin init`, the class will look like: + +``` +registerPostType('Bookmarks'); + +// Plugin +$this->registerPostType('MyPlugin.Bookmarks'); + +``` + +### `addController` + +Adding your custom controller to CakeAdmin can be done using the `addController` method. You can use multiple formats to parse the route: + +Default example + +``` +$this->addController('Custom Item', 'Admin/Custom::index'); +``` + +With plugin + +``` +$this->addController('Custom Item', 'MyPlugin.Admin/Custom::index'); +``` + +Without prefix (Admin) +``` +$this->addController('Custom Item', 'Custom::index'); +``` + +Without action (default `index`) + +``` +$this->addController('Custom Item', 'Admin/Custom'); +``` + +As array + +``` +$this->addController('Custom Item', [ + 'plugin' => false, + 'prefix' => 'admin', + 'controller' => 'Custom', + 'action' => 'index' +]); +``` + +### `addMenuItem` + +Adding a custom menu item can be done using: + +``` +$this->addMenuItem('cakeadmin_main', 'Dashboard', ['uri' => [ + 'plugin' => 'Bakkerij/CakeAdmin', + 'prefix' => 'admin', + 'controller' => 'Dashboard', + 'action' => 'index' +]]); +``` + +> Note to developers: Not implemented yet ;) + +## Events + +The following events are listened by the CakeAdmin class. By creating those methods you can hook into the events. + +### `CakeAdmin.Controller.startup` + +``` +public function startup(Event $event) +{ + +} +``` + +### `CakeAdmin.Controller.beforeRedirect` + +``` +public function beforeRedirect(Event $event) +{ + +} +``` + +### `CakeAdmin.Controller.beforeFilter` + +``` +public function beforeFilter(Event $event) +{ + +} +``` + +### `CakeAdmin.Controller.beforeRender` + +``` +public function beforeRender(Event $event) +{ + +} +``` + +### `CakeAdmin.Controller.shutdown` + +``` +public function shutdown(Event $event) +{ + +} +``` + +### Add events + +To add your own implemented events use the following code: + +``` +public function implementedEvents() + { + $events = parent::implementedEvents(); + + $events['your.event'] = 'yourEvent'; + + return $events; + } +``` \ No newline at end of file diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 0000000..2b595c2 --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,24 @@ +Commands +======== + +The following shell tasks are provided by CakeAdmin: + +### Init + +To initialize CakeAdmin, the following shell command is available: + +``` +$ bin/cake cakeadmin init +``` + +This command will create a `/src/CakeAdmin.php` file. + +### Admin + +To create an administrator user for CakeAdmin, use the `admin` command: + +``` +$ bin/cake cakeadmin admin +``` + +This command will ask for your e-mail and name, and will set the default password `cakeadmin` (you can change this later on). \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..eb9de21 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,9 @@ +Configuration +============= + +The following configurations are used in CakeAdmin using the `Cake\Core\Configure` class: + +- `CA.fields` - The login fields to use. Default `email` and `password`. +- `CA.menu` - Array for the menu + +> Note, all CakeAdmin related configurations will contain the prefix `CA`. \ No newline at end of file diff --git a/docs/custom-controllers.md b/docs/custom-controllers.md new file mode 100644 index 0000000..25667ec --- /dev/null +++ b/docs/custom-controllers.md @@ -0,0 +1,63 @@ +Custom Controllers +================== + +While CakeAdmin has some default controllers and PostTypes in it, we want to give you your freedom to extend CakeAdmin with your own functionality. This can be done +by creating your own custom controllers. To add custom controllers you must apply the following rules: + +- Controller must contain the prefix `Admin` (path would become `/src/Controller/Admin`). +- Controller must depend on CakeAdmin's `Bakkerij/CakeAdmin/Controller/AppController` class. + +> Note to developers: Probably a bake command could be implemented to create this like `cake bake cakeadmin_controller CustomController` + +Example: + +``` +addController('Custom Item', 'Admin/Custom::index'); +``` + +With plugin + +``` +$this->addController('Custom Item', 'MyPlugin.Admin/Custom::index'); +``` + +Without prefix (Admin) +``` +$this->addController('Custom Item', 'Custom::index'); +``` + +Without action (default `index`) + +``` +$this->addController('Custom Item', 'Admin/Custom'); +``` + +As array + +``` +$this->addController('Custom Item', [ + 'plugin' => false, + 'prefix' => 'admin', + 'controller' => 'Custom', + 'action' => 'index' +]); +``` \ No newline at end of file diff --git a/docs/events.md b/docs/events.md new file mode 100644 index 0000000..ae6ae3c --- /dev/null +++ b/docs/events.md @@ -0,0 +1,18 @@ +Events +====== + +List of fired events by CakeAdmin: + +### Controller + +- `CakeAdmin.Controller.startup` - Fired before CakeAdmins initialization +- `CakeAdmin.Controller.beforeRedirect` - Fired before CakeAdmins redirects +- `CakeAdmin.Controller.beforeFilter` - Fired before CakeAdmins filter +- `CakeAdmin.Controller.beforeRender` - Fired before CakeAdmins render +- `CakeAdmin.Controller.shutdown` - Fired before CakeAdmins shutdown + +> Note that these events are applied to the controller, but only on CakeAdmin, not regular controllers. + +### PostTypes + +> Note to developers: No events on PostTypes yet, but they'll come! diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0184c3f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,26 @@ +Introduction +============ + +## What is CakeAdmin? +The CakeAdmin Plugin is built to provide developers a backend for their application. Every application needs a backend to have insights, manage data, et cetera. +CakeAdmin is easy to install and provides a basic admin panel. + +## Goals + +- Goal 1 +- Goal 2 +- Goal 3 + +## Questions? + +If you need help, you can join us at [Gitter](https://gitter.im/bakkerij/cakeadmin-beta). + +## Bugs + +If you happen to stumble upon a bug, please feel free to create a pull request or submit an issue with a fix (optionally with a test), and a description of the bug +and how it was resolved. + +## Features + +If you have suggestions for CakeAdmin, please join us at [Gitter](https://gitter.im/bakkerij/cakeadmin-beta), and let's talk! Opening a pull request is always more +than welcome, and a great way to start a discussion. Please check our contribution guidelines. diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..8fac02d --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,48 @@ +Installation +============ + +## Requirements + +You need PHP >= 5.5.9 to use CakeAdmin, and CakePHP 3.2 or higher. + +## Composer + +CakeAdmin is available on [Packagist](https://packagist.org/) and can be installed using [Composer](https://getcomposer.org/): + +``` +$ composer require bakkerij/cakeadmin +``` + +> Note: while this plugin is under development, just clone the repository into `plugins/Bakkerij/CakeAdmin` + +## Loading the plugin + +Run the following command: + +``` +$ bin/cake plugin load -b -r Bakkerij/CakeAdmin +``` + +Or add the following to your `/config/bootstrap.php`: + +``` +Plugin::load('Bakkerij/CakeAdmin', ['bootstrap' => true, 'routes' => true]); +``` + +## Initializing CakeAdmin + +To make hooks to CakeAdmin easier, CakeAdmin makes use of an `App/CakeAdmin` class. This class can be generated running the command: + +``` +$ bin/cake cakeadmin init +``` + +## Creating an user + +To create your first administrator you can run the command: + +``` +$ bin/cake cakeadmin admin +``` + +This command will ask for your e-mail and name, and will set the default password `cakeadmin` (you can change this later on). diff --git a/docs/posttypes.md b/docs/posttypes.md new file mode 100644 index 0000000..d3b1d2b --- /dev/null +++ b/docs/posttypes.md @@ -0,0 +1,217 @@ +PostTypes +========= + +PostTypes are a great way to manage your table data per model. + +## Basic Usage + +To get started, create a PostType class. These classes live in `src/PostType`. The most basic PostType class would look like: + +``` +// src/PostType/BookmarksPostType.php +namespace App\PostType; + +use Bakkerij\CakeAdmin\PostType\PostType; + +class BookmarksPostType extends PostType +{ +} +``` + +Note that we did not tell the PostType which model to use for our PostType. By convention PostType objects will use a model that matches the upper cased version of the +class name. In the above example the `Bookmarks` model will be used. If our PostType class was named `BlogPosts` your model should be named `BlogPosts` as well. +You can specify the model to using the `model()` method: + +``` +// src/PostType/BookmarksPostType.php +namespace App\PostType; + +use Bakkerij\CakeAdmin\PostType\PostType; + +class BookmarksPostType extends PostType +{ + + public function initialize() { + + $this->model('Bookmarks'); + + } + +} +``` + +The same rule is applied to the name of the PostType and its slug (used in routes). You can define them using the `name()` and `slug()` method: + +``` +// src/PostType/BookmarksPostType.php +namespace App\PostType; + +use Bakkerij\CakeAdmin\PostType\PostType; + +class BookmarksPostType extends PostType +{ + + public function initialize() { + + $this->name('Bookmarks'); // also `alias()` could be used + $this->slug('bookmarks'); + + } + +} +``` + +## Appearance in Menu + +By default the PostTypes appears in CakeAdmin's main menu (on the left). To disable this, use the `menu()` method: + +``` + public function initialize() { + + $this->menu(false); + + } +``` + +## Adding a Description + +To add a description to your PostType, use the `description()` method: + +``` + public function initialize() { + + $this->description('Manages all bookmarks of the application.'); + + } +``` + +## Actions + +By default, the following actions are available: + +- index +- add +- view +- edit +- delete + +To disable or enable any action, you can use the `action()` method: + +``` + public function initialize() { + + // enable + $this->action('index' => true); + + // disable + $this->action('add' => false); + + } +``` + +To get the current state of an action, use the same `action()` method without any argument: + +``` +$state = $this->action('add'); +``` + +To get the state of all actions, use `actions()`: + +``` +$actions = $this->actions(); +``` + +> Note; while Crud is used, at this time it isn't possible yet to customize the `Action` to use. + +## Table Columns + +By default the table (on the index page of the PostType) contains the following columns: + +- primary key (usually `id`) +- display field (given in the Model) +- `created` and `modified` when the `Timestamp` behavior is loaded + +You can choose your own columns using the `tableColumns()` method: + +``` + public function initialize() { + + $this->tableColumns([ + 'id', + 'title', + 'url', + 'created', + 'modified' + ]); + + } +``` + +You can use different getters using the `get` key as option: + +``` +$this->tableColumns([ + 'url' => [ + 'get' => 'customUrl' + ], +]); +``` + +This can be useful when you are using [virtual fields](http://book.cakephp.org/3.0/en/orm/entities.html#creating-virtual-fields). + +## Form Fields + +By default the form (on the add and edit page of the PostType) contains all columns from the table excluding `created` and `modified` when the `Timestamp` behavior +is loaded. + +You can choose your own fields using the `formFields()` method: + +``` + public function initialize() { + + $this->formFields([ + 'id', + 'title', + 'description', + 'created', + 'modified' + ]); + + } +``` + +By default, all fields are presented in both forms: add and edit. To enable fields only on add, or only on edit, use the `on` key as option: + +``` +$this->formFields([ + 'description' => [ + 'on' => 'add' + ], +]); +``` + +In this case, the description field will only be displayed on the add page, and not on the edit page. + +## Filters + +> Note to developers: Not implemented yet. + +## Table Instance + +By default a Table instance is created from the `model()` value, but in case you want to modify the table instance you can modify the Table instance using: + +``` + public function initialize() { + + // get table instance + $table = $this->table(); + + // modify $table + + // set table instance + $this->table($table); + } +``` + +From now on, the modified table instance will be used. + diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 0000000..e43680f --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,68 @@ +Quick Start +=========== + +After the [installation](/installation.html), you are ready to login to your admin panel via `localhost/admin`. + +We will walk through the setup of CakeAdmin + +## CakeAdmin Class + +The `App\CakeAdmin` class is located in your own `src` folder and makes it easier to hook into CakeAdmin. + +According to the [installation](/installation.html) section; you can generate this class using the command: + +``` +$ bin/cake cakeadmin init +``` + +[Read more about the CakeAdmin class here](/cakeadmin-class.html). + +## PostTypes + +PostTypes make managing data very easy. Creating a PostType will give you the basic crud actions to manage your models. For example: + +Create the table `bookmarks` using the following query: + +``` +CREATE TABLE bookmarks ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(50), + description TEXT, + url TEXT, + created DATETIME, + modified DATETIME +); +``` + +Now create your model via the command: + +``` +$ bin/cake bake model Bookmarks +``` + +Now CakeAdmin will join the process using the command: + +``` +$ bin/cake bake post_type Bookmarks +``` + +You can see a new file is created in `src/PostType/BookmarksPostType.php`. This is the PostType `Bookmarks`. + +Now refresh your CakeAdmin dashboard and you will see a new menu item called `Bookmarks`. Click on it and you are able to see all bookmarks, create a new one, +modify existing bookmarks, and delete them. + +Is this it? No! The PostType class we just created is able to manage your custom configurations. + +[Read more about PostTypes here](/posttypes.html). + +## Custom Controllers + +While CakeAdmin has some default controllers and PostTypes in it, we want to give you your freedom to extend CakeAdmin with your own functionality. This can be done +by creating your own custom controllers. To add custom controllers you must apply the following rules: + +- Controller must contain the prefix `Admin` (path would become `/src/Controller/Admin`). +- Controller must depend on CakeAdmin's `Bakkerij/CakeAdmin/Controller/AppController` class. + +> Note to developers: Probably a bake command could be implemented to create this like `cake bake cakeadmin_controller CustomController` + +[Read more about controllers here](/custom-controllers.html). diff --git a/docs/shell-tasks.md b/docs/shell-tasks.md new file mode 100644 index 0000000..d1a6d48 --- /dev/null +++ b/docs/shell-tasks.md @@ -0,0 +1,24 @@ +Shell Tasks +=========== + +The following shell tasks are provided by CakeAdmin: + +### Init + +To initialize CakeAdmin, the following shell command is available: + +``` +$ bin/cake cakeadmin init +``` + +This command will create a `/src/CakeAdmin.php` file. + +### Admin + +To create an administrator user for CakeAdmin, use the `admin` command: + +``` +$ bin/cake cakeadmin admin +``` + +This command will ask for your e-mail and name, and will set the default password `cakeadmin` (you can change this later on). \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bc68448..f4c3e2b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,7 +13,7 @@ - + ./tests/TestCase diff --git a/src/Action/LoginAction.php b/src/Action/LoginAction.php new file mode 100644 index 0000000..532f694 --- /dev/null +++ b/src/Action/LoginAction.php @@ -0,0 +1,93 @@ + true, + 'messages' => [ + 'success' => [ + 'text' => 'Successfully logged you in' + ], + 'error' => [ + 'text' => 'Invalid credentials, please try again' + ] + ], + ]; + + /** + * HTTP GET handler + * + * @return void + */ + protected function _get() + { + $subject = $this->_subject([ + 'success' => true, + ]); + + $this->_trigger('beforeRender', $subject); + } + + /** + * HTTP POST handler + * + * @return \Cake\Network\Response + */ + protected function _post() + { + $subject = $this->_subject(); + + $this->_trigger('beforeLogin', $subject); + + if ($user = $this->_controller()->Auth->identify()) { + return $this->_success($subject, $user); + } + + $this->_error($subject); + } + + /** + * Post success callback + * + * @param \Crud\Event\Subject $subject Event subject. + * @param array $user Authenticated user record data. + * @return \Cake\Network\Response + */ + protected function _success(Subject $subject, array $user) + { + $subject->set(['success' => true, 'user' => $user]); + + $this->_trigger('afterLogin', $subject); + $this->_controller()->Auth->setUser($subject->user); + $this->setFlash('success', $subject); + + return $this->_redirect( + $subject, + $this->_controller()->Auth->redirectUrl() + ); + } + + /** + * Post error callback + * + * @param \Crud\Event\Subject $subject Event subject + * @return void + */ + protected function _error(Subject $subject) + { + $subject->set(['success' => false]); + + $this->_trigger('afterLogin', $subject); + $this->setFlash('error', $subject); + $this->_trigger('beforeRender', $subject); + } +} \ No newline at end of file diff --git a/src/Action/LogoutAction.php b/src/Action/LogoutAction.php new file mode 100644 index 0000000..42722c4 --- /dev/null +++ b/src/Action/LogoutAction.php @@ -0,0 +1,46 @@ + true, + 'messages' => [ + 'success' => [ + 'text' => 'Successfully logged you out' + ], + ] + ]; + + /** + * HTTP GET handler + * + * @return void|\Cake\Network\Response + */ + protected function _get() + { + $subject = $this->_subject(); + $this->_trigger('beforeLogout', $subject); + + $subject->set([ + 'success' => true, + 'redirectUrl' => $this->_controller()->Auth->logout() + ]); + + $this->_trigger('afterLogout', $subject); + $this->setFlash('success', $subject); + + return $this->_redirect( + $subject, + $subject->redirectUrl + ); + } +} \ No newline at end of file diff --git a/src/BaseCakeAdmin.php b/src/BaseCakeAdmin.php new file mode 100644 index 0000000..8525202 --- /dev/null +++ b/src/BaseCakeAdmin.php @@ -0,0 +1,278 @@ +initialize(); + } + + public function initialize() + { + + } + + /** + * Register a PostType + * + * ### Example + * + * ``` + * // App + * $this->registerPostType('Bookmarks'); + * + * // Plugin + * $this->registerPostType('MyPlugin.Bookmarks'); + * ``` + * + * @param string $postType PostType + * @return void + */ + public function registerPostType($postType) + { + PostTypeRegistry::register($postType); + } + + /** + * Register a custom controller + * + * The route of the controller can be parsed in multiple ways. + * Of course, you can parse an array like: + * + * ``` + * $this->addController('Custom Item', [ + * 'controller' => 'Custom', + * 'action' => 'index' + * ]); + * ``` + * + * Another way to parse the route is via a string. Some examples: + * + * ``` + * // Default example + * $this->addController('Custom Item', 'Admin/Custom::index'); + * + * // With plugin + * $this->addController('Custom Item', 'MyPlugin.Admin/Custom::index'); + * + * // Without prefix (Admin) + * $this->addController('Custom Item', 'Custom::index'); + * + * // Without action (default `index`) + * $this->addController('Custom Item', 'Admin/Custom'); + * ``` + * + * @param $alias + * @param $route + */ + public function addController($alias, $route) + { + if (is_string($route)) { + $route = $this->__formatRoute($route); + } + + Configure::write('CA.menu.main', array_merge(Configure::read('CA.menu.main'), [ + $alias => [ + 'uri' => $route + ] + ])); + } + + /** + * Returns a list of events this object is implementing. When the class is registered + * in an event manager, each individual method will be associated with the respective event. + * + * @return array associative array or event key names pointing to the function + * that should be called in the object when the respective event is fired + */ + public function implementedEvents() + { + return [ + 'CakeAdmin.Controller.startup' => 'startup', + 'CakeAdmin.Controller.beforeRedirect' => 'beforeRedirect', + 'CakeAdmin.Controller.beforeFilter' => 'beforeFilter', + 'CakeAdmin.Controller.beforeRender' => 'beforeRender', + 'CakeAdmin.Controller.shutdown' => 'shutdown', + ]; + } + + /** + * Event called method on startup. + * + * @param Event $event Event. + */ + public function startup(Event $event) + { + } + + /** + * Event called method on beforeRedirect. + * + * @param Event $event Event. + */ + public function beforeRedirect(Event $event) + { + } + + /** + * Event called method on beforeFilter. + * + * @param Event $event Event. + */ + public function beforeFilter(Event $event) + { + } + + /** + * Event called method on beforeRender. + * + * @param Event $event Event. + */ + public function beforeRender(Event $event) + { + } + + /** + * Event called method on shutdown. + * + * @param Event $event Event. + */ + public function shutdown(Event $event) + { + } + + /** + * Format route string to an array + * + * ``` + * // Default example + * $this->addController('Custom Item', 'Admin/Custom::index'); + * + * // With plugin + * $this->addController('Custom Item', 'MyPlugin.Admin/Custom::index'); + * + * // Without prefix (Admin) + * $this->addController('Custom Item', 'Custom::index'); + * + * // Without action (default `index`) + * $this->addController('Custom Item', 'Admin/Custom'); + * ``` + * + * @param string $route Route string + * @return array + */ + private function __formatRoute($route) + { + return [ + 'plugin' => $this->__checkForPlugin($route), + 'prefix' => lcfirst($this->__checkForPrefix($route)), + 'controller' => $this->__checkForController($route), + 'action' => $this->__checkForAction($route) ?: 'index' + ]; + } + + /** + * Get the plugin from the route string + * + * @param string $route Route string + * @return bool + */ + private function __checkForPlugin($route) + { + if (strpos($route, '.') !== false) { + $parts = explode('.', $route, 2); + return $parts[0]; + } + + return false; + } + + /** + * Get the prefix from the route string + * + * @param string $route Route string + * @return bool + */ + private function __checkForPrefix($route) + { + if (strpos($route, '.') !== false) { + $parts = explode('.', $route, 2); + $route = $parts[1]; + } + + if (strpos($route, '/') !== false) { + $parts = explode('/', $route, 2); + return $parts[0]; + } + + return false; + } + + /** + * Get the controller from the route string + * + * @param string $route Route string + * @return bool + */ + private function __checkForController($route) + { + if (strpos($route, '.') !== false) { + $parts = explode('.', $route, 2); + $route = $parts[1]; + } + + if (strpos($route, '/') !== false) { + $parts = explode('/', $route, 2); + $route = $parts[1]; + } + + if (strpos($route, '::') !== false) { + $parts = explode('::', $route, 2); + return $parts[0]; + } + + return $route; + } + + /** + * Get the action from the route string + * + * @param string $route Route string + * @return bool + */ + private function __checkForAction($route) + { + if (strpos($route, '.') !== false) { + $parts = explode('.', $route, 2); + $route = $parts[1]; + } + + if (strpos($route, '/') !== false) { + $parts = explode('/', $route, 2); + $route = $parts[1]; + } + + if (strpos($route, '::') !== false) { + $parts = explode('::', $route, 2); + return $parts[1]; + } + + return false; + } + +} \ No newline at end of file diff --git a/src/Controller/Admin/DashboardController.php b/src/Controller/Admin/DashboardController.php index 3b721f8..8e25f37 100644 --- a/src/Controller/Admin/DashboardController.php +++ b/src/Controller/Admin/DashboardController.php @@ -1,39 +1,24 @@ Menu->active('ca.dashboard'); + } + } diff --git a/src/Controller/Admin/NotificationsController.php b/src/Controller/Admin/NotificationsController.php deleted file mode 100644 index 7026829..0000000 --- a/src/Controller/Admin/NotificationsController.php +++ /dev/null @@ -1,50 +0,0 @@ -set('notifications', $this->Notifier->getNotifications()); - $this->Notifier->markAsRead(); - - parent::beforeFilter($event); - } - - /** - * Index action. - * - * @return void - */ - public function index() - { - } -} diff --git a/src/Controller/Admin/PostTypesController.php b/src/Controller/Admin/PostTypesController.php index 7b78317..61b9c18 100644 --- a/src/Controller/Admin/PostTypesController.php +++ b/src/Controller/Admin/PostTypesController.php @@ -1,317 +1,67 @@ loadComponent('Utils.Menu'); - $this->loadComponent('Utils.Search'); - $this->helpers['Utils.Search'] = []; - } + use PostTypesTrait; /** - * beforeFilter event. - * - * @param \Cake\Event\Event $event Event. - * @return void + * @var PostType */ - public function beforeFilter(Event $event) - { - $slug = lcfirst($this->request->params['type']); - - $this->type = $this->PostTypes->getOption($slug); - - if (!$this->type) { - throw new Exception("The PostType is not registered"); - } - - $this->Model = TableRegistry::get($this->type['model']); - - // making the current item active - $this->Menu->active($this->type['alias']); - - parent::beforeFilter($event); - } + protected $postType; /** - * beforeRender event. - * - * @param \Cake\Event\Event $event Event. - * @return void + * @var CrudComponent */ - public function beforeRender(Event $event) - { - parent::beforeRender($event); + protected $Crud; - $this->set('type', $this->type); - $this->set('title', $this->type['name']); - } - - /** - * Index method - * - * @param string $type The requested PostType. - * @return void - */ - public function index($type = null) + public function initialize() { - $this->_validateActionIsEnabled('index'); + parent::initialize(); - $this->_event('beforeIndex'); + $this->postType = PostTypeRegistry::getBySlug($this->request->param('type')); - $this->paginate = [ - 'limit' => 25, - 'order' => [ - ucfirst($this->Model->alias()) . '.id' => 'asc' + $this->loadComponent('Crud.Crud', [ + 'actions' => [ + 'Crud.Index', + 'Crud.View', + 'Crud.Add', + 'Crud.Edit', + 'Crud.Delete' ] - ]; - - foreach ($this->type['filters'] as $key => $value) { - if (is_array($value)) { - $this->Search->addFilter($key, $value); - } else { - $this->Search->addFilter($value); - } - } - - $query = $this->_callQuery($this->Model->find('all')); - $query = $this->Search->search($query); - - $this->set('data', $this->paginate($query)); - - $this->_event('afterIndex'); - } - - /** - * View method - * - * @param string $type The requested PostType. - * @param string|null $id Post Type id - * @return void - */ - public function view($type = null, $id = null) - { - $this->_validateActionIsEnabled('view'); - - $this->_event('beforeView', [ - 'id' => $id - ]); - - $data = $this->Model->get($id, [ - 'contain' => $this->type['contain'] - ]); - $this->set('data', $data); - - $this->_event('afterView', [ - 'id' => $id - ]); - } - - /** - * Add method - * - * @param string $type The requested PostType. - * @return void|\Cake\Network\Response - */ - public function add($type = null) - { - $this->_validateActionIsEnabled('add'); - - $this->_event('beforeAdd'); - - $entity = $this->Model->newEntity()->accessible('*', true); - if ($this->request->is('post')) { - $entity = $this->Model->patchEntity($entity, $this->request->data()); - if ($this->Model->save($entity)) { - $this->Flash->success(__d('CakeAdmin', 'The {0} has been saved.', [$this->type['singularAliasLc']])); - return $this->redirect(['action' => 'index', 'type' => $this->type['name']]); - } else { - $this->Flash->error(__d('CakeAdmin', 'The {0} could not be saved. Please, try again.', [$this->type['singularAliasLc']])); - } - } - - $this->_loadAssociations(); - - $this->set(compact('type', 'entity')); - - $this->_event('afterAdd'); - } - - /** - * Edit method - * - * @param string $type The requested PostType. - * @param string|null $id Post Type id - * @return void|\Cake\Network\Response - * @throws \Cake\Network\Exception\NotFoundException - */ - public function edit($type = null, $id = null) - { - $this->_validateActionIsEnabled('edit'); - - $this->_event('beforeEdit', [ - 'id' => $id ]); - $query = $this->_callQuery($this->Model->findById($id)); - $entity = $query->first(); - - if ($this->request->is(['patch', 'post', 'put'])) { - $entity->accessible('*', true); - $entity = $this->Model->patchEntity($entity, $this->request->data()); - if ($this->Model->save($entity)) { - $this->Flash->success(__d('CakeAdmin', 'The {0} has been edited.', [$this->type['singularAliasLc']])); - return $this->redirect(['action' => 'index', 'type' => $this->type['name']]); - } else { - $this->Flash->error(__d('CakeAdmin', 'The {0} could not be edited. Please, try again.', [$this->type['singularAliasLc']])); - } - } - - $this->_loadAssociations(); - - $this->set(compact('type', 'entity')); - - $this->_event('afterEdit', [ - 'id' => $id - ]); + $this->setPostTypeActions(); + $this->setModelClass(); } - /** - * Delete method - * - * @param string $type The requested PostType. - * @param string|null $id Post Type id - * @return void|\Cake\Network\Response - */ - public function delete($type = null, $id = null) - { - $this->_validateActionIsEnabled('delete'); - - $this->_event('beforeDelete', [ - 'id' => $id - ]); - - $entity = $this->Model->get($id); - - $this->request->allowMethod(['post', 'delete']); - - if ($this->Model->delete($entity)) { - $this->Flash->success(__d('CakeAdmin', 'The {0} has been deleted.', [$this->type['singularAliasLc']])); - } else { - $this->Flash->error(__d('CakeAdmin', 'The {0} could not be deleted. Please, try again.', [$this->type['singularAliasLc']])); - } - - $this->_event('afterDelete', [ - 'id' => $id - ]); - - return $this->redirect(['action' => 'index', 'type' => $this->type['name']]); - } - - /** - * Uses the query-callable from the PostType. - * - * @param Query $query Query object. - * @return Query Query object. - */ - protected function _callQuery($query) - { - $query->contain($this->type['contain']); - $extQuery = $this->type['query']; - return $extQuery($query); - } - - /** - * Dynamically loads all associations of the model. - * - * @return void - */ - protected function _loadAssociations() + public function beforeFilter(Event $event) { - foreach ($this->Model->associations()->getIterator() as $association => $assocData) { - $this->set(Inflector::variable($assocData->alias()), $this->Model->{$association}->find('list')->toArray()); - } - } + $this->Crud->action()->viewVar('items'); - /** - * Validates if the action is enabled. If not an exception will be raised. - * - * @param string $action Chosen action to check on. - * @return void - */ - protected function _validateActionIsEnabled($action) - { - if (!$this->_actionIsEnabled($action)) { - throw new Exception('This action is disabled for the PostType ' . $this->type['alias']); - } + parent::beforeFilter($event); } - /** - * Checks if the action is enabled. - * - * @param string $action Chosen action to check on. - * @return bool - */ - protected function _actionIsEnabled($action) + public function beforeRender(Event $event) { - $actions = $this->type['actions']; + $this->viewBuilder()->helpers(['Bakkerij/CakeAdmin.PostType' => [ + 'data' => $this->postType + ]]); - if (array_key_exists($action, $actions)) { - return $actions[$action]; - } - return true; + parent::beforeRender($event); } - /** - * Fires an event with the PostType-prefix. - * - * @param string $action Current action. - * @param array $data data that should be sent with the event. - * @return void - */ - protected function _event($action, $data = []) - { - $_event = new Event('Controller.PostTypes.' . $this->type['name'] . '.' . $action, $this, $data); - $this->eventManager()->dispatch($_event); - } } diff --git a/src/Controller/Admin/SettingsController.php b/src/Controller/Admin/SettingsController.php deleted file mode 100644 index 9b722fa..0000000 --- a/src/Controller/Admin/SettingsController.php +++ /dev/null @@ -1,116 +0,0 @@ -loadModel('Settings.Configurations'); - - $this->prefixes = Configure::read('Settings.Prefixes'); - - $this->Menu->active('ca.settings'); - $this->Menu->area('navbar'); - - foreach ($this->prefixes as $prefix => $alias) { - $this->Menu->add($alias, [ - 'url' => [ - 'action' => 'index', $prefix, - ] - ]); - } - } - - /** - * index action - * - * Shows all settings with the specific prefix. - * - * @param string $key The prefix. - * @return void|\Cake\Network\Respose - * @throws NotFoundException - */ - public function index($key = null) - { - if (!$key) { - $key = 'App'; - } - $this->Menu->active($this->prefixes[$key]); - - if (!$this->__prefixExists($key)) { - throw new NotFoundException("The prefix-setting " . $key . " could not be found"); - } - - $prefix = Hash::get($this->prefixes, ucfirst($key)); - - $settings = $this->Configurations->find('all')->where([ - 'name LIKE' => $key . '%', - 'editable' => 1, - ])->order(['weight', 'id']); - - if ($this->request->is(['patch', 'post', 'put'])) { - $settings = $this->Configurations->patchEntities($settings, $this->request->data); - foreach ($settings as $setting) { - $this->Flash->success('The settings has been saved.'); - if (!$this->Configurations->save($setting)) { - $this->Flash->error('The settings could not be saved. Please, try again.'); - } - } - Setting::clear(true); - Setting::autoLoad(); - return $this->redirect([]); - } - - $this->set(compact('prefix', 'settings')); - } - - /** - * Checks if a prefix exists. - * - * @param string $prefix The prefix. - * @return bool - */ - protected function __prefixExists($prefix) - { - if (Hash::get($this->prefixes, ucfirst($prefix)) == null) { - return false; - } - - return true; - } -} diff --git a/src/Controller/Admin/UsersController.php b/src/Controller/Admin/UsersController.php index 0d019bc..7acdf60 100644 --- a/src/Controller/Admin/UsersController.php +++ b/src/Controller/Admin/UsersController.php @@ -1,24 +1,7 @@ Auth->allow([ - 'forgot', - 'reset', - 'login' - ]); - - $this->loadModel('CakeAdmin.Administrators'); - } - - /** - * Login action - * - * Login action for administrators. Here you are able to login into your admin-panel. - * - * @return \Cake\Network\Response|void - */ - public function login() - { - if ($this->authUser) { - return $this->redirect($this->Auth->redirectUrl()); - } + $this->Auth->allow(['logout']); - if ($this->request->is('post')) { - $user = $this->Auth->identify(); - if ($user) { - $user['CakeAdmin'] = $user; - $this->Auth->setUser($user); - return $this->redirect($this->Auth->redirectUrl()); - } - $this->Flash->error(__d('CakeAdmin', 'Invalid username or password, try again')); - } else { - $this->request->data['email'] = $this->request->query('email'); - } - } - - /** - * Logout action - * - * Via this action you will be logged out and redirected to the login-page. - * - * @return \Cake\Network\Response|void - */ - public function logout() - { - $this->Flash->success(__d('CakeAdmin', 'You are now logged out.')); - return $this->redirect($this->Auth->logout()); - } - - /** - * Forgot password action - * - * Via this action you are able to request a new password. - * After the post it will send a mail with a link. - * This link will redirect to the action 'reset'. - * - * This action always gives a success-message. - * That's because else hackers (or other bad-guys) will be able - * to see if an e-mail is registered or not. - * - * @return void|\Cake\Network\Response - */ - public function forgot() - { - // Redirect if user is already logged in - if ($this->authUser) { - return $this->redirect('/login'); - } - - $this->Flash->success(__d('CakeAdmin', 'Check your e-mail to change your password.')); - - if ($this->request->is('post')) { - $user = $this->Administrators->findByEmail($this->request->data('email')); - if ($user->count()) { - $user = $user->first(); - $user->set('request_key', $this->Administrators->generateRequestKey()); - if ($this->Users->save($user)) { - $event = new Event('Controller.Admin.Users.afterForgotPassword', $this, [ - 'user' => $user - ]); - EventManager::instance()->dispatch($event); - - $this->getMailer('CakeAdmin.CakeAdmin')->send('resetPassword', [$user]); - - return $this->redirect($this->Auth->config('loginAction') + ['email' => $user->email]); - } - } + $this->loadComponent('Crud.Crud', [ + 'actions' => [ + 'login' => 'Bakkerij/CakeAdmin.Login', + 'logout' => 'Bakkerij/CakeAdmin.Logout' + ] + ]); - return $this->redirect($this->Auth->config('loginAction')); - } } - /** - * Reset password action - * - * Users will reach this action when they need to set a new password for their account. - * This action will set a new password and redirect to the login page - * - * @param string $email The e-mailaddress from the user. - * @param string $requestKey The refering activation key. - * @return void|\Cake\Network\Response - */ - public function reset($email, $requestKey = null) - { - // Redirect if user is already logged in - if ($this->authUser) { - $this->Flash->error(__d('CakeAdmin', 'Your account could not be reset.')); - return $this->redirect($this->Auth->config('loginAction') + ['email' => $email]); - } - - // If the email and key doesn't match - if (!$this->Administrators->validateRequestKey($email, $requestKey)) { - $this->Flash->error(__d('CakeAdmin', 'Your account could not be reset.')); - return $this->redirect($this->Auth->config('loginAction') + ['email' => $email]); - } - - // If we passed and the POST isset - if ($this->request->is('post')) { - $user = $this->Administrators->find()->where([ - 'email' => $email, - 'request_key' => $requestKey, - ])->first(); - - if ($user) { - $user = $this->Administrators->patchEntity($user, $this->request->data); - $user->set('active', 1); - $user->set('request_key', null); - - if ($this->Administrators->save($user)) { - $this->Flash->success(__d('CakeAdmin', 'Your password has been changed.')); - return $this->redirect($this->Auth->config('loginAction') + ['email' => $email]); - } - } - $this->Flash->error(__d('CakeAdmin', 'Your account could not be activated.')); - } - } } diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index ca1f5d6..ae292bd 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -1,27 +1,19 @@ initializeCakeAdmin(); + $this->loadComponent('Flash'); - $this->loadComponent('CakeAdmin.CakeAdmin'); + $this->loadComponent('Gourmet/KnpMenu.Menu'); + + $this->loadComponent('Bakkerij/CakeAdmin.CakeAdmin'); $this->loadComponent('Auth', [ 'authorize' => ['Controller'], 'authenticate' => [ 'Basic' => [ - 'userModel' => 'CakeAdmin.Administrators' + 'userModel' => 'Bakkerij/CakeAdmin.Administrators' ], 'Form' => [ - 'userModel' => 'CakeAdmin.Administrators', + 'userModel' => 'Bakkerij/CakeAdmin.Administrators', 'fields' => Configure::read('CA.fields'), - 'scope' => ['Administrators.cakeadmin' => true] + 'scope' => ['Administrators.active' => true] ], ], 'loginAction' => [ 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', + 'plugin' => 'Bakkerij/CakeAdmin', 'controller' => 'Users', 'action' => 'login' ], 'loginRedirect' => [ 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', + 'plugin' => 'Bakkerij/CakeAdmin', 'controller' => 'Dashboard', 'action' => 'index' ], 'logoutRedirect' => [ 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', + 'plugin' => 'Bakkerij/CakeAdmin', 'controller' => 'Users', 'action' => 'login' ] ]); - $this->Auth->sessionKey = 'Auth.CakeAdmin'; - $this->authUser = $this->Auth->user(); - - $this->loadComponent('Utils.GlobalAuth'); - $this->loadComponent('Csrf'); - $this->loadComponent('Utils.Menu'); - $this->loadComponent('CakeAdmin.PostTypes'); - $this->loadComponent('Notifier.Notifier'); - - $event = new Event('CakeAdmin.Controller.afterInitialize', $this); - EventManager::instance()->dispatch($event); + $this->Auth->__set('sessionKey', 'Auth.CakeAdmin'); } /** - * beforeFilter event. - * - * @param Event $event Event. - * @return void - */ - public function beforeFilter(Event $event) - { - $this->viewBuilder()->className(Configure::read('CA.viewClass'))->theme(Configure::read('CA.theme')); - - if ($this->authUser) { - $this->viewBuilder()->layout(Configure::read('CA.layout.default')); - } else { - $this->viewBuilder()->layout(Configure::read('CA.layout.login')); - } - - $this->_addNotificationMenu(); - - $event = new Event('CakeAdmin.Controller.beforeFilter', $this); - EventManager::instance()->dispatch($event); - } - - /** - * beforeRender event. - * - * @param Event $event Event. - * @return void - */ - public function beforeRender(Event $event) - { - $this->set('authUser', $this->authUser); - $this->set('title', $this->name); - - $event = new Event('CakeAdmin.Controller.beforeRender', $this); - EventManager::instance()->dispatch($event); - } - - /** - * authorizes every administrator on every action. + * Authorizes every administrator on every action. * * @param array $user User to authorize. * @return bool @@ -128,99 +77,27 @@ public function isAuthorized($user = null) return true; } - /** - * Initializes all admin menu-items. - * - * @return void - */ - public function initMenuItems() + public function beforeFilter(Event $event) { - $this->Menu->area('headerLeft'); - - $this->Menu->add('ca.user', [ - 'title' => $this->authUser[Configure::read('CA.fields.username')], - 'url' => '#' - ]); + $this->CakeAdmin->loadPostTypesFromConfig(); - $this->Menu->add('ca.logout', [ - 'parent' => 'ca.user', - 'title' => __d('CakeAdmin', 'Logout'), - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'Users', - 'action' => 'logout', - ] - ]); + $this->buildMenu(); - $this->Menu->area('main'); - - $this->Menu->add('ca.dashboard', [ - 'title' => __d('CakeAdmin', 'Dashboard'), - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'Dashboard', - 'action' => 'index', - ], - 'weight' => 0, - ]); + $this->__trigger('CakeAdmin.Controller.beforeFilter'); + } - $this->Menu->add('ca.settings', [ - 'title' => __d('CakeAdmin', 'Settings'), - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'Settings', - 'action' => 'index', - ], - 'weight' => 50 + public function beforeRender(Event $event) + { + $this->viewBuilder()->helpers([ + 'Gourmet/KnpMenu.Menu' ]); - foreach (Configure::read('CA.Menu.main') as $key => $value) { - $this->Menu->add($key, $value); - } + $this->__trigger('CakeAdmin.Controller.beforeRender'); } - /** - * Adds the notification-menu-item to the header menu. - * - * @return void - */ - protected function _addNotificationMenu() + public function afterFilter(Event $event) { - $this->Menu->area('headerLeft'); - - $this->Menu->add('notifier.notifications', [ - 'title' => __d('CakeAdmin', 'Notifications ({0})', $this->Notifier->countNotifications(null, true)), - 'url' => '#', - 'weight' => 5 - ]); - - $notifications = $this->Notifier->getNotifications(null, true); - - foreach ($notifications as $not) { - $this->Menu->add('notifier.notifications.' . $not->id, [ - 'parent' => 'notifier.notifications', - 'title' => $not->title, - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'Notifications', - 'action' => 'index' - ] - ]); - } - - $this->Menu->add('notifier.notifications.url', [ - 'parent' => 'notifier.notifications', - 'title' => '> ' . __d('CakeAdmin', 'All Notifications'), - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'Notifications', - 'action' => 'index' - ] - ]); + $this->__trigger('CakeAdmin.Controller.shutdown'); } + } diff --git a/src/Controller/CakeAdminTrait.php b/src/Controller/CakeAdminTrait.php new file mode 100644 index 0000000..a7a527b --- /dev/null +++ b/src/Controller/CakeAdminTrait.php @@ -0,0 +1,79 @@ +eventManager()->on($init); + } + + $this->__trigger('CakeAdmin.Controller.startup'); + } + + public function buildMenu() + { + /** @var MenuItem $menu */ + $menu = $this->Menu->get('cakeadmin_main'); + + $menu->addChild('Dashboard', ['uri' => [ + 'plugin' => 'Bakkerij/CakeAdmin', + 'prefix' => 'admin', + 'controller' => 'Dashboard', + 'action' => 'index' + ]]); + + $this->addPostTypesToMenu(); + + $this->addConfigurationsToMenu(); + } + + public function addPostTypesToMenu() + { + /** @var MenuItem $menu */ + $menu = $this->Menu->get('cakeadmin_main'); + + $postTypes = PostTypeRegistry::getAll(); + + foreach ($postTypes as $postType) { + $menu->addChild($postType->name(), ['uri' => [ + 'plugin' => 'Bakkerij/CakeAdmin', + 'prefix' => 'admin', + 'controller' => 'PostTypes', + 'action' => 'index', + 'type' => $postType->slug() + ]]); + } + } + + public function addConfigurationsToMenu() + { + /** @var MenuItem $menu */ + $menu = $this->Menu->get('cakeadmin_main'); + + $configurations = (array) Configure::read('CA.menu.main'); + + foreach($configurations as $label => $options) { + $menu->addChild($label, $options); + } + } + + private function __trigger($event, array $data = []) + { + $event = new Event($event, $this, $data); + $this->eventManager()->dispatch($event); + } +} \ No newline at end of file diff --git a/src/Controller/Component/CakeAdminComponent.php b/src/Controller/Component/CakeAdminComponent.php index 6949339..0bd66a5 100644 --- a/src/Controller/Component/CakeAdminComponent.php +++ b/src/Controller/Component/CakeAdminComponent.php @@ -1,28 +1,17 @@ Controller = $this->_registry->getController(); - - $this->_setRecipientList(); - } - - /** - * setController - * - * Setter for the Controller property. - * - * @param \Cake\Controller\Controller $controller Controller. - * @return void - */ - public function setController($controller) - { - $this->Controller = $controller; - } - - /** - * Returns a list of administrators. - * - * @param null $field Non-required field, if empty all data will be returned. - * @return array|string - */ - public function administrators($field = null) + public function loadPostTypesFromConfig() { - $model = TableRegistry::get('CakeAdmin.Administrators'); + $list = (array) Configure::read('CA.postTypes'); - $query = $model->find('all'); - - if ($field) { - $model->displayField($field); - $query->find('list'); - } - - $result = $query->toArray(); - - return $result; - } - - /** - * Checks if an administrator is logged in. - * - * @return bool - */ - public function isLoggedIn() - { - $session = $this->Controller->request->session(); - if ($session->check('Auth.CakeAdmin')) { - return (bool)$session->read('Auth.CakeAdmin'); + foreach($list as $key => $value) { + PostTypeRegistry::register($key, $value); } - return false; - } - - /** - * Returns the logged in administrator. - * Will return `false` when there'se no session. - * - * @return bool - */ - public function authUser() - { - $session = $this->Controller->request->session(); - if ($session->check('Auth.CakeAdmin')) { - return $session->read('Auth.CakeAdmin'); - } - return false; - } - - /** - * Sets the recipient-list in the NotificationManager to notify all administrators very easily. - * Administrators will be available under the list called `administrators`. - * - * @return void - */ - protected function _setRecipientList() - { - NotificationManager::instance()->addRecipientList( - 'administrators', - TableRegistry::get('CakeAdmin.Administrators')->find('list')->toArray() - ); } } diff --git a/src/Controller/Component/PostTypesComponent.php b/src/Controller/Component/PostTypesComponent.php deleted file mode 100644 index 39cd8c9..0000000 --- a/src/Controller/Component/PostTypesComponent.php +++ /dev/null @@ -1,425 +0,0 @@ - [ - 'ignoredColumns' => [ - 'password' - ], - 'max' => 2 - ], - 'form' => [ - 'ignoredFields' => [ - 'created_by', - 'modified_by', - 'created', - 'modified' - ] - ] - ]; - - /** - * Controller - * - * @var Controller - */ - public $controller = null; - - /** - * Initialize component. - * - * @param array $config Configuration. - * @return void - */ - public function initialize(array $config) - { - $this->setController($this->_registry->getController()); - - $this->_registerPostTypesFromConfigure(); - - $this->_addMenuItems(); - } - - /** - * setController - * - * Setter for the Controller property. - * - * @param \Cake\Controller\Controller $controller Controller. - * @return void - */ - public function setController($controller) - { - $this->Controller = $controller; - } - - /** - * beforeFilter - * - * BeforeFilter event. - * - * @param \Cake\Event\Event $event Event. - * @return void - */ - public function beforeFilter($event) - { - } - - /** - * beforeRender - * - * beforeRender event. - * - * @param \Cake\Event\Event $event Event. - * @return void - */ - public function beforeRender($event) - { - } - - /** - * register - * - * Registers a new PostType. - * The default options will be merged with the given options. - * After that, the type will be saved in the Configure-class. - * - * @param string $model Model to make a PostType off. - * @param array $options Options. - * @return void - */ - public function register($model, $options = []) - { - $postTypes = Configure::read('CA.PostTypes'); - - $_defaults = [ - 'model' => $model, - 'menu' => true, - 'menuWeight' => 20, - 'slug' => lcfirst(Inflector::slug(pluginSplit($model)[1])), - 'name' => ucfirst(Inflector::slug(pluginSplit($model)[1])), - 'alias' => ucfirst(Inflector::humanize(pluginSplit($model)[1])), - 'aliasLc' => lcfirst(Inflector::humanize(pluginSplit($model)[1])), - 'singularAlias' => ucfirst(Inflector::singularize(Inflector::humanize(pluginSplit($model)[1]))), - 'singularAliasLc' => lcfirst(Inflector::singularize(Inflector::humanize(pluginSplit($model)[1]))), - 'description' => null, - 'actions' => [ - 'index' => true, - 'add' => true, - 'edit' => true, - 'view' => true, - 'delete' => true, - ], - 'filters' => [], - 'contain' => [], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => false, - 'formFields' => false, - ]; - $options = array_merge($_defaults, $options); - - if (!$options['tableColumns']) { - $options['tableColumns'] = $this->_generateTableColumns($model); - } - if (!$options['formFields']) { - $options['formFields'] = $this->_generateFormFields($model); - } - - # model is able to disable the PostType to register by returning false - $modelOptions = $this->_getOptionsFromModel($options['model']); - if ($modelOptions === false) { - return; - } - $options = array_merge($options, $modelOptions); - - if ($options['formFields']) { - $options['formFields'] = $this->_normalizeFormFields($options['formFields']); - } - - if ($options['tableColumns']) { - $options['tableColumns'] = $this->_normalizeTableColumns($options['tableColumns']); - } - - $postTypes[$options['slug']] = $options; - - Configure::write('CA.PostTypes', $postTypes); - } - - /** - * getOption - * - * Return single option, or all options per PostType. - * - * @param string $name Name of the PostType. - * @param string $option String of the named option. - * @return array|bool - */ - public function getOption($name, $option = null) - { - $postTypes = Configure::read('CA.PostTypes'); - - if (array_key_exists($name, $postTypes)) { - if ($option) { - if (array_key_exists($option, $postTypes[$name])) { - return $postTypes[$name][$option]; - } - } - return $postTypes[$name]; - } - return false; - } - - /** - * getFormFields - * - * Returns a list with the formfields of the type. - * - * @param string $name Name of the PostType. - * @return void - */ - public function getFormFields($name) - { - } - - /** - * getTableColumns - * - * Returns a list with the tablecolumns of the type. - * - * @param string $name Name of the PostType. - * @return void - */ - public function getTableColumns($name) - { - } - - /** - * _addMenuItems - * - * Adds menu-items of every PostType to the 'main' menu. - * - * @return void - */ - protected function _addMenuItems() - { - $postTypes = Configure::read('CA.PostTypes'); - - $this->Controller->Menu->area('main'); - - foreach ($postTypes as $name => $options) { - if ($options['menu']) { - $this->Controller->Menu->add($options['alias'], [ - 'url' => [ - 'prefix' => 'admin', - 'plugin' => 'CakeAdmin', - 'controller' => 'PostTypes', - 'action' => 'index', - 'type' => $options['slug'] - ], - 'weight' => $options['menuWeight'] - ]); - } - } - } - - /** - * _getOptionsFromModel - * - * Returns a list of options token from the model. - * - * @param string $model The model to use. - * @return array|null|bool - */ - protected function _getOptionsFromModel($model) - { - $model = TableRegistry::get($model); - - if (method_exists($model, 'postType')) { - $result = $model->postType(); - if ($result) { - $result['table'] = $model->table(); - } - return $result; - } - if (property_exists($model, 'postType')) { - $result = $model->postType; - if ($result) { - $result['table'] = $model->table(); - } - return $result; - } - return []; - } - - /** - * _registerPostTypesFromConfigure - * - * Registers the PostTypes added via the Configure-class. - * The PostType should be added via `CA.Models`. - * - * @return void - */ - protected function _registerPostTypesFromConfigure() - { - $configure = Configure::read('CA.Models'); - - foreach ($configure as $name => $model) { - $this->register($model); - } - } - - /** - * If no tablecolumns are given, this method will be called to generate a list of tablecolumns. - * - * @param \Cake\ORM\Table $model Model to rely on. - * @return array - */ - protected function _generateTableColumns($model) - { - $model = TableRegistry::get($model); - $columns = ConnectionManager::get('default')->schemaCollection()->describe($model->table())->columns(); - - $result = []; - $counter = 0; - $max = 2; - - if (in_array('id', $columns)) { - $result['id'] = []; - unset($columns['id']); - } - - foreach ($columns as $column) { - if ($counter < $max) { - $result[$column] = []; - unset($columns[$column]); - $counter++; - } - } - - if (in_array('created', $columns)) { - $result['created'] = []; - } - - return $result; - } - - /** - * If no formfields are given, this method will be called to generate a list of formfields. - * - * @param \Cake\ORM\Table $model Model to rely on. - * @return array - */ - protected function _generateFormFields($model) - { - $model = TableRegistry::get($model); - $columns = ConnectionManager::get('default')->schemaCollection()->describe($model->table())->columns(); - - $ignoredFields = [ - 'created', - 'modified', - 'created_by', - 'modified_by', - 'password' - ]; - - $result = []; - - foreach ($columns as $column) { - if (!in_array($column, $ignoredFields)) { - $result[$column] = []; - } - } - return $result; - } - - /** - * Normalizes the formfields-array. - * - * @param array $fields Fields to normalize. - * @return array - */ - protected function _normalizeFormFields($fields) - { - $_options = [ - 'on' => 'both' - ]; - - $_defaults = [ - '_create' => $_options - ]; - - $result = []; - - $result['_create'] = $_defaults['_create']; - - foreach ($fields as $name => $options) { - if (is_array($options)) { - $result[$name] = array_merge($_options, $options); - } else { - $result[$options] = $_options; - } - } - return $result; - } - - /** - * Normalizes the tablecolumns-array. - * - * @param array $columns Columns to normalize. - * @return array - */ - protected function _normalizeTableColumns($columns) - { - $_defaults = [ - 'get' => false, - 'before' => '', - 'after' => '', - ]; - $result = []; - - foreach ($columns as $name => $options) { - if (is_array($options)) { - $_defaults['get'] = $name; - $result[$name] = array_merge($_defaults, $options); - } else { - $_defaults['get'] = $options; - $result[$options] = $_defaults; - } - } - return $result; - } -} diff --git a/src/Controller/PostTypesTrait.php b/src/Controller/PostTypesTrait.php new file mode 100644 index 0000000..100812a --- /dev/null +++ b/src/Controller/PostTypesTrait.php @@ -0,0 +1,27 @@ +postType->actions(); + + foreach($actions as $action => $state) { + if($state) { + $this->Crud->enable($action); + } else { + $this->Crud->disable($action); + } + } + } + + public function setModelClass() + { + $this->modelClass = $this->postType->model(); + } + +} \ No newline at end of file diff --git a/src/Locale/CakeAdmin.pot b/src/Locale/CakeAdmin.pot deleted file mode 100644 index e77ee50..0000000 --- a/src/Locale/CakeAdmin.pot +++ /dev/null @@ -1,169 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"POT-Creation-Date: 2016-02-16 00:52+0000\n" -"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" -"Last-Translator: NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: Controller/AppController.php:148 -msgid "Logout" -msgstr "" - -#: Controller/AppController.php:160 -msgid "Dashboard" -msgstr "" - -#: Controller/AppController.php:171 -msgid "Settings" -msgstr "" - -#: Controller/AppController.php:196 -msgid "Notifications ({0})" -msgstr "" - -#: Controller/AppController.php:218 -msgid "All Notifications" -msgstr "" - -#: Controller/Admin/PostTypesController.php:166 -msgid "The {0} has been saved." -msgstr "" - -#: Controller/Admin/PostTypesController.php:169 -msgid "The {0} could not be saved. Please, try again." -msgstr "" - -#: Controller/Admin/PostTypesController.php:203 -msgid "The {0} has been edited." -msgstr "" - -#: Controller/Admin/PostTypesController.php:206 -msgid "The {0} could not be edited. Please, try again." -msgstr "" - -#: Controller/Admin/PostTypesController.php:239 -msgid "The {0} has been deleted." -msgstr "" - -#: Controller/Admin/PostTypesController.php:241 -msgid "The {0} could not be deleted. Please, try again." -msgstr "" - -#: Controller/Admin/UsersController.php:70 -msgid "Invalid username or password, try again" -msgstr "" - -#: Controller/Admin/UsersController.php:85 -msgid "You are now logged out." -msgstr "" - -#: Controller/Admin/UsersController.php:109 -msgid "Check your e-mail to change your password." -msgstr "" - -#: Controller/Admin/UsersController.php:146;152 -msgid "Your account could not be reset." -msgstr "" - -#: Controller/Admin/UsersController.php:169 -msgid "Your password has been changed." -msgstr "" - -#: Controller/Admin/UsersController.php:173 -msgid "Your account could not be activated." -msgstr "" - -#: Mailer/CakeAdminMailer.php:51 -msgid "Forgot Password" -msgstr "" - -#: Model/Table/AdministratorsTable.php:57 -msgid "Administrators" -msgstr "" - -#: Model/Table/AdministratorsTable.php:58 -msgid "administrators" -msgstr "" - -#: Model/Table/AdministratorsTable.php:59 -msgid "Administrator" -msgstr "" - -#: Model/Table/AdministratorsTable.php:60 -msgid "administrator" -msgstr "" - -#: Model/Table/AdministratorsTable.php:118;130 -msgid "Passwords are not equal." -msgstr "" - -#: Template/Admin/PostTypes/index.ctp:37 -msgid "previous" -msgstr "" - -#: Template/Admin/PostTypes/index.ctp:39 -msgid "next" -msgstr "" - -#: Template/Admin/Settings/index.ctp:25 -#: View/Helper/PostTypesHelper.php:364 -msgid "Submit" -msgstr "" - -#: Template/Admin/Users/forgot.ctp:5 -#: Template/Admin/Users/login.ctp:31 -msgid "Forgot password" -msgstr "" - -#: Template/Admin/Users/forgot.ctp:8 -msgid "Request" -msgstr "" - -#: Template/Admin/Users/login.ctp:18;25;29 -msgid "Login" -msgstr "" - -#: Template/Admin/Users/reset.ctp:5 -msgid "New Password" -msgstr "" - -#: Template/Admin/Users/reset.ctp:9 -msgid "Save" -msgstr "" - -#: Template/Layout/default.ctp:56 -msgid "Menu" -msgstr "" - -#: View/Helper/PostTypesHelper.php:202 -msgid "Actions" -msgstr "" - -#: View/Helper/PostTypesHelper.php:243 -msgid "View" -msgstr "" - -#: View/Helper/PostTypesHelper.php:244 -msgid "Edit" -msgstr "" - -#: View/Helper/PostTypesHelper.php:245 -msgid "Delete" -msgstr "" - -#: View/Helper/PostTypesHelper.php:282 -msgid "Are you sure you want to delete # {0}?" -msgstr "" - -#: View/Helper/PostTypesHelper.php:328 -msgid "Add " -msgstr "" diff --git a/src/Locale/pt_BR/CakeAdmin.po b/src/Locale/pt_BR/CakeAdmin.po deleted file mode 100644 index e4658e5..0000000 --- a/src/Locale/pt_BR/CakeAdmin.po +++ /dev/null @@ -1,168 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# -msgid "" -msgstr "" -"Project-Id-Version: CakeAdmin 1\n" -"POT-Creation-Date: 2016-02-15 22:53-0200\n" -"PO-Revision-Date: 2016-02-15 22:58-0200\n" -"Last-Translator: NAME \n" -"Language-Team: LANGUAGE \n" -"Language: pt_BR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 1.8.7\n" - -#: Controller/AppController.php:148 -msgid "Logout" -msgstr "Sair" - -#: Controller/AppController.php:160 -msgid "Dashboard" -msgstr "Resumo" - -#: Controller/AppController.php:171 -msgid "Settings" -msgstr "Configurações" - -#: Controller/AppController.php:196 -msgid "Notifications ({0})" -msgstr "Notificações ({0})" - -#: Controller/AppController.php:218 -msgid "All Notifications" -msgstr "Todas Notificações" - -#: Controller/Admin/PostTypesController.php:166 -msgid "The {0} has been saved." -msgstr "{0} foi salvo." - -#: Controller/Admin/PostTypesController.php:169 -msgid "The {0} could not be saved. Please, try again." -msgstr "{0} não foi salvo. Tente novamente." - -#: Controller/Admin/PostTypesController.php:203 -msgid "The {0} has been edited." -msgstr "{0} foi editado." - -#: Controller/Admin/PostTypesController.php:206 -msgid "The {0} could not be edited. Please, try again." -msgstr "{0} não foi editado. Tente novamente." - -#: Controller/Admin/PostTypesController.php:239 -msgid "The {0} has been deleted." -msgstr "{0} foi removido." - -#: Controller/Admin/PostTypesController.php:241 -msgid "The {0} could not be deleted. Please, try again." -msgstr "{0} não foi removido. Tente novamente." - -#: Controller/Admin/UsersController.php:70 -msgid "Invalid username or password, try again" -msgstr "Usuário ou senha inválidos. Tente novamente." - -#: Controller/Admin/UsersController.php:85 -msgid "You are now logged out." -msgstr "Você saiu do sistema." - -#: Controller/Admin/UsersController.php:109 -msgid "Check your e-mail to change your password." -msgstr "Verifique seu e-mail para mudar a senha." - -#: Controller/Admin/UsersController.php:146;152 -msgid "Your account could not be reset." -msgstr "Sua conta não pode ser recuperada." - -#: Controller/Admin/UsersController.php:169 -msgid "Your password has been changed." -msgstr "Sua senha foi alterada." - -#: Controller/Admin/UsersController.php:173 -msgid "Your account could not be activated." -msgstr "Sua conta não pode ser ativada." - -#: Mailer/CakeAdminMailer.php:51 -msgid "Forgot Password" -msgstr "Esqueci a senha" - -#: Model/Table/AdministratorsTable.php:57 -msgid "Administrators" -msgstr "Administradores" - -#: Model/Table/AdministratorsTable.php:58 -msgid "administrators" -msgstr "administradores" - -#: Model/Table/AdministratorsTable.php:59 -msgid "Administrator" -msgstr "Administrador" - -#: Model/Table/AdministratorsTable.php:60 -msgid "administrator" -msgstr "administrador" - -#: Model/Table/AdministratorsTable.php:118;130 -msgid "Passwords are not equal." -msgstr "As senhas não são iguais" - -#: Template/Admin/PostTypes/index.ctp:37 -msgid "previous" -msgstr "anterior" - -#: Template/Admin/PostTypes/index.ctp:39 -msgid "next" -msgstr "próximo" - -#: Template/Admin/Settings/index.ctp:25 View/Helper/PostTypesHelper.php:364 -msgid "Submit" -msgstr "Enviar" - -#: Template/Admin/Users/forgot.ctp:5 Template/Admin/Users/login.ctp:31 -msgid "Forgot password" -msgstr "Esqueci a senha" - -#: Template/Admin/Users/forgot.ctp:8 -msgid "Request" -msgstr "Solicitar" - -#: Template/Admin/Users/login.ctp:18;25;29 -msgid "Login" -msgstr "Entrar" - -#: Template/Admin/Users/reset.ctp:5 -msgid "New Password" -msgstr "Nova Senha" - -#: Template/Admin/Users/reset.ctp:9 -msgid "Save" -msgstr "Salvar" - -#: Template/Layout/default.ctp:56 -msgid "Menu" -msgstr "Menu" - -#: View/Helper/PostTypesHelper.php:202 -msgid "Actions" -msgstr "Ações" - -#: View/Helper/PostTypesHelper.php:243 -msgid "View" -msgstr "Visualizar" - -#: View/Helper/PostTypesHelper.php:244 -msgid "Edit" -msgstr "Editar" - -#: View/Helper/PostTypesHelper.php:245 -msgid "Delete" -msgstr "Remover" - -#: View/Helper/PostTypesHelper.php:282 -msgid "Are you sure you want to delete # {0}?" -msgstr "Você tem certeza que deseja remover #{0}?" - -#: View/Helper/PostTypesHelper.php:328 -msgid "Add " -msgstr "Adicionar " diff --git a/src/Mailer/CakeAdminMailer.php b/src/Mailer/CakeAdminMailer.php deleted file mode 100644 index c9451e6..0000000 --- a/src/Mailer/CakeAdminMailer.php +++ /dev/null @@ -1,54 +0,0 @@ -domain($fullBaseUrl); - - $this->viewVars([ - 'user' => $user, - 'resetUrl' => $fullBaseUrl . '/admin/users/reset/' . $user['email'] . '/' . $user['request_key'], - 'baseUrl' => $fullBaseUrl, - 'loginUrl' => $fullBaseUrl . '/admin', - 'from' => reset($from), - ]); - - $this->template('CakeAdmin.resetPassword', 'CakeAdmin.default'); - $this->emailFormat('both'); - $this->from($from); - $this->to($user['email']); - $this->subject(__d('CakeAdmin', 'Forgot Password')); - $this->transport(Configure::read('CA.email.transport')); - } -} diff --git a/src/Model/Entity/Administrator.php b/src/Model/Entity/Administrator.php index 94a80f0..1fa3369 100644 --- a/src/Model/Entity/Administrator.php +++ b/src/Model/Entity/Administrator.php @@ -1,23 +1,20 @@ true, - 'password' => true, - 'new_password' => true, - 'confirm_password' => true, - 'activation_key' => true, + '*' => true, + 'id' => false ]; /** @@ -52,7 +50,7 @@ protected function _setPassword($password) } /** - * Fields that should be hidden. + * Fields that are excluded from JSON versions of the entity. * * @var array */ diff --git a/src/Model/Table/AdministratorsTable.php b/src/Model/Table/AdministratorsTable.php index 2d2468e..90f5e7b 100644 --- a/src/Model/Table/AdministratorsTable.php +++ b/src/Model/Table/AdministratorsTable.php @@ -1,29 +1,25 @@ table('users'); - $this->displayField('id'); - $this->primaryKey('id'); - $this->addBehavior('Timestamp'); + parent::initialize($config); - $this->addBehavior('Utils.IsOwnedBy', [ - 'column' => 'id' - ]); - } + $this->table('cakeadmin_administrators'); + $this->displayField('name'); + $this->primaryKey('id'); - /** - * Configures the PostType for CakeAdmin. - * - * @return array - */ - public function postType() - { - return [ - 'alias' => __d('CakeAdmin', 'Administrators'), - 'aliasLc' => __d('CakeAdmin', 'administrators'), - 'singularAlias' => __d('CakeAdmin', 'Administrator'), - 'singularAliasLc' => __d('CakeAdmin', 'administrator'), - 'formFields' => [ - 'email', - 'new_password' => [ - 'type' => 'password', - ], - 'confirm_password' => [ - 'type' => 'password' - ] - ], - 'tableColumns' => [ - 'id', - 'email', - 'created', - ], - 'filters' => [ - 'email' - ], - ]; + $this->addBehavior('Timestamp'); } /** @@ -87,47 +50,26 @@ public function postType() public function validationDefault(Validator $validator) { $validator - ->add('id', 'valid', ['rule' => 'numeric']) + ->uuid('id') ->allowEmpty('id', 'create'); $validator - ->add('email', 'valid', ['rule' => 'email']) - ->notEmpty('email'); + ->requirePresence('name', 'create') + ->notEmpty('name'); $validator - ->notEmpty('password'); + ->email('email') + ->allowEmpty('email'); $validator - ->allowEmpty('new_password'); - - - $validator - ->allowEmpty('confirm_password'); + ->allowEmpty('password'); $validator - ->add('new_password', 'custom', [ - 'rule' => function ($value, $context) { - if (!array_key_exists('confirm_password', $context['data'])) { - return false; - } - if ($value !== $context['data']['confirm_password']) { - return false; - } - return true; - }, - 'message' => __d('CakeAdmin', 'Passwords are not equal.')]); + ->integer('cakeadmin') + ->allowEmpty('cakeadmin'); $validator - ->add('confirm_password', 'custom', ['rule' => function ($value, $context) { - if (!array_key_exists('new_password', $context['data'])) { - return false; - } - if ($value !== $context['data']['new_password']) { - return false; - } - return true; - }, - 'message' => __d('CakeAdmin', 'Passwords are not equal.')]); + ->allowEmpty('request_key'); return $validator; } @@ -142,107 +84,7 @@ public function validationDefault(Validator $validator) public function buildRules(RulesChecker $rules) { $rules->add($rules->isUnique(['email'])); - return $rules; - } - - /** - * beforeFind event. - * - * @param \Cake\Event\Event $event Event. - * @param \Cake\ORM\Query $query Query. - * @param array $options Options. - * @param bool $primary Primary. - * @return void - */ - public function beforeFind($event, $query, $options, $primary) - { - $query->where(['Administrators.cakeadmin' => true]); - } - - /** - * beforeSave event - * - * @param \Cake\Event\Event $event Event. - * @param \Cake\ORM\Entity $entity Entity. - * @param array $options Options. - * @return void - */ - public function beforeSave($event, $entity, $options) - { - $entity->set('cakeadmin', true); - $newPassword = $entity->get('new_password'); - - if (!empty($newPassword)) { - $entity->set('password', $entity->new_password); // set for password-changes - } - } - - /** - * afterSave event - * - * @param \Cake\Event\Event $event Event. - * @param \Cake\ORM\Entity $entity Entity. - * @param array $options Options. - * @return void - */ - public function afterSave($event, $entity, $options) - { - if ($entity->isNew()) { - NotificationManager::instance()->notify([ - 'recipientLists' => ['administrators'], - 'template' => 'newAdministrator', - 'vars' => [ - 'email' => $entity->get('email'), - 'created' => $entity->get('created'), - ] - ]); - } - } - - /** - * generateRequestKey - * - * This method generates a request key for an user. - * It returns a generated string. - * - * @return string - */ - public function generateRequestKey() - { - $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $charactersLength = strlen($characters); - $requestKey = ''; - for ($i = 0; $i < 40; $i++) { - $requestKey .= $characters[rand(0, $charactersLength - 1)]; - } - return $requestKey; - } - - /** - * validateRequestKey - * - * Checks if an user is allowed to do an action with a required activation-key - * - * @param string $email E-mailaddress of the user. - * @param string $requestKey Activation key of the user. - * @return bool - */ - public function validateRequestKey($email, $requestKey = null) - { - if (!$requestKey) { - return false; - } - - $field = Configure::read('CA.fields.username'); - $query = $this->find('all')->where([ - $field => $email, - 'request_key' => $requestKey - ]); - - if ($query->Count() > 0) { - return true; - } - return false; + return $rules; } } diff --git a/src/PostType/AdministratorsPostType.php b/src/PostType/AdministratorsPostType.php new file mode 100644 index 0000000..acc0fbb --- /dev/null +++ b/src/PostType/AdministratorsPostType.php @@ -0,0 +1,29 @@ +name('Administrators'); + $this->slug('administrators'); + + $this->model('Bakkerij/CakeAdmin.Administrators'); + + $this->tableColumns([ + 'name', + 'email', + 'active', + 'created', + 'modified' + ]); + } + +} \ No newline at end of file diff --git a/src/PostType/Exception/MissingPostTypeException.php b/src/PostType/Exception/MissingPostTypeException.php new file mode 100644 index 0000000..fd1205a --- /dev/null +++ b/src/PostType/Exception/MissingPostTypeException.php @@ -0,0 +1,14 @@ + true, + 'view' => true, + 'add' => true, + 'edit' => true, + 'delete' => true + ]; + + /** + * Table columns + * + * @var array + */ + protected $_columns; + + /** + * Form fields + * + * @var array + */ + protected $_fields; + + /** + * PostType constructor. + */ + public function __construct() + { + + $this->initialize(); + } + + /** + * Initialize the PostType. + * + * This method can be overridden in the PostType implementation. + * + * @return void + */ + public function initialize() + { + } + + /** + * Returns the model name or sets a new one + * + * @param string|null $model Model name. + * @return string + */ + public function model($model = null) + { + if ($model) { + $this->_model = $model; + } + return $this->_model; + } + + /** + * Returns the name or sets a new one + * + * @param string|null $name Name. + * @return string + */ + public function name($name = null) + { + if ($name) { + $this->_name = $name; + } + if(!$this->_name) { + $this->_name = $this->table()->alias(); + } + return $this->_name; + } + + /** + * Returns the alias or sets a new one + * + * @param string|null $alias Alias. + * @return string + */ + public function alias($alias = null) + { + return $this->name($alias); + } + + /** + * Returns the PostType slug or sets a new one + * + * @param string|null $slug Slug + * @return string + */ + public function slug($slug = null) + { + if($slug) { + $this->_slug = Text::slug($slug); + } + if(!$this->_slug) { + $this->_slug = Text::slug($this->name()); + } + return $this->_slug; + } + + /** + * Returns the menu state or sets a new one + * + * If the PostType should not be presented in the menu, + * the value should be `false`. Default `true`. + * + * @param bool|null $menu Menu state + * @return bool + */ + public function menu($menu = null) + { + if($menu) { + $this->_menu = (bool) $menu; + } + if(!$this->_menu) { + $this->_menu = true; + } + return $this->_menu; + } + + /** + * Returns the description or sets a new one + * + * @param string|null $description Description + * @return bool|null|string + */ + public function description($description = null) + { + if($description) { + $this->_description = $description; + } + if(!$this->_description) { + $this->_description = true; + } + return $this->_description; + } + + /** + * Returns the action state or sets a new one + * + * @param string $action Action name like `index` or `add` + * @param bool|null $enabled State of action like `true` or `false` + * @return bool + */ + public function action($action, $enabled = null) + { + if(is_array($action)) { + foreach($action as $key => $value) { + $this->action($key, $value); + } + } + + if($enabled !== null) { + $this->_actions[$action] = (bool) $enabled; + } + if(!array_key_exists($action, $this->_actions)) { + $this->_actions[$action] = true; + } + return $this->_actions[$action]; + } + + /** + * Returns list of actions. Actions can be set using `actions()` + * + * @return array + */ + public function actions() + { + return $this->_actions; + } + + /** + * Returns the filters or sets a new one + * + * @return void + */ + public function filter() + { + throw new Exception("Not implemented yet"); + } + + /** + * Returns the tables columns or sets new one + * + * @param array|null $columns Columns + * @return array + */ + public function tableColumns(array $columns = null) + { + if($columns) { + $this->_columns = $this->_normalizeTableColumns($columns); + } + if(!$this->_columns) { + $this->_columns = $this->_generateTableColumns(); + } + return $this->_columns; + } + + /** + * Returns the forms fields or sets new one + * + * @param array|null $fields Fields + * @return array + */ + public function formFields(array $fields = null) + { + if($fields) { + $this->_fields = $this->_normalizeFormFields($fields); + } + if(!$this->_fields) { + $this->_fields = $this->_generateFormFields(); + } + return $this->_fields; + } + + /** + * Returns the table instance or sets a new one + * + * @param Table|null $table Table + * @return Table + */ + public function table($table = null) + { + if($table) { + $this->_table = $table; + } + if(!$this->_table) { + $this->_table = TableRegistry::get($this->model()); + } + return $this->_table; + } + + /** + * Normalizes array with table columns. + * + * @param array $columns Columns to normalize. + * @return array + */ + protected function _normalizeTableColumns($columns) + { + $_defaults = [ + 'get' => false, + 'before' => '', + 'after' => '', + ]; + $result = []; + foreach ($columns as $name => $options) { + if (is_array($options)) { + $_defaults['get'] = $name; + $result[$name] = array_merge($_defaults, $options); + } else { + $_defaults['get'] = $options; + $result[$options] = $_defaults; + } + } + return $result; + } + + /** + * Normalizes array with form fields. + * + * @param array $fields Fields to normalize. + * @return array + */ + protected function _normalizeFormFields($fields) + { + $_options = [ + 'on' => 'both' + ]; + $_defaults = [ + '_create' => $_options + ]; + $result = []; + $result['_create'] = $_defaults['_create']; + foreach ($fields as $name => $options) { + if (is_array($options)) { + $result[$name] = array_merge($_options, $options); + } else { + $result[$options] = $_options; + } + } + return $result; + } + + /** + * Generates an array with table columns from the model. + * + * @return array + */ + protected function _generateTableColumns() + { + $table = $this->table(); + $schema = $table->schema(); + + $columns = []; + + $pk = $schema->primaryKey(); + $columns[] = reset($pk); + $columns[] = $table->displayField(); + + if($table->hasBehavior('Timestamp')) { + if($schema->column('created')) { + $columns[] = 'created'; + } + if($schema->column('modified')) { + $columns[] = 'modified'; + } + } + + return $this->_normalizeTableColumns($columns); + } + + /** + * Generates an array with form fields from the model. + * + * @return array + */ + protected function _generateFormFields() + { + $table = $this->table(); + $schema = $table->schema(); + + $fields = $schema->columns(); + + return $this->_normalizeFormFields($fields); + } + +} \ No newline at end of file diff --git a/src/PostType/PostTypeRegistry.php b/src/PostType/PostTypeRegistry.php new file mode 100644 index 0000000..68ba26a --- /dev/null +++ b/src/PostType/PostTypeRegistry.php @@ -0,0 +1,74 @@ + Inflector::pluralize($class)]); + } + + $transformer = App::className(Inflector::pluralize($className), 'PostType', 'PostType'); + + if ($transformer === false) { + throw new MissingPostTypeException(['posttype' => Inflector::pluralize($className)]); + } + + return new $transformer; + } + + public static function getBySlug($slug) + { + $all = self::getAll(); + + foreach($all as $class => $type) { + if($type->slug() === $slug) { + return self::get($class); + } + } + + throw new MissingPostTypeException(['posttype' => $slug]); + } + + /** + * @return PostType[] + */ + public static function getAll() + { + $list = (array)self::$list; + + $all = []; + + foreach($list as $class) { + $all[$class] = self::get($class); + } + + return $all; + } + +} \ No newline at end of file diff --git a/src/Shell/CainstallShell.php b/src/Shell/CainstallShell.php deleted file mode 100644 index 32cc80b..0000000 --- a/src/Shell/CainstallShell.php +++ /dev/null @@ -1,85 +0,0 @@ -out('Migrating CakeAdmin Tables...'); - $this->migrate('CakeAdmin'); - $this->out('Migrating CakeAdmin Tables completed!'); - $this->hr(); - - // Notifier Migration - $this->out('Migrating Notifier Tables...'); - $this->migrate('Notifier'); - $this->out('Migrating Notifier Tables completed!'); - $this->hr(); - - // Settings Migration - $this->out('Migrating Settings Tables...'); - $this->migrate('Settings'); - $this->out('Migrating Settings Tables completed!'); - $this->hr(); - - $createAdmin = $this->in('Do you want to create your first administrator?', ['Y', 'n'], 'Y'); - - if ($createAdmin === 'Y') { - $this->out('Generating a new administrator...'); - $this->dispatchShell('admin'); - } - } - - /** - * Migrates the given plugin. - * - * @param string $plugin Plugin name. - * @return bool - */ - protected function migrate($plugin) - { - $migrations = new Migrations(); - - return $migrations->migrate(['plugin' => $plugin]); - } - - /** - * Checks if the table exists. - * - * @param string $table Plugin name. - * @return bool - */ - protected function _tableExists($table) - { - $db = ConnectionManager::get('default'); - $tables = $db->schemaCollection()->listTables(); - - return in_array($table, $tables); - } -} diff --git a/src/Shell/CakeadminShell.php b/src/Shell/CakeadminShell.php new file mode 100644 index 0000000..f83d8bf --- /dev/null +++ b/src/Shell/CakeadminShell.php @@ -0,0 +1,54 @@ +addSubcommand('init', [ + 'help' => 'Initialize CakeAdmin. Will create a base CakeAdmin.php file', + 'parser' => $this->Admin->getOptionParser(), + ]); + $parser->addSubcommand('admin', [ + 'help' => 'Create CakeAdmin Administrator', + 'parser' => $this->Admin->getOptionParser(), + ]); + + return $parser; + } + + /** + * main() method. + * + * @return bool|int Success or error code. + */ + public function main() + { + $this->out($this->OptionParser->help()); + } +} diff --git a/src/Shell/AdminShell.php b/src/Shell/Task/AdminTask.php similarity index 50% rename from src/Shell/AdminShell.php rename to src/Shell/Task/AdminTask.php index 6ebd4d7..0f40add 100644 --- a/src/Shell/AdminShell.php +++ b/src/Shell/Task/AdminTask.php @@ -1,42 +1,35 @@ in('E-mailaddress:'); + $email = $this->in('E-mail:'); + + $password = 'cakeadmin'; + $this->out('Password will be `cakeadmin`. You can change this later'); - $password = $this->in('Password: [WILL BE VISIBLE]'); + $name = $this->in('Name:'); - $this->loadModel('CakeAdmin.Administrators'); + $this->loadModel('Bakkerij/CakeAdmin.Administrators'); $entity = $this->Administrators->newEntity([ 'email' => $email, - 'password' => $password + 'password' => $password, + 'name' => $name, + 'active' => 1 ]); if ($this->Administrators->save($entity)) { diff --git a/src/Shell/Task/InitTask.php b/src/Shell/Task/InitTask.php new file mode 100644 index 0000000..60d073a --- /dev/null +++ b/src/Shell/Task/InitTask.php @@ -0,0 +1,24 @@ +createFile(APP . DS . 'CakeAdmin.php', file_get_contents($file)); + } +} diff --git a/src/Shell/Task/PostTypeTask.php b/src/Shell/Task/PostTypeTask.php new file mode 100644 index 0000000..217964d --- /dev/null +++ b/src/Shell/Task/PostTypeTask.php @@ -0,0 +1,82 @@ +BakeTemplate->set('ptname', $this->ptname($name)); + $this->BakeTemplate->set('ptslug', $this->ptslug($name)); + $this->BakeTemplate->set('ptmodel', $this->ptmodel($name)); + + parent::main($name); + } + + /** + * Get the generated object's name. + * + * @return string + */ + public function name() + { + return 'postType'; + } + + /** + * Get the generated object's filename without the leading path. + * + * @param string $name The name of the object being generated + * @return string + */ + public function fileName($name) + { + return $name . 'PostType.php'; + } + + /** + * Get the template name. + * + * @return string + */ + public function template() + { + return 'Bakkerij/CakeAdmin.postType'; + } + + public function ptname($name) + { + return Inflector::humanize($name); + } + + public function ptslug($name) + { + return Inflector::dasherize(Text::slug($name)); + } + + public function ptmodel($name) + { + $model = Inflector::pluralize($name); + + if ($this->param('plugin')) { + $model = $this->param('plugin') . '.' . $model; + } + + return $model; + } +} \ No newline at end of file diff --git a/src/Template/Admin/Dashboard/index.ctp b/src/Template/Admin/Dashboard/index.ctp index d46d675..350e101 100644 --- a/src/Template/Admin/Dashboard/index.ctp +++ b/src/Template/Admin/Dashboard/index.ctp @@ -1,28 +1,10 @@ -set('title', 'Dashboard'); -?> - -

Dashboard

- -
-
- cell('CakeAdmin.Dashboard::welcome') ?> -
+ +
+

- -
-
- cell('CakeAdmin.Dashboard::gettingStarted') ?> - cell('CakeAdmin.Dashboard::plugins'); ?> - cell('CakeAdmin.Dashboard::gettingHelp'); ?> -
-
- cell('CakeAdmin.Dashboard::latestPosts'); ?> -
-
- -
-
- cell('CakeAdmin.Dashboard::aboutUs') ?> -
-
\ No newline at end of file diff --git a/src/Template/Admin/Notifications/index.ctp b/src/Template/Admin/Notifications/index.ctp deleted file mode 100644 index 2ac32da..0000000 --- a/src/Template/Admin/Notifications/index.ctp +++ /dev/null @@ -1,19 +0,0 @@ - - -
    -
  • - unread): echo ''; endif; ?> - get('title')) ?> - unread): echo ''; endif; ?> -
      -
    • get('body')) ?>
    • -
    • get('created')->timeAgoInWords([ - 'accuracy' => ['month' => 'month'], - 'end' => '1 year' - ])) ?>
    • -
    -
  • -
- \ No newline at end of file diff --git a/src/Template/Admin/PostTypes/add.ctp b/src/Template/Admin/PostTypes/add.ctp index 4d41afa..d064de7 100644 --- a/src/Template/Admin/PostTypes/add.ctp +++ b/src/Template/Admin/PostTypes/add.ctp @@ -1,31 +1,10 @@ -PostTypes->type($type); -?> - -PostTypes->header() ?> - -PostTypes->indexButton() ?> - -
-PostTypes->createForm($entity) ?> -
- PostTypes->fieldset([ - 'on' => ['both', 'add'] - ]) ?> -
-PostTypes->submitForm() ?> -PostTypes->endForm() ?> + +
+

PostType->name('singular')]) ?>

+
diff --git a/src/Template/Admin/PostTypes/edit.ctp b/src/Template/Admin/PostTypes/edit.ctp index 8da4d55..17f3e8e 100644 --- a/src/Template/Admin/PostTypes/edit.ctp +++ b/src/Template/Admin/PostTypes/edit.ctp @@ -1,32 +1,10 @@ -PostTypes->type($type); -?> - -PostTypes->header() ?> - -PostTypes->indexButton() ?> - -
-PostTypes->createForm($entity) ?> -
- PostTypes->fieldset([ - 'label' => 'Edit ', - 'on' => ['both', 'edit'] - ]) ?> -
-PostTypes->submitForm() ?> -PostTypes->endForm() ?> + +
+

PostType->name('singular')]) ?>

+
diff --git a/src/Template/Admin/PostTypes/index.ctp b/src/Template/Admin/PostTypes/index.ctp index b542e35..e13f6a7 100644 --- a/src/Template/Admin/PostTypes/index.ctp +++ b/src/Template/Admin/PostTypes/index.ctp @@ -1,42 +1,49 @@ - +
    +
  • -$this->PostTypes->type($type); -$this->PostTypes->data($data); -?> - -PostTypes->header() ?> - -PostTypes->addButton() ?> + Menu->render('cakeadmin_main'); ?> +
+ +
+

PostType->name('plural')]) ?>

-
-PostTypes->searchFilter($searchFilters) ?> + + + + PostType->tableColumns() as $column => $options): ?> + + + + + + + + + PostType->tableColumns() as $column => $options): ?> + + + + + + +
Paginator->sort($column) ?>
get($options['get'])) ?> + PostType->viewLink($item) ?> + PostType->editLink($item) ?> + PostType->deleteLink($item) ?> +
+
+
    + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> +
+

Paginator->counter() ?>

+
- - - PostTypes->tableHead() ?> - - - PostTypes->tableBody() ?> - -
-
-
    - Paginator->prev('< ' . __d('CakeAdmin', 'previous')); ?> - Paginator->numbers(); ?> - Paginator->next(__d('CakeAdmin', 'next') . ' >'); ?> -
-

Paginator->counter(); ?>

-
\ No newline at end of file + + + + + +
diff --git a/src/Template/Admin/PostTypes/view.ctp b/src/Template/Admin/PostTypes/view.ctp index b6020bb..f7ce131 100644 --- a/src/Template/Admin/PostTypes/view.ctp +++ b/src/Template/Admin/PostTypes/view.ctp @@ -1,5 +1,13 @@ - +
    +
  • -debug($type); + Menu->render('cakeadmin_main'); ?> +
+ +
+

PostType->name('singular')]) ?>

-?> \ No newline at end of file + + +
diff --git a/src/Template/Admin/Settings/index.ctp b/src/Template/Admin/Settings/index.ctp deleted file mode 100644 index 1a48db8..0000000 --- a/src/Template/Admin/Settings/index.ctp +++ /dev/null @@ -1,27 +0,0 @@ -

- -Menu->menu('navbar', 'CakeAdmin.NavbarMenu') ?> - -Form->create(); - -foreach ($settings as $id => $setting) { - - echo $this->Form->input($id . '.id', [ - 'type' => 'hidden', - 'value' => $setting->id, - ]); - - $name = explode('.', $setting->name); - - echo $this->Form->input($id . '.value', [ - 'type' => (($setting->type) ? $setting->type : 'text'), - 'label' => ucfirst(end($name)) . (($setting->description) ? ' - ' . $setting->description : ''), - 'options' => (($setting->options) ? $setting->options : ''), - 'value' => $setting->value, - ]); -} - -echo $this->Form->button(__d('CakeAdmin', 'Submit')); - -echo $this->Form->end(); \ No newline at end of file diff --git a/src/Template/Admin/Users/forgot.ctp b/src/Template/Admin/Users/forgot.ctp deleted file mode 100644 index d929883..0000000 --- a/src/Template/Admin/Users/forgot.ctp +++ /dev/null @@ -1,11 +0,0 @@ -
- Flash->render('auth') ?> - Form->create() ?> -
- - Form->input('email') ?> -
- Form->button(__d('CakeAdmin', 'Request')); ?> - Form->end() ?> - Html->link('Login', ['action' => 'login']); ?> -
\ No newline at end of file diff --git a/src/Template/Admin/Users/login.ctp b/src/Template/Admin/Users/login.ctp index 7ac6ee1..1dd7c0d 100644 --- a/src/Template/Admin/Users/login.ctp +++ b/src/Template/Admin/Users/login.ctp @@ -1,32 +1,23 @@ set('title', __d('CakeAdmin', 'Login')); - ?> -
- Flash->render('auth') ?> - Form->create() ?> -
- - Form->input(Configure::read('CA.fields.username')) ?> - Form->input(Configure::read('CA.fields.password'), ['value' => '']) ?> -
- Form->button(__d('CakeAdmin', 'Login')); ?> - Form->end() ?> - Html->link(__d('CakeAdmin', 'Forgot password'), ['action' => 'forgot']); ?> + + +
+

+
+ Flash->render('auth') ?> + Form->create() ?> +
+ + Form->input(Configure::read('CA.fields.username')) ?> + Form->input(Configure::read('CA.fields.password'), ['value' => '']) ?> +
+ Form->button(__d('CakeAdmin', 'Login')); ?> + Form->end() ?> + Html->link(__d('CakeAdmin', 'Forgot password'), ['action' => 'forgot']); ?> +
diff --git a/src/Template/Admin/Users/reset.ctp b/src/Template/Admin/Users/reset.ctp deleted file mode 100644 index 363e292..0000000 --- a/src/Template/Admin/Users/reset.ctp +++ /dev/null @@ -1,11 +0,0 @@ -
- Flash->render('auth') ?> - Form->create() ?> -
- - Form->input('new_password', ['type' => 'password', 'value' => '']) ?> - Form->input('confirm_password', ['type' => 'password', 'value' => '']) ?> -
- Form->button(__d('CakeAdmin', 'Save')); ?> - Form->end() ?> -
\ No newline at end of file diff --git a/src/Template/Bake/post_type.ctp b/src/Template/Bake/post_type.ctp new file mode 100644 index 0000000..e54a929 --- /dev/null +++ b/src/Template/Bake/post_type.ctp @@ -0,0 +1,21 @@ +\PostType; + +use Bakkerij\CakeAdmin\PostType\PostType; + +/** + * <%= $name %> PostType + */ +class <%= $name %>PostType extends PostType +{ + + public function initialize() + { + $this->name('<%= $ptname %>'); + $this->slug('<%= $ptslug %>'); + + $this->model('<%= $ptmodel %>'); + } + +} \ No newline at end of file diff --git a/src/Template/Cell/Dashboard/about_us.ctp b/src/Template/Cell/Dashboard/about_us.ctp deleted file mode 100644 index c7b7962..0000000 --- a/src/Template/Cell/Dashboard/about_us.ctp +++ /dev/null @@ -1,3 +0,0 @@ -

About Us

-DEVELOPERS DEVELOPERS DEVELOPERS -
\ No newline at end of file diff --git a/src/Template/Cell/Dashboard/getting_help.ctp b/src/Template/Cell/Dashboard/getting_help.ctp deleted file mode 100644 index 59ffeaa..0000000 --- a/src/Template/Cell/Dashboard/getting_help.ctp +++ /dev/null @@ -1,14 +0,0 @@ -

Getting Help

-
    - $item): ?> - -
  • - -
      -
    • -
    -
  • - - -
-
\ No newline at end of file diff --git a/src/Template/Cell/Dashboard/getting_started.ctp b/src/Template/Cell/Dashboard/getting_started.ctp deleted file mode 100644 index 7724ce0..0000000 --- a/src/Template/Cell/Dashboard/getting_started.ctp +++ /dev/null @@ -1,14 +0,0 @@ -

Getting Started

-
    - $item): ?> - -
  • - -
      -
    • -
    -
  • - - -
-
\ No newline at end of file diff --git a/src/Template/Cell/Dashboard/latest_posts.ctp b/src/Template/Cell/Dashboard/latest_posts.ctp deleted file mode 100644 index 21f8dc0..0000000 --- a/src/Template/Cell/Dashboard/latest_posts.ctp +++ /dev/null @@ -1,22 +0,0 @@ - -

Latest Posts

-
    - -
  • - -
      - -
    • timeAgoInWords() ?>
    • -
    -
  • - - -
-
-Read more at cakemanager.org. -

- -
\ No newline at end of file diff --git a/src/Template/Cell/Dashboard/plugins.ctp b/src/Template/Cell/Dashboard/plugins.ctp deleted file mode 100644 index d059e56..0000000 --- a/src/Template/Cell/Dashboard/plugins.ctp +++ /dev/null @@ -1,14 +0,0 @@ -

Useful Plugins from the CakeManager Team

-
    - $item): ?> - -
  • - -
      -
    • -
    -
  • - - -
-
\ No newline at end of file diff --git a/src/Template/Cell/Dashboard/welcome.ctp b/src/Template/Cell/Dashboard/welcome.ctp deleted file mode 100644 index 394ec53..0000000 --- a/src/Template/Cell/Dashboard/welcome.ctp +++ /dev/null @@ -1,5 +0,0 @@ -

-

- The CakeManager Plugin allows you to easily manage your website. The CakeManager Team provides you with many useful plugins for CakePHP 3.x. -

-
\ No newline at end of file diff --git a/src/Template/Email/html/reset_password.ctp b/src/Template/Email/html/reset_password.ctp deleted file mode 100644 index 0cf4c90..0000000 --- a/src/Template/Email/html/reset_password.ctp +++ /dev/null @@ -1,25 +0,0 @@ -

- Hello email ?>, -

- -

- You've got this e-mail because you lost your password at .
- Via the following url you will be able to set a new password: Reset new Password. -

- -

- After you've chosen your new password you are able to login at: . -

- - -

- If you didn't request a new password, you can ignore this e-mail and continue your account at . -

- -

- Greetz, -

- -

- -

\ No newline at end of file diff --git a/src/Template/Email/text/reset_password.ctp b/src/Template/Email/text/reset_password.ctp deleted file mode 100644 index 9176777..0000000 --- a/src/Template/Email/text/reset_password.ctp +++ /dev/null @@ -1,12 +0,0 @@ -Hello email ?>, - -You've got this e-mail because you lost your password at . -Via the following url you will be able to set a new password: . - -After you've chosen your new password you are able to login at: . - -If you didn't request a new password, you can ignore this e-mail and continue your account at . - -Greetz, - - diff --git a/src/Template/Layout/Email/html/default.ctp b/src/Template/Layout/Email/html/default.ctp deleted file mode 100644 index 3b28b4c..0000000 --- a/src/Template/Layout/Email/html/default.ctp +++ /dev/null @@ -1,9 +0,0 @@ - - - - <?= $this->fetch('title') ?> - - -fetch('content') ?> - - \ No newline at end of file diff --git a/src/Template/Layout/Email/text/default.ctp b/src/Template/Layout/Email/text/default.ctp deleted file mode 100644 index ac2bcf1..0000000 --- a/src/Template/Layout/Email/text/default.ctp +++ /dev/null @@ -1,16 +0,0 @@ - -fetch('content') ?> diff --git a/src/Template/Layout/default.ctp b/src/Template/Layout/default.ctp deleted file mode 100644 index bb49069..0000000 --- a/src/Template/Layout/default.ctp +++ /dev/null @@ -1,71 +0,0 @@ -assign('title', $title); -?> - - - - Html->charset() ?> - - - <?= $this->fetch('title') ?> - - Html->meta('icon') ?> - - Html->css('CakeAdmin.base') ?> - Html->css('CakeAdmin.cake') ?> - Html->css('CakeAdmin.custom') ?> - - fetch('meta') ?> - fetch('css') ?> - fetch('script') ?> - - -
-
- fetch('title') ?> - - Menu->menu('headerLeft', 'CakeAdmin.HeaderLeftMenu') ?> - -
- -
-
- -
- Flash->render() ?> - -
-
-

-
    - Menu->menu('main', 'CakeAdmin.MainMenu') ?> -
-
- -
- fetch('content') ?> -
-
-
-
-
-
- - diff --git a/src/Template/Layout/login.ctp b/src/Template/Layout/login.ctp deleted file mode 100644 index 69da831..0000000 --- a/src/Template/Layout/login.ctp +++ /dev/null @@ -1,61 +0,0 @@ -assign('title', $title); -?> - - - - Html->charset() ?> - - - <?= $this->fetch('title') ?> - - Html->meta('icon') ?> - - Html->css('CakeAdmin.base') ?> - Html->css('CakeAdmin.cake') ?> - Html->css('CakeAdmin.custom') ?> - - fetch('meta') ?> - fetch('css') ?> - fetch('script') ?> - - -
-
- fetch('title') ?> -
- -
-
- -
- Flash->render() ?> - -
-
- fetch('content') ?> -
-
-
-
-
-
- - diff --git a/src/View/Cell/DashboardCell.php b/src/View/Cell/DashboardCell.php deleted file mode 100644 index 1a52214..0000000 --- a/src/View/Cell/DashboardCell.php +++ /dev/null @@ -1,155 +0,0 @@ -set('welcome', "Welcome to your CakeAdmin admin panel."); - } - - /** - * Latest Posts method. - * - * @return void - */ - public function latestPosts() - { - $rss = file_get_contents('http://cakemanager.org/rss', false); - - if ($rss) { - $xml = Xml::toArray(Xml::build($rss)); - $data = $xml['rss']['channel']['item']; - } - - $this->set('posts', (isset($data) ? $data : [])); - } - - /** - * Getting Started method - * - * @return void - */ - public function gettingStarted() - { - $links = [ - 'CakeManager Docs' => [ - 'url' => 'http://cakemanager.org/docs/cakeadmin/1.0/', - 'description' => 'Documentation about the CakeAdmin Plugin.' - ], - 'Quick Start Tutorial' => [ - 'url' => 'http://cakemanager.org/docs/cakeadmin/1.0/tutorials-and-examples/quick-start/', - 'description' => 'Short tutorial about how to install the CakeAdmin Plugin', - ] - ]; - - $this->set('list', $links); - } - - /** - * Getting Help method - * - * @return void - */ - public function gettingHelp() - { - $links = [ - 'CakeManager Website' => [ - 'url' => 'http://cakemanager.org/', - 'description' => 'Website of the CakeManager Team. Here you can find everything about us and our plugins.' - ], - 'Gitter' => [ - 'url' => 'https://gitter.im/cakemanager/cakephp-cakeadmin', - 'description' => 'Chat Tool for GitHub to talk about issues and new features.', - ], - 'GitHub' => [ - 'url' => 'https://github.com/cakemanager/cakephp-cakeadmin/issues', - 'description' => 'When there\'s something wrong, please open a new issue!', - ], - 'CakeAdmin Docs' => [ - 'url' => 'http://cakemanager.org/docs/cakeadmin/1.0/', - 'description' => 'Documentation about the CakeAdmin Plugin.', - ], - 'CakePHP Utils Plugin Docs' => [ - 'url' => 'http://cakemanager.org/docs/utils/1.0/', - 'description' => 'Documentation about the Utils Plugin.', - ], - ]; - - $this->set('list', $links); - } - - /** - * Plugins method - * - * @return void - */ - public function plugins() - { - $links = [ - 'Utils' => [ - 'url' => 'https://github.com/cakemanager/cakephp-utils', - 'description' => 'Utilities for Cake 3.x.' - ], - 'Notifier' => [ - 'url' => 'https://github.com/cakemanager/cakephp-notifier', - 'description' => 'Notification plugin for Cake 3.x' - ], - 'Who Is Online' => [ - 'url' => 'https://github.com/cakemanager/cakephp-whosonline', - 'description' => 'Plugin to follow your users on your app.' - ], - 'PostTypes' => [ - 'url' => 'https://github.com/cakemanager/cakephp-posttypes', - 'description' => 'Plugin to create dynamic CRUD for your admin-panel.' - ], - 'Settings' => [ - 'url' => 'https://github.com/cakemanager/cakephp-settings', - 'description' => 'Plugin to save settings in your database and manage them.' - ], - ]; - - $this->set('list', $links); - } - - /** - * About Us method - * - * @return void - */ - public function aboutUs() - { - } -} diff --git a/src/View/Helper/HeaderLeftMenuHelper.php b/src/View/Helper/HeaderLeftMenuHelper.php deleted file mode 100644 index fff2e30..0000000 --- a/src/View/Helper/HeaderLeftMenuHelper.php +++ /dev/null @@ -1,159 +0,0 @@ -' . $item['title'] . ''; - - return $html; - } - - /** - * item - * - * Method to build an submenu item. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function subItem($item = [], $options = []) - { - return ''; - } - - /** - * beforeItem - * - * Method before an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function beforeItem($item = [], $options = []) - { - return ''; - } - - /** - * afterItem - * - * Method after an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function afterItem($item = [], $options = []) - { - return ''; - } -} diff --git a/src/View/Helper/MainMenuHelper.php b/src/View/Helper/MainMenuHelper.php deleted file mode 100644 index 323ed7f..0000000 --- a/src/View/Helper/MainMenuHelper.php +++ /dev/null @@ -1,158 +0,0 @@ -' . - $this->Html->link($item['title'], $item['url']) . ''; - return $html; - } - - /** - * item - * - * Method to build an submenu item. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function subItem($item = [], $options = []) - { - return ''; - } - - /** - * beforeItem - * - * Method before an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function beforeItem($item = [], $options = []) - { - return ''; - } - - /** - * afterItem - * - * Method after an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function afterItem($item = [], $options = []) - { - return ''; - } -} diff --git a/src/View/Helper/NavbarMenuHelper.php b/src/View/Helper/NavbarMenuHelper.php deleted file mode 100644 index cc040a2..0000000 --- a/src/View/Helper/NavbarMenuHelper.php +++ /dev/null @@ -1,160 +0,0 @@ -'; - } - - /** - * afterSubItem - * - * Method after a submenu item has been build. - * - * @param array $item The menu items. - * @param array $options Options. - * @return string - */ - public function afterSubItem($item = [], $options = []) - { - return ''; - } - - /** - * beforeMenu - * - * Method before the menu has been build. - * - * @param array $menu The menu items. - * @param array $options Options. - * @return string - */ - public function beforeMenu($menu = [], $options = []) - { - return '
    '; - } - - /** - * afterSubItem - * - * Method before a submenu item has been build. - * - * @param array $item The menu items. - * @param array $options Options. - * @return string - */ - public function beforeSubItem($item = [], $options = []) - { - return ''; - } - - /** - * item - * - * Method to build an menu item. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function item($item = [], $options = []) - { - $html = '
  • '; - $html .= (key_exists('active', $item) && $item['active'] ? '' : ''); - $html .= $this->Html->link($item['title'], $item['url']); - $html .= (key_exists('active', $item) ? '' : ''); - $html .= '
  • '; - return $html; - } - - /** - * item - * - * Method to build an submenu item. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function subItem($item = [], $options = []) - { - return ''; - } - - /** - * beforeItem - * - * Method before an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function beforeItem($item = [], $options = []) - { - return ''; - } - - /** - * afterItem - * - * Method after an item has been build. - * - * @param array $item The menu item. - * @param array $options Options. - * @return string - */ - public function afterItem($item = [], $options = []) - { - return ''; - } -} diff --git a/src/View/Helper/PostTypeHelper.php b/src/View/Helper/PostTypeHelper.php new file mode 100644 index 0000000..c4c7340 --- /dev/null +++ b/src/View/Helper/PostTypeHelper.php @@ -0,0 +1,148 @@ +PostType->name('singular')`) + * - plural (calling `$this->PostType->name('plural')`) + * + * @param string|null $form Form + * @return mixed|string + */ + public function name($form = null) + { + $name = $this->getPostType('name'); + + if ($form === 'singular') { + return Inflector::singularize($name); + } + if ($form === 'plural') { + return Inflector::pluralize($name); + } + return $name; + } + + /** + * Returns slug + * + * @return string + */ + public function slug() + { + return $this->getPostType('slug'); + } + + public function tableColumns() + { + return $this->getPostType('tableColumns'); + } + + public function indexLink() + { + return $this->Html->link( + __('List'), + [ + '_name' => 'cakeadmin:posttype:index', + 'type' => $this->slug(), + ] + ); + } + + public function viewLink(EntityInterface $item) + { + if(!$this->getPostType()->action('view')) { + return; + } + + return $this->Html->link( + __('View'), + [ + '_name' => 'cakeadmin:posttype:view', + 'type' => $this->slug(), + $item->get('id') + ] + ); + } + + public function editLink(EntityInterface $item) + { + if(!$this->getPostType()->action('edit')) { + return; + } + + return $this->Html->link( + __('Edit'), + [ + '_name' => 'cakeadmin:posttype:edit', + 'type' => $this->slug(), + $item->get('id') + ] + ); + } + + public function deleteLink(EntityInterface $item) + { + if(!$this->getPostType()->action('delete')) { + return; + } + + return $this->Form->postLink( + __('Delete'), + [ + '_name' => 'cakeadmin:posttype:delete', + 'type' => $this->slug(), + $item->get('id') + ], + [ + 'confirm' => __('Are you sure you want to delete # {0}?', $item->get('id')) + ] + ); + } + + /** + * Getter for PostType values. + * + * @param string|null $key Key like `name` or `slug`. Leave `null` to get full PostType + * @return mixed + */ + protected function getPostType($key = null) + { + $postType = $this->config('data'); + if ($key) { + return call_user_func([$postType, $key]); + } + return $postType; + } +} diff --git a/src/View/Helper/PostTypesHelper.php b/src/View/Helper/PostTypesHelper.php deleted file mode 100644 index fd16be7..0000000 --- a/src/View/Helper/PostTypesHelper.php +++ /dev/null @@ -1,384 +0,0 @@ -_type = $type; - } - return $this->_type; - } - - /** - * data - * - * Setter and getter for $_data. - * - * @param array $data Data. - * @return array|null - */ - public function data($data = null) - { - if ($data) { - $this->_data = $data; - } - return $this->_data; - } - - /** - * header - * - * Header of the page. - * - * ### Options - * - `before` - Html before the header. - * - `after` - Html after the header. - * - * @param array $options Options. - * @return string - */ - public function header($options = []) - { - $_options = [ - 'before' => '

    ', - 'after' => '

    ' - ]; - - $options = array_merge($_options, $options); - - return $options['before'] . h($this->_type['alias']) . $options['after']; - } - - /** - * indexButton - * - * An `index`-button with a link to the PostType List. - * - * ### Options - * - `before` - Html before the button. - * - `after` - Html after the button. - * - * The link will be created via the HtmlHelper. - * - * @param array $options Options. - * @return string - */ - public function indexButton($options = []) - { - $_options = [ - 'before' => 'All ', - 'after' => '', - ]; - - $options = array_merge($_options, $options); - - $string = $options['before'] . h(Inflector::singularize($this->_type['alias'])) . $options['after']; - return $this->Html->link($string, ['action' => 'add', 'type' => $this->_type['slug']]); - } - - /** - * addButton - * - * An `add`-button with a link to add a new PostType Entity. - * - * ### Options - * - `before` - Html before the button. - * - `after` - Html after the button. - * - * The link will be created via the HtmlHelper. - * - * @param array $options Options. - * @return string - */ - public function addButton($options = []) - { - $_options = [ - 'before' => 'New ', - 'after' => '', - ]; - - $options = array_merge($_options, $options); - - $string = $options['before'] . h(Inflector::singularize($this->_type['alias'])) . $options['after']; - return $this->Html->link($string, ['action' => 'add', 'type' => $this->_type['slug']]); - } - - /** - * searchFilter - * - * Filter-form to search with. - * - * @param array $searchFilters Filter-data. - * @param array $options Options. - * @return null|string - */ - public function searchFilter($searchFilters, $options = []) - { - $_options = []; - - $options = array_merge($_options, $options); - - return ($searchFilters ? $this->Search->filterForm($searchFilters) : null); - } - - /** - * tableHead - * - * Generates the head of the table (all columns). - * - * ### Options - * - `beforeActionHead` - Html before the action-column. - * - `afterActionHead` - Html after the action-column. - * - `actionsLabel` - Label of `Actions`. - * - * @param array $options Options. - * @return string - */ - public function tableHead($options = []) - { - $_options = [ - 'beforeActionHead' => '', - 'afterActionHead' => '', - 'actionsLabel' => __d('CakeAdmin', 'Actions'), - ]; - - $options = array_merge($_options, $options); - - $html = ''; - - $html .= ''; - - foreach ($this->type()['tableColumns'] as $column => $opt) : - $html .= ''; - $html .= $this->Paginator->sort($column); - $html .= ''; - endforeach; - - $html .= $options['beforeActionHead'] . $options['actionsLabel'] . $options['afterActionHead']; - $html .= ''; - - return $html; - } - - /** - * tableBody - * - * Generates the head of the table (all columns). - * - * ### Options - * - `beforeActionBody` - Html before the actions-cell. - * - `afterActionBody` - Html after the actions-cell. - * - `viewLabel` - Label for the view-button. - * - `editLabel` - Label for the edit-button. - * - `deleteLabel` - Label for the delete-button. - * - * @param array $options Options. - * @return string - */ - public function tableBody($options = []) - { - $_options = [ - 'beforeActionBody' => '', - 'afterActionBody' => '', - 'viewLabel' => __d('CakeAdmin', 'View'), - 'editLabel' => __d('CakeAdmin', 'Edit'), - 'deleteLabel' => __d('CakeAdmin', 'Delete'), - ]; - - $options = array_merge($_options, $options); - - $html = ''; - - foreach ($this->_data as $item) : - $html .= ''; - - foreach ($this->_type['tableColumns'] as $column => $opt) : - $html .= ''; - $html .= $opt['before']; - $html .= Hash::get($item->toArray(), $opt['get']); - $html .= $opt['after']; - $html .= ''; - endforeach; - - $html .= $options['beforeActionBody']; - - $html .= $this->Html->link($options['viewLabel'], [ - 'action' => 'view', - 'type' => $this->type()['slug'], - $item->get('id') - ]) . ' '; - - $html .= $this->Html->link($options['editLabel'], [ - 'action' => 'edit', - 'type' => $this->type()['slug'], - $item->get('id') - ]) . ' '; - - $html .= $this->Form->postLink($options['deleteLabel'], [ - 'action' => 'delete', - 'type' => $this->type()['slug'], - $item->get('id') - ], [ - 'confirm' => __d('CakeAdmin', 'Are you sure you want to delete # {0}?', $item->get('id')) - ]); - - $html .= $options['afterActionBody']; - - $html .= ''; - endforeach; - - return $html; - } - - /** - * createForm - * - * Initializer for a form. - * - * @param \Cake\ORM\Entity $entity Entity. - * @param array $options Options. - * @return mixed - */ - public function createForm($entity, $options = []) - { - $options = array_merge($this->type()['formFields']['_create'], $options); - - return $this->Form->create($entity, $options); - } - - /** - * fieldset - * - * Generates a fieldset, - * - * ### Options - * - `beforeLegend` - Html before the legend. - * - `afterLegend` - Html after the legend. - * - `label` - Label at top of the fieldset. - * - `on` - Array with the validations (`both`, `add` or `edit`). - * - * @param array $options Options. - * @return string - */ - public function fieldset($options = []) - { - $_options = [ - 'beforeLegend' => '', - 'afterLegend' => '', - 'label' => __d('CakeAdmin', 'Add '), - 'on' => ['both'] - ]; - - $options = array_merge($_options, $options); - - $html = ''; - - $html .= $options['beforeLegend'] . $options['label'] . $this->type()['alias'] . $options['afterLegend']; - - foreach ($this->type()['formFields'] as $field => $opt) : - if (substr($field, 0, 1) !== '_') { - if (in_array($opt['on'], $options['on'])) { - echo $this->Form->input($field, $opt); - } - } - endforeach; - - return $html; - } - - /** - * submitForm - * - * Submitbutton for the form. - * - * ### Options - * - `submitLabel` - Label to use. - * - `options` - Options for the button. - * - * @param array $options Options. - * @return mixed - */ - public function submitForm($options = []) - { - $_options = [ - 'submitLabel' => __d('CakeAdmin', 'Submit'), - 'options' => [], - ]; - - $options = array_merge($_options, $options); - - return $this->Form->button($options['submitLabel'], $options['options']); - } - - /** - * endForm - * - * Ends the form. - * - * @return mixed - */ - public function endForm() - { - return $this->Form->end(); - } -} diff --git a/tests/App/Model/Entity/Article.php b/tests/App/Model/Entity/Article.php deleted file mode 100644 index 681c508..0000000 --- a/tests/App/Model/Entity/Article.php +++ /dev/null @@ -1,21 +0,0 @@ -hasMany('articles'); - } -} diff --git a/tests/App/Model/Table/BooksTable.php b/tests/App/Model/Table/BooksTable.php deleted file mode 100644 index c301aff..0000000 --- a/tests/App/Model/Table/BooksTable.php +++ /dev/null @@ -1,71 +0,0 @@ -belongsTo('authors'); - } - - public function postType() - { - return [ - 'model' => 'Books', - 'menu' => false, - 'menuWeight' => 25, - 'slug' => 'books', - 'name' => 'Cake Books', - 'alias' => 'CakeBooks', - 'aliasLc' => 'cakebooks', - 'singularAlias' => 'Cake Book', - 'singularAliasLc' => 'cake book', - 'description' => 'Books are written by authors.', - 'actions' => [ - 'index' => false, - 'add' => false, - 'edit' => false, - 'view' => false, - 'delete' => false - ], - 'filters' => [ - 'title' - ], - 'contain' => [ - 'authors' - ], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id', - 'author_id', - 'title', - 'body', - 'published' - ], - 'formFields' => [ - 'id', - 'author_id', - 'title' - ] - ]; - } -} diff --git a/tests/App/Template/Error/error500.ctp b/tests/App/Template/Error/error500.ctp deleted file mode 100644 index e69de29..0000000 diff --git a/tests/App/Template/Layout/error.ctp b/tests/App/Template/Layout/error.ctp deleted file mode 100644 index e69de29..0000000 diff --git a/tests/App/View/AppView.php b/tests/App/View/AppView.php deleted file mode 100644 index 5d22bc4..0000000 --- a/tests/App/View/AppView.php +++ /dev/null @@ -1,35 +0,0 @@ -loadHelper('Html');` - * - * @return void - */ - public function initialize() - { - } -} diff --git a/tests/Fixture/AdministratorsFixture.php b/tests/Fixture/AdministratorsFixture.php new file mode 100644 index 0000000..5dadc65 --- /dev/null +++ b/tests/Fixture/AdministratorsFixture.php @@ -0,0 +1,62 @@ + ['type' => 'uuid', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], + 'name' => ['type' => 'string', 'length' => 150, 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], + 'email' => ['type' => 'string', 'length' => 50, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], + 'password' => ['type' => 'string', 'length' => 255, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], + 'cakeadmin' => ['type' => 'integer', 'length' => 1, 'unsigned' => false, 'null' => true, 'default' => '0', 'comment' => '', 'precision' => null, 'autoIncrement' => null], + 'request_key' => ['type' => 'string', 'length' => 255, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], + 'created' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], + 'modified' => ['type' => 'datetime', 'length' => null, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null], + '_constraints' => [ + 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], + ], + '_options' => [ + 'engine' => 'InnoDB', + 'collation' => 'utf8_general_ci' + ], + ]; + // @codingStandardsIgnoreEnd + + /** + * Records + * + * @var array + */ + public $records = [ + [ + 'id' => '12bace86-66c3-48e0-8355-d90eaf724959', + 'name' => 'Lorem ipsum dolor sit amet', + 'email' => 'Lorem ipsum dolor sit amet', + 'password' => 'Lorem ipsum dolor sit amet', + 'cakeadmin' => 1, + 'request_key' => 'Lorem ipsum dolor sit amet', + 'created' => '2016-07-16 12:38:31', + 'modified' => '2016-07-16 12:38:31' + ], + ]; +} diff --git a/tests/Fixture/BooksFixture.php b/tests/Fixture/BooksFixture.php deleted file mode 100644 index 2e26dc0..0000000 --- a/tests/Fixture/BooksFixture.php +++ /dev/null @@ -1,44 +0,0 @@ - ['type' => 'integer'], - 'author_id' => ['type' => 'integer', 'null' => true], - 'title' => ['type' => 'string', 'null' => true], - 'body' => 'text', - 'published' => ['type' => 'string', 'length' => 1, 'default' => 'N'], - '_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]] - ]; - - /** - * records property - * - * @var array - */ - public $records = [ - ['author_id' => 1, 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y'], - ['author_id' => 3, 'title' => 'Second Article', 'body' => 'Second Article Body', 'published' => 'Y'], - ['author_id' => 1, 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y'] - ]; -} diff --git a/tests/Fixture/UsersFixture.php b/tests/Fixture/UsersFixture.php deleted file mode 100644 index ac7b1f3..0000000 --- a/tests/Fixture/UsersFixture.php +++ /dev/null @@ -1,128 +0,0 @@ - [ - 'type' => 'integer', - 'length' => 11, - 'unsigned' => false, - 'null' => false, - 'default' => null, - 'comment' => '', - 'autoIncrement' => true, - 'precision' => null - ], - 'email' => [ - 'type' => 'string', - 'length' => 50, - 'null' => true, - 'default' => null, - 'comment' => '', - 'precision' => null, - 'fixed' => null - ], - 'password' => [ - 'type' => 'string', - 'length' => 255, - 'null' => true, - 'default' => null, - 'comment' => '', - 'precision' => null, - 'fixed' => null - ], - 'cakeadmin' => [ - 'type' => 'integer', - 'length' => 11, - 'unsigned' => false, - 'null' => true, - 'default' => '1', - 'comment' => '', - 'precision' => null, - 'autoIncrement' => null - ], - 'request_key' => [ - 'type' => 'string', - 'length' => 255, - 'null' => true, - 'default' => null, - 'comment' => '', - 'precision' => null, - 'fixed' => null - ], - 'created' => [ - 'type' => 'datetime', - 'length' => null, - 'null' => true, - 'default' => null, - 'comment' => '', - 'precision' => null - ], - 'modified' => [ - 'type' => 'datetime', - 'length' => null, - 'null' => true, - 'default' => null, - 'comment' => '', - 'precision' => null - ], - '_constraints' => [ - 'primary' => [ - 'type' => 'primary', - 'columns' => ['id'], - 'length' => [] - ], - ], - '_options' => [ - 'engine' => 'InnoDB', - 'collation' => 'latin1_swedish_ci' - ], - ]; - - /** - * Records - * - * @var array - */ - public $records = [ - [ - 'email' => 'bob@cakeplugins.org', - 'password' => '12345', - 'cakeadmin' => 1, - 'created' => '2015-12-18 15:37:51', - 'modified' => '2015-12-18 15:37:51' - ], - [ - 'email' => 'unknown@cakeplugins.org', - 'password' => '12345', - 'cakeadmin' => 0, - 'created' => '2015-12-18 15:37:51', - 'modified' => '2015-12-18 15:37:51' - ], - ]; -} diff --git a/tests/TestCase/Controller/Admin/DashboardControllerTest.php b/tests/TestCase/Controller/Admin/DashboardControllerTest.php index cc80058..e2d9c4c 100644 --- a/tests/TestCase/Controller/Admin/DashboardControllerTest.php +++ b/tests/TestCase/Controller/Admin/DashboardControllerTest.php @@ -1,67 +1,22 @@ get('/admin/dashboard'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - public function testIndex() + public function testInitialization() { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/dashboard'); - - $this->assertResponseSuccess(); - $this->assertNoRedirect(); - - $this->assertLayout('default'); - $this->assertLayout('lightstrap'); - $this->assertTemplate('index'); - $this->assertTemplate('lightstrap'); - - $this->assertResponseContains('
  • Dashboard
  • '); + $this->markTestIncomplete('Not implemented yet.'); } } diff --git a/tests/TestCase/Controller/Admin/NotificationsControllerTest.php b/tests/TestCase/Controller/Admin/NotificationsControllerTest.php deleted file mode 100644 index 7ee35f0..0000000 --- a/tests/TestCase/Controller/Admin/NotificationsControllerTest.php +++ /dev/null @@ -1,79 +0,0 @@ -get('/admin/notifications'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - public function testIndex() - { - NotificationManager::instance()->notify([ - 'users' => [1], - 'vars' => [ - 'title' => 'Testing the title', - 'body' => 'Testing the body' - ] - ]); - - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/notifications'); - - $this->assertResponseSuccess(); - $this->assertNoRedirect(); - - $viewVars = $this->_controller->viewVars; - - $this->assertArrayHasKey('notifications', $viewVars); - $this->assertArrayHasKey(0, $viewVars['notifications']); - $this->assertInstanceOf('Notifier\Model\Entity\Notification', $viewVars['notifications'][0]); - - $this->assertResponseContains('Testing the title'); - $this->assertResponseContains('Testing the body'); - } -} diff --git a/tests/TestCase/Controller/Admin/PostTypeControllerTest.php b/tests/TestCase/Controller/Admin/PostTypeControllerTest.php new file mode 100644 index 0000000..57b56bb --- /dev/null +++ b/tests/TestCase/Controller/Admin/PostTypeControllerTest.php @@ -0,0 +1,71 @@ +markTestIncomplete('Not implemented yet.'); + } + + /** + * Test view method + * + * @return void + */ + public function testView() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test add method + * + * @return void + */ + public function testAdd() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test edit method + * + * @return void + */ + public function testEdit() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test delete method + * + * @return void + */ + public function testDelete() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Controller/Admin/PostTypesControllerTest.php b/tests/TestCase/Controller/Admin/PostTypesControllerTest.php deleted file mode 100644 index 24857e6..0000000 --- a/tests/TestCase/Controller/Admin/PostTypesControllerTest.php +++ /dev/null @@ -1,465 +0,0 @@ -enableCsrfToken(); - $this->enableSecurityToken(); - } - - /** - * Runs after each test. - * - * @return void - */ - public function tearDown() - { - parent::tearDown(); - - Configure::write('CA.PostTypes', []); - Configure::write('CA.Models', []); - } - - /** - * Test if the index request is authorized. - * - * @return void - */ - public function testIndexNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/index'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if exception is called if the posttype does not exist. - * - * @expectedException - * @return void - */ - public function testIndexNoPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/posttypes/articles/index'); - - $this->assertResponseFailure(); - } - - /** - * Test index request on registered posttype. - * - * @return void - */ - public function testIndexWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/index'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains('
  • Articles
  • '); - - $this->assertLayout('default.ctp'); - $this->assertTemplate(DS . 'Template' . DS . 'Admin' . DS . 'PostTypes' . DS . 'index.ctp'); - } - - /** - * Test if the view request is authorized. - * - * @return void - */ - public function testViewNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/view/1'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if exception is called if the posttype does not exist. - * - * @return void - */ - public function testViewNoPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/posttypes/articles/view/1'); - - $this->assertResponseFailure(); - } - - /** - * Test view request on registered posttype. - * - * @return void - */ - public function testViewWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/view/1'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains('
  • Articles
  • '); - - $this->assertLayout('default.ctp'); - $this->assertTemplate(DS . 'Template' . DS . 'Admin' . DS . 'PostTypes' . DS . 'view.ctp'); - } - - /** - * Test if the add request is authorized. - * - * @return void - */ - public function testAddNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/add'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if exception is called if the posttype does not exist. - * - * @return void - */ - public function testAddNoPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/posttypes/articles/add'); - - $this->assertResponseFailure(); - } - - /** - * Test add request on registered posttype. - * - * @return void - */ - public function testAddWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/add'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains('
  • Articles
  • '); - - $this->assertLayout('default.ctp'); - $this->assertTemplate(DS . 'Template' . DS . 'Admin' . DS . 'PostTypes' . DS . 'add.ctp'); - } - - /** - * Test add POST request on registered posttype. - * - * @return void - */ - public function testAddPostWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $articles = TableRegistry::get('Articles'); - - $this->post('/admin/posttypes/articles/add', [ - 'author_id' => 1, - 'title' => 'Fourth article', - 'body' => 'Fourth Article Body', - 'published' => 'Y' - ]); - - $this->assertResponseSuccess(); - - $this->assertEquals(4, $articles->find()->count()); - } - - /** - * Test if the edit request is authorized. - * - * @return void - */ - public function testEditNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/edit/1'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if exception is called if the posttype does not exist. - * - * @return void - */ - public function testEditNoPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/posttypes/articles/edit/1'); - - $this->assertResponseFailure(); - } - - /** - * Test edit request on registered posttype. - * - * @return void - */ - public function testEditWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/edit/1'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains('
  • Articles
  • '); - - $this->assertLayout('default.ctp'); - $this->assertTemplate(DS . 'Template' . DS . 'Admin' . DS . 'PostTypes' . DS . 'edit.ctp'); - } - - /** - * Test edit POST request on registered posttype. - * - * @return void - */ - public function testEditPostWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $articles = TableRegistry::get('Articles'); - - $article = $articles->get(1); - - $this->assertEquals('First Article', $article->title); - - $this->post('/admin/posttypes/articles/edit/1', [ - 'title' => 'First Article Edited', - ]); - - $this->assertResponseSuccess(); - - $article = $articles->get(1); - - $this->assertEquals('First Article Edited', $article->title); - } - - /** - * Test if the delete request is authorized. - * - * @return void - */ - public function testDeleteNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->delete('/admin/posttypes/articles/delete/1'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if exception is called if the posttype does not exist. - * - * @return void - */ - public function testDeleteNoPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->delete('/admin/posttypes/articles/delete/1'); - - $this->assertResponseFailure(); - } - - /** - * Test delete request on registered posttype. - * - * @return void - */ - public function testDeleteWithPostType() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - Configure::write('CA.Models.articles', 'Articles'); - - $articles = TableRegistry::get('Articles'); - - - $this->assertEquals(3, $articles->find()->count()); - - $this->delete('/admin/posttypes/articles/delete/1'); - - $this->assertResponseSuccess(); - - $this->assertEquals(2, $articles->find()->count()); - } -} diff --git a/tests/TestCase/Controller/Admin/SettingsControllerTest.php b/tests/TestCase/Controller/Admin/SettingsControllerTest.php deleted file mode 100644 index 20a91a2..0000000 --- a/tests/TestCase/Controller/Admin/SettingsControllerTest.php +++ /dev/null @@ -1,195 +0,0 @@ -enableCsrfToken(); - $this->enableSecurityToken(); - } - - /** - * Runs after each test. - * - * @return void - */ - public function tearDown() - { - parent::tearDown(); - - Setting::clear(true); - - Configure::write('CA.PostTypes', []); - Configure::write('CA.Models', []); - } - - /** - * Test if the index request is authorized. - * - * @return void - */ - public function testIndexNotAuthorized() - { - Configure::write('CA.Models.articles', 'Articles'); - - $this->get('/admin/posttypes/articles/index'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin'); - } - - /** - * Test if the index request uses the default key and shows the form. - * - * @return void - */ - public function testIndexWithDefaultKey() - { - Setting::write('App.FirstKey', 'First Value'); - Setting::write('App.SecondKey', 'Second Value'); - - Setting::write('CA.ThirthKey', 'Thirth Value'); - - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/settings'); - - $this->assertResponseSuccess(); - $this->assertNoRedirect(); - - $viewVars = $this->_controller->viewVars; - - $settingVar = $viewVars['settings']->toArray(); - - $this->assertEquals(2, count($settingVar)); - $this->assertEquals('App.FirstKey', $settingVar[0]->name); - $this->assertEquals('App.SecondKey', $settingVar[1]->name); - - $formElement = '
    '; - $this->assertResponseContains($formElement); - - $formElement = '
    '; - $this->assertResponseContains($formElement); - } - - /** - * Test if the index request can handle custom keys and shows the form. - * - * @return void - */ - public function testIndexWithCustomKey() - { - Setting::write('App.FirstKey', 'First Value'); - Setting::write('App.SecondKey', 'Second Value'); - - Setting::write('CA.ThirthKey', 'Thirth Value'); - - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/settings/CA'); - - $this->assertResponseSuccess(); - $this->assertNoRedirect(); - - $viewVars = $this->_controller->viewVars; - - $settingVar = $viewVars['settings']->toArray(); - - $this->assertEquals(1, count($settingVar)); - $this->assertEquals('CA.ThirthKey', $settingVar[0]->name); - - $formElement = '
    '; - $this->assertResponseContains($formElement); - } - - public function testIndexPostWithDefaultKey() - { - Setting::write('App.FirstKey', 'First Value'); - Setting::write('App.SecondKey', 'Second Value'); - - Setting::write('CA.ThirthKey', 'Thirth Value'); - - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $settings = TableRegistry::get('Settings.Configurations'); - - $this->assertEquals('First Value', $settings->findByName('App.FirstKey')->toArray()[0]['value']); - - $this->post('/admin/settings', [ - [ - 'id' => '1', - 'value' => 'First Value Edited' - ] - ]); - - $this->assertResponseSuccess(); - - $this->assertEquals('First Value Edited', $settings->findByName('App.FirstKey')->toArray()[0]['value']); - } -} diff --git a/tests/TestCase/Controller/Admin/UsersControllerTest.php b/tests/TestCase/Controller/Admin/UsersControllerTest.php index fbfa267..b012954 100644 --- a/tests/TestCase/Controller/Admin/UsersControllerTest.php +++ b/tests/TestCase/Controller/Admin/UsersControllerTest.php @@ -1,375 +1,22 @@ enableCsrfToken(); - $this->enableSecurityToken(); - } - - /** - * Runs after each test. - * - * @return void - */ - public function tearDown() - { - parent::tearDown(); - } - - /** - * Test login request. - * - * @return void - */ - public function testLogin() - { - $this->get('/admin/login'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains(''); - $this->assertResponseContains(''); - } - - /** - * Test login POST request. - * - * @return void - */ - public function testLoginPost() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $details = [ - 'email' => 'test@cakeplugins.org', - 'password' => '12345' - ]; - - $administrators->save($administrators->newEntity($details)); - - $this->post('/admin/login', [ - 'email' => 'test@cakeplugins.org', - 'password' => '12345' - ]); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin/dashboard'); - - $this->assertSession('3', 'Auth.CakeAdmin.id'); - $this->assertSession('test@cakeplugins.org', 'Auth.CakeAdmin.email'); - $this->assertSession('1', 'Auth.CakeAdmin.cakeadmin'); - } - - /** - * Test login POST request fail. - * - * @return void - */ - public function testLoginPostFail() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $details = [ - 'email' => 'test@cakeplugins.org', - 'password' => '12345' - ]; - - $administrators->save($administrators->newEntity($details)); - - $this->post('/admin/login', [ - 'email' => 'test@cakeplugins.org', - 'password' => '123456' - ]); - - $this->assertResponseSuccess(); - $this->assertNoRedirect(); - - $this->assertResponseContains('Invalid username or password, try again'); - - $this->assertSession(null, 'Auth.CakeAdmin'); - } - - /** - * Test login request when an user has been logged in. The user should be redirected. - * - * @return void - */ - public function testLoginLoggedin() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/login'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin/dashboard'); - } - - /** - * Test if `/admin` request will be the same as the `/admin/login` request. - * - * @return void - */ - public function testLoginAdminRequest() - { - $this->get('/admin'); - - $this->assertResponseSuccess(); - - $request = $this->_controller->request; - - $this->assertEquals('CakeAdmin', $request->params['plugin']); - $this->assertEquals('Users', $request->params['controller']); - $this->assertEquals('login', $request->params['action']); - $this->assertEquals('admin', $request->params['prefix']); - } - - /** - * Test if the email in the query url will be used in the form. - * For example: `/admin/login?email=bob@cakeplugins.org`. - * - * @return void - */ - public function testLoginWithEmailInQuery() - { - $this->get('/admin/login?email=bob@cakeplugins.org'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains(''); - } - - /** - * Test logout request. - * - * @return void - */ - public function testLogout() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/logout'); - - $this->assertSession([], 'Auth'); - $this->assertSession('You are now logged out.', 'Flash.flash.0.message'); - } - - /** - * Test forgot request. - * - * @return void - */ - public function testForgot() - { - $this->markTestIncomplete('This will be tested by LeoRuhland because of the theming'); - } /** - * Test forgot POST request. + * Test initial setup * * @return void */ - public function testForgotPost() + public function testInitialization() { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $this->assertNull($administrators->get(1)->get('request_key')); - - EventManager::instance()->on( - 'Dispatcher.beforeDispatch', - ['priority' => 998], - function ($event) { - $mailer = $this->getMock('CakeAdmin\Mailer\CakeAdminMailer', ['send']); - - $mailer->expects($this->once()) - ->method('send') - ->with($this->equalTo('resetPassword')) - ->will($this->returnValue(true)); - - $this->_controller = $this->getMock( - 'CakeAdmin\Controller\Admin\UsersController', - ['getMailer'], - [$event->data['request'], $event->data['response']] - ); - - $this->_controller->expects($this->once()) - ->method('getMailer') - ->with($this->equalTo('CakeAdmin.CakeAdmin')) - ->will($this->returnValue($mailer)); - - $events = $this->_controller->eventManager(); - $events->on('View.beforeRender', function ($event, $viewFile) { - if (!$this->_viewName) { - $this->_viewName = $viewFile; - } - }); - $events->on('View.beforeLayout', function ($event, $viewFile) { - $this->_layoutName = $viewFile; - }); - - $event->data['controller'] = $this->_controller; - - $event->stopPropagation(); - } - ); - - $this->post('/admin/users/forgot', [ - 'email' => 'bob@cakeplugins.org' - ]); - - $this->assertNotNull($administrators->get(1)->get('request_key')); - } - - /** - * Test forgot request when an user has been logged in. The user should be redirected. - * - * @return void - */ - public function testForgotLoggedin() - { - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->post('/admin/users/forgot'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/login'); - } - - /** - * Test reset request. - * - * @return void - */ - public function testReset() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $administrator = $administrators->get(1); - $administrator->set('request_key', 'custom_request_key'); - $administrators->save($administrator); - - $this->get('/admin/users/reset/bob@cakeplugins.org/custom_request_key'); - - $this->assertResponseSuccess(); - - $this->assertResponseContains('
    '); - $this->assertResponseContains(''); - $this->assertResponseContains(''); - } - - /** - * Test reset POST request. - * - * @return void - */ - public function testResetLoggedin() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $administrator = $administrators->get(1); - $administrator->set('request_key', 'custom_request_key'); - $administrators->save($administrator); - - $this->session([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->get('/admin/users/reset/bob@cakeplugins.org/custom_request_key'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin?email=bob%40cakeplugins.org'); - } - - /** - * Test forgot request when an user has been logged in. The user should be redirected. - * - * @return void - */ - public function testResetInvalid() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $administrator = $administrators->get(1); - $administrator->set('request_key', 'custom_request_key'); - $administrators->save($administrator); - - $this->get('/admin/users/reset/bob@cakeplugins.org/wrong_request_key'); - - $this->assertResponseSuccess(); - $this->assertRedirect('/admin?email=bob%40cakeplugins.org'); - - $this->assertSession('Your account could not be reset.', 'Flash.flash.0.message'); + $this->markTestIncomplete('Not implemented yet.'); } } diff --git a/tests/TestCase/Controller/Component/CakeAdminComponentTest.php b/tests/TestCase/Controller/Component/CakeAdminComponentTest.php index b2c2945..bfd5def 100644 --- a/tests/TestCase/Controller/Component/CakeAdminComponentTest.php +++ b/tests/TestCase/Controller/Component/CakeAdminComponentTest.php @@ -1,38 +1,22 @@ CakeAdmin = $this->getMock( - 'CakeAdmin\Controller\Component\CakeAdminComponent', - ['_setRecipientList'], - [$collection] - ); - $this->Controller = $this->getMock('Cake\Controller\Controller', ['redirect']); - $this->CakeAdmin->setController($this->Controller); + $this->CakeAdmin = new CakeAdminComponent($registry); } /** @@ -74,134 +49,6 @@ public function tearDown() */ public function testInitialization() { - $collection = new ComponentRegistry(); - $CakeAdmin = $this->getMock( - 'CakeAdmin\Controller\Component\CakeAdminComponent', - ['_setRecipientList'], - [$collection] - ); - - $CakeAdmin->expects($this->once()) - ->method('_setRecipientList') - ->will($this->returnValue(true)); - - $CakeAdmin->initialize([]); - } - - /** - * Test setController method. - * - * @return void - */ - public function testSetController() - { - $this->CakeAdmin->setController('No Controller'); - - $this->assertEquals('No Controller', $this->CakeAdmin->Controller); - } - - /** - * Test if administrators-method will return list of all administrators. - * - * @return void - */ - public function testAdministrators() - { - $result = $this->CakeAdmin->administrators(); - - $this->assertArrayHasKey(0, $result); - $this->assertInstanceOf('CakeAdmin\Model\Entity\Administrator', $result[0]); - } - - /** - * Test if a list of the chosen field of all administrators will be returned. - * - * @return void - */ - public function testAdministratorsWithField() - { - $administrators = TableRegistry::get('CakeAdmin.Administrators'); - - $details = [ - 'email' => 'test@cakeplugins.org', - 'password' => '12345' - ]; - - $administrators->save($administrators->newEntity($details)); - - $result = $this->CakeAdmin->administrators('email'); - - $expected = [ - 1 => 'bob@cakeplugins.org', - 3 => 'test@cakeplugins.org' - ]; - - $this->assertEquals($expected, $result); - } - - /** - * Test if the method will return if an administrators is logged in. - * - * @return void - */ - public function testIsLoggedIn() - { - $this->CakeAdmin->Controller->request->session()->write([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $this->assertTrue($this->CakeAdmin->isLoggedIn()); - } - - /** - * Test that isLoggedIn-method will return `false` when no administrator is logged in. - * - * @return void - */ - public function testIsLoggedInFalse() - { - $this->assertFalse($this->CakeAdmin->isLoggedIn()); - } - - /** - * Test if authUser-method will return the current logged in user. - * - * @return void - */ - public function testAuthUser() - { - $this->CakeAdmin->Controller->request->session()->write([ - 'Auth' => [ - 'CakeAdmin' => [ - 'id' => 1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => 1 - ] - ] - ]); - - $expected = [ - 'id' => (int)1, - 'email' => 'bob@cakeplugins.org', - 'cakeadmin' => (int)1 - ]; - - $this->assertEquals($expected, $this->CakeAdmin->authUser()); - } - - /** - * Test that `false` will be returned when the administrator is not logged in. - * - * @return void - */ - public function testAuthUserFalse() - { - $this->assertFalse($this->CakeAdmin->authUser()); + $this->markTestIncomplete('Not implemented yet.'); } } diff --git a/tests/TestCase/Controller/Component/PostTypesComponentTest.php b/tests/TestCase/Controller/Component/PostTypesComponentTest.php deleted file mode 100644 index 31a1d6d..0000000 --- a/tests/TestCase/Controller/Component/PostTypesComponentTest.php +++ /dev/null @@ -1,522 +0,0 @@ -PostTypes = $this->getMock( - 'CakeAdmin\Controller\Component\PostTypesComponent', - ['_registerPostTypesFromConfigure', '_addMenuItems'], - [$collection] - ); - $this->Controller = $this->getMock('Cake\Controller\Controller', ['redirect']); - $this->PostTypes->setController($this->Controller); - } - - /** - * tearDown method - * - * @return void - */ - public function tearDown() - { - Configure::write('CA.PostTypes', []); - - unset($this->PostTypes); - - parent::tearDown(); - } - - /** - * Test initial setup - * - * @return void - */ - public function testInitialization() - { - $collection = new ComponentRegistry(); - $PostType = $this->getMock( - 'CakeAdmin\Controller\Component\PostTypesComponent', - ['_registerPostTypesFromConfigure', '_addMenuItems'], - [$collection] - ); - - $PostType->expects($this->once()) - ->method('_registerPostTypesFromConfigure') - ->will($this->returnValue(true)); - - $PostType->expects($this->once()) - ->method('_addMenuItems') - ->will($this->returnValue(true)); - - $PostType->initialize([]); - } - - /** - * Test setController method. - * - * @return void - */ - public function testSetController() - { - $this->PostTypes->setController('No Controller'); - - $this->assertEquals('No Controller', $this->PostTypes->Controller); - } - - /** - * Test if the PostType will have all needed default options. - * - * @return void - */ - public function testRegisterDefaultOptions() - { - $this->assertEquals([], Configure::read('CA.PostTypes')); - - $this->PostTypes->register('Authors'); - - $this->assertNotNull(Configure::read('CA.PostTypes')); - - $posttypes = Configure::read('CA.PostTypes'); - - $expected = [ - 'model' => 'Authors', - 'menu' => true, - 'menuWeight' => (int)20, - 'slug' => 'authors', - 'name' => 'Authors', - 'alias' => 'Authors', - 'aliasLc' => 'authors', - 'singularAlias' => 'Author', - 'singularAliasLc' => 'author', - 'description' => null, - 'actions' => [ - 'index' => true, - 'add' => true, - 'edit' => true, - 'view' => true, - 'delete' => true - ], - 'filters' => [], - 'contain' => [], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id' => [ - 'get' => 'id', - 'before' => '', - 'after' => '' - ], - 'name' => [ - 'get' => 'name', - 'before' => '', - 'after' => '' - ] - ], - 'formFields' => [ - '_create' => [ - 'on' => 'both' - ], - 'id' => [ - 'on' => 'both' - ], - 'name' => [ - 'on' => 'both' - ] - ] - ]; - - $this->assertArrayHasKey('authors', $posttypes); - $this->assertEquals($expected, $posttypes['authors']); - } - - /** - * Test if all options are customizable. - * - * @return void - */ - public function testRegisterCustomOptions() - { - $this->assertEquals([], Configure::read('CA.PostTypes')); - - $this->PostTypes->register('Authors', [ - 'model' => 'CakeAdmin.Authors', - 'menu' => false, - 'menuWeight' => 25, - 'slug' => 'cake-authors', - 'name' => 'Cake Authors', - 'alias' => 'CakeAuthors', - 'aliasLc' => 'cakeauthors', - 'singularAlias' => 'Cake Author', - 'singularAliasLc' => 'cake author', - 'description' => 'Authors are owners of books.', - 'actions' => [ - 'index' => false, - 'add' => false, - 'edit' => false, - 'view' => false, - 'delete' => false - ], - 'filters' => [ - 'name' - ], - 'contain' => [ - 'books' - ], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id', - 'name' - ], - 'formFields' => [ - 'id', - 'name' - ] - ]); - - $this->assertNotNull(Configure::read('CA.PostTypes')); - - $posttypes = Configure::read('CA.PostTypes'); - - $expected = [ - 'model' => 'CakeAdmin.Authors', - 'menu' => false, - 'menuWeight' => (int)25, - 'slug' => 'cake-authors', - 'name' => 'Cake Authors', - 'alias' => 'CakeAuthors', - 'aliasLc' => 'cakeauthors', - 'singularAlias' => 'Author', - 'singularAliasLc' => 'author', - 'description' => 'Authors are owners of books.', - 'actions' => [ - 'index' => false, - 'add' => false, - 'edit' => false, - 'view' => false, - 'delete' => false - ], - 'filters' => [ - (int)0 => 'name' - ], - 'contain' => [ - (int)0 => 'books' - ], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id' => [ - 'get' => 'id', - 'before' => '', - 'after' => '' - ], - 'name' => [ - 'get' => 'name', - 'before' => '', - 'after' => '' - ] - ], - 'formFields' => [ - '_create' => [ - 'on' => 'both' - ], - 'id' => [ - 'on' => 'both' - ], - 'name' => [ - 'on' => 'both' - ] - ], - 'singularAlias' => 'Cake Author', - 'singularAliasLc' => 'cake author' - ]; - - $this->assertArrayHasKey('cake-authors', $posttypes); - $this->assertEquals($expected, $posttypes['cake-authors']); - } - - /** - * Test if options defined in the model will be used when registering a PostType. - * - * @return void - */ - public function testRegisterModelOptions() - { - $this->assertEquals([], Configure::read('CA.PostTypes')); - - $this->PostTypes->register('Books'); - - $this->assertNotNull(Configure::read('CA.PostTypes')); - - $posttypes = Configure::read('CA.PostTypes'); - - $expected = [ - 'model' => 'Books', - 'menu' => false, - 'menuWeight' => (int)25, - 'slug' => 'books', - 'name' => 'Cake Books', - 'alias' => 'CakeBooks', - 'aliasLc' => 'cakebooks', - 'singularAlias' => 'Book', - 'singularAliasLc' => 'book', - 'description' => 'Books are written by authors.', - 'actions' => [ - 'index' => false, - 'add' => false, - 'edit' => false, - 'view' => false, - 'delete' => false - ], - 'filters' => [ - (int)0 => 'title' - ], - 'contain' => [ - (int)0 => 'authors' - ], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id' => [ - 'get' => 'id', - 'before' => '', - 'after' => '' - ], - 'author_id' => [ - 'get' => 'author_id', - 'before' => '', - 'after' => '' - ], - 'title' => [ - 'get' => 'title', - 'before' => '', - 'after' => '' - ], - 'body' => [ - 'get' => 'body', - 'before' => '', - 'after' => '' - ], - 'published' => [ - 'get' => 'published', - 'before' => '', - 'after' => '' - ] - ], - 'formFields' => [ - '_create' => [ - 'on' => 'both' - ], - 'id' => [ - 'on' => 'both' - ], - 'author_id' => [ - 'on' => 'both' - ], - 'title' => [ - 'on' => 'both' - ] - ], - 'singularAlias' => 'Cake Book', - 'singularAliasLc' => 'cake book', - 'table' => 'books' - ]; - - $this->assertArrayHasKey('books', $posttypes); - $this->assertEquals($expected, $posttypes['books']); - } - - /** - * Test if the options can be retrieved per PostType. - * - * @return void - */ - public function testGetOption() - { - $this->assertEquals([], Configure::read('CA.PostTypes')); - - $this->PostTypes->register('Books'); - - $this->assertNotNull(Configure::read('CA.PostTypes')); - - $this->assertEquals('Books are written by authors.', $this->PostTypes->getOption('books', 'description')); - - $expected = [ - 'id' => [ - 'get' => 'id', - 'before' => '', - 'after' => '' - ], - 'author_id' => [ - 'get' => 'author_id', - 'before' => '', - 'after' => '' - ], - 'title' => [ - 'get' => 'title', - 'before' => '', - 'after' => '' - ], - 'body' => [ - 'get' => 'body', - 'before' => '', - 'after' => '' - ], - 'published' => [ - 'get' => 'published', - 'before' => '', - 'after' => '' - ] - ]; - - $this->assertEquals($expected, $this->PostTypes->getOption('books', 'tableColumns')); - } - - /** - * Test if all options can be retrieved per PostType when no key is used. - * - * @return void - */ - public function testGetOptionWithoutKey() - { - $this->assertEquals([], Configure::read('CA.PostTypes')); - - $this->PostTypes->register('Books'); - - $this->assertNotNull(Configure::read('CA.PostTypes')); - - $expected = [ - 'model' => 'Books', - 'menu' => false, - 'menuWeight' => (int)25, - 'slug' => 'books', - 'name' => 'Cake Books', - 'alias' => 'CakeBooks', - 'aliasLc' => 'cakebooks', - 'singularAlias' => 'Book', - 'singularAliasLc' => 'book', - 'description' => 'Books are written by authors.', - 'actions' => [ - 'index' => false, - 'add' => false, - 'edit' => false, - 'view' => false, - 'delete' => false - ], - 'filters' => [ - (int)0 => 'title' - ], - 'contain' => [ - (int)0 => 'authors' - ], - 'query' => function ($query) { - return $query; - }, - 'tableColumns' => [ - 'id' => [ - 'get' => 'id', - 'before' => '', - 'after' => '' - ], - 'author_id' => [ - 'get' => 'author_id', - 'before' => '', - 'after' => '' - ], - 'title' => [ - 'get' => 'title', - 'before' => '', - 'after' => '' - ], - 'body' => [ - 'get' => 'body', - 'before' => '', - 'after' => '' - ], - 'published' => [ - 'get' => 'published', - 'before' => '', - 'after' => '' - ] - ], - 'formFields' => [ - '_create' => [ - 'on' => 'both' - ], - 'id' => [ - 'on' => 'both' - ], - 'author_id' => [ - 'on' => 'both' - ], - 'title' => [ - 'on' => 'both' - ] - ], - 'singularAlias' => 'Cake Book', - 'singularAliasLc' => 'cake book', - 'table' => 'books' - ]; - - $this->assertEquals($expected, $this->PostTypes->getOption('books')); - } - - /** - * Test if the getOption can handle a non-existing PostType and returns `false`. - * - * @return void - */ - public function testGetOptionWithNoExisitingPostType() - { - $this->assertFalse($this->PostTypes->getOption('cake-books')); - } -} diff --git a/tests/TestCase/Model/Table/AdministratorsTableTest.php b/tests/TestCase/Model/Table/AdministratorsTableTest.php index a168316..0da4882 100644 --- a/tests/TestCase/Model/Table/AdministratorsTableTest.php +++ b/tests/TestCase/Model/Table/AdministratorsTableTest.php @@ -1,31 +1,30 @@ Administrators = TableRegistry::get('CakeAdmin.Administrators'); - parent::setUp(); + $config = TableRegistry::exists('Administrators') ? [] : ['className' => 'Bakkerij\CakeAdmin\Model\Table\AdministratorsTable']; + $this->Administrators = TableRegistry::get('Administrators', $config); } /** @@ -53,82 +52,32 @@ public function tearDown() } /** - * Test find query method; only users with `cakeadmin` column on `true` will be queried. + * Test initialize method * * @return void */ - public function testFindQuery() + public function testInitialize() { - $result = $this->Administrators->find(); - - $this->assertEquals(1, $result->count()); + $this->markTestIncomplete('Not implemented yet.'); } /** - * Before an administrator will be saved, `cakeadmin` must be true. + * Test validationDefault method * * @return void */ - public function testBeforeSave() + public function testValidationDefault() { - $data = [ - 'email' => 'test@cakeplugins.org', - 'password' => 12345 - ]; - - $this->Administrators->save($this->Administrators->newEntity($data)); - - $result = $this->Administrators->get(3); - - $this->assertEquals(1, $result->get('cakeadmin')); + $this->markTestIncomplete('Not implemented yet.'); } /** - * Test if new password will be set. + * Test buildRules method * * @return void */ - public function testNewPassword() + public function testBuildRules() { - $entity = $this->Administrators->get(1); - - $oldPassword = $entity->get('password'); - - $data = [ - 'new_password' => '54321', - 'confirm_password' => '54321', - ]; - - $this->Administrators->save($this->Administrators->patchEntity($entity, $data)); - - $this->assertEquals(0, count($entity->errors())); - - $result = $this->Administrators->get(1); - - $this->assertNotEquals($oldPassword, $result->get('password')); - } - - /** - * Test that new password won't be set without confirm_password. - * - * @return void - */ - public function testNewPasswordWithoutConfirmation() - { - $entity = $this->Administrators->get(1); - - $oldPassword = $entity->get('password'); - - $data = [ - 'new_password' => '54321' - ]; - - $this->Administrators->save($this->Administrators->patchEntity($entity, $data)); - - $this->assertEquals(1, count($entity->errors())); - - $result = $this->Administrators->get(1); - - $this->assertEquals($oldPassword, $result->get('password')); + $this->markTestIncomplete('Not implemented yet.'); } } diff --git a/tests/TestCase/Shell/AdminShellTest.php b/tests/TestCase/Shell/AdminShellTest.php deleted file mode 100644 index 898b785..0000000 --- a/tests/TestCase/Shell/AdminShellTest.php +++ /dev/null @@ -1,58 +0,0 @@ -io = $this->getMock('Cake\Console\ConsoleIo'); - $this->Admin = new AdminShell($this->io); - } - - /** - * tearDown method - * - * @return void - */ - public function tearDown() - { - unset($this->Admin); - - parent::tearDown(); - } - - /** - * Test main method - * - * @return void - */ - public function testMain() - { - $this->markTestIncomplete('Not implemented yet.'); - } -} diff --git a/tests/TestCase/Shell/CakeadminShellTest.php b/tests/TestCase/Shell/CakeadminShellTest.php new file mode 100644 index 0000000..22ecaf5 --- /dev/null +++ b/tests/TestCase/Shell/CakeadminShellTest.php @@ -0,0 +1,70 @@ +io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock(); + $this->Cakeadmin = new CakeadminShell($this->io); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->Cakeadmin); + + parent::tearDown(); + } + + /** + * Test getOptionParser method + * + * @return void + */ + public function testGetOptionParser() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test main method + * + * @return void + */ + public function testMain() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Shell/Task/AdminTaskTest.php b/tests/TestCase/Shell/Task/AdminTaskTest.php new file mode 100644 index 0000000..8b04712 --- /dev/null +++ b/tests/TestCase/Shell/Task/AdminTaskTest.php @@ -0,0 +1,63 @@ +io = $this->getMockBuilder('Cake\Console\ConsoleIo')->getMock(); + + $this->Admin = $this->getMockBuilder('Bakkerij\CakeAdmin\Shell\Task\AdminTask') + ->setConstructorArgs([$this->io]) + ->getMock(); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->Admin); + + parent::tearDown(); + } + + /** + * Test main method + * + * @return void + */ + public function testMain() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/View/Helper/PostTypeHelperTest.php b/tests/TestCase/View/Helper/PostTypeHelperTest.php new file mode 100644 index 0000000..374de71 --- /dev/null +++ b/tests/TestCase/View/Helper/PostTypeHelperTest.php @@ -0,0 +1,54 @@ +PostType = new PostTypeHelper($view); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->PostType); + + parent::tearDown(); + } + + /** + * Test initial setup + * + * @return void + */ + public function testInitialization() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index e9ecba8..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,104 +0,0 @@ - 'CakeAdmin\Test\App', - 'paths' => [ - 'templates' => [ - APP . 'Template' . DS - ] - ] -]); -Configure::write('debug', true); - -$TMP = new Folder(TMP); -$TMP->create(TMP . 'cache/models', 0777); -$TMP->create(TMP . 'cache/persistent', 0777); -$TMP->create(TMP . 'cache/views', 0777); - -$cache = [ - 'default' => [ - 'engine' => 'File' - ], - '_cake_core_' => [ - 'className' => 'File', - 'prefix' => 'cakeadmin_myapp_cake_core_', - 'path' => CACHE . 'persistent/', - 'serialize' => true, - 'duration' => '+10 seconds' - ], - '_cake_model_' => [ - 'className' => 'File', - 'prefix' => 'cakeadmin_my_app_cake_model_', - 'path' => CACHE . 'models/', - 'serialize' => 'File', - 'duration' => '+10 seconds' - ] -]; - -Cake\Cache\Cache::config($cache); -Cake\Core\Configure::write('Session', [ - 'defaults' => 'php' -]); - -// Ensure default test connection is defined -if (!getenv('db_dsn')) { - putenv('db_dsn=sqlite:///:memory:'); -} - -Cake\Datasource\ConnectionManager::config('default', [ - 'url' => getenv('db_dsn'), - 'timezone' => 'UTC' -]); - -Cake\Datasource\ConnectionManager::config('test', [ - 'url' => getenv('db_dsn'), - 'timezone' => 'UTC' -]); - -Cake\Core\Plugin::load('Settings', ['autoload' => true, 'routes' => true, 'bootstrap' => true]); -Cake\Core\Plugin::load('Notifier', ['autoload' => true, 'routes' => true, 'bootstrap' => true]); -Cake\Core\Plugin::load('CakeAdmin', ['path' => ROOT . DS, 'autoload' => true, 'routes' => true, 'bootstrap' => true]); - -Cake\Routing\DispatcherFactory::add('Routing'); -Cake\Routing\DispatcherFactory::add('ControllerFactory'); \ No newline at end of file diff --git a/tests/config/routes.php b/tests/config/routes.php deleted file mode 100644 index e7a7a18..0000000 --- a/tests/config/routes.php +++ /dev/null @@ -1,24 +0,0 @@ -.column,.row.collapse>.columns{padding-left:0;padding-right:0}.row.collapse .row{margin-left:0;margin-right:0}.row .row{width:auto;margin-left:-0.9375rem;margin-right:-0.9375rem;margin-top:0;margin-bottom:0;max-width:none}.row .row:before,.row .row:after{content:" ";display:table}.row .row:after{clear:both}.row .row.collapse{width:auto;margin:0;max-width:none}.row .row.collapse:before,.row .row.collapse:after{content:" ";display:table}.row .row.collapse:after{clear:both}.column,.columns{padding-left:0.9375rem;padding-right:0.9375rem;width:100%;float:left}[class*="column"]+[class*="column"]:last-child{float:right}[class*="column"]+[class*="column"].end{float:left}@media only screen{.small-push-0{position:relative;left:0%;right:auto}.small-pull-0{position:relative;right:0%;left:auto}.small-push-1{position:relative;left:8.33333%;right:auto}.small-pull-1{position:relative;right:8.33333%;left:auto}.small-push-2{position:relative;left:16.66667%;right:auto}.small-pull-2{position:relative;right:16.66667%;left:auto}.small-push-3{position:relative;left:25%;right:auto}.small-pull-3{position:relative;right:25%;left:auto}.small-push-4{position:relative;left:33.33333%;right:auto}.small-pull-4{position:relative;right:33.33333%;left:auto}.small-push-5{position:relative;left:41.66667%;right:auto}.small-pull-5{position:relative;right:41.66667%;left:auto}.small-push-6{position:relative;left:50%;right:auto}.small-pull-6{position:relative;right:50%;left:auto}.small-push-7{position:relative;left:58.33333%;right:auto}.small-pull-7{position:relative;right:58.33333%;left:auto}.small-push-8{position:relative;left:66.66667%;right:auto}.small-pull-8{position:relative;right:66.66667%;left:auto}.small-push-9{position:relative;left:75%;right:auto}.small-pull-9{position:relative;right:75%;left:auto}.small-push-10{position:relative;left:83.33333%;right:auto}.small-pull-10{position:relative;right:83.33333%;left:auto}.small-push-11{position:relative;left:91.66667%;right:auto}.small-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.small-1{width:8.33333%}.small-2{width:16.66667%}.small-3{width:25%}.small-4{width:33.33333%}.small-5{width:41.66667%}.small-6{width:50%}.small-7{width:58.33333%}.small-8{width:66.66667%}.small-9{width:75%}.small-10{width:83.33333%}.small-11{width:91.66667%}.small-12{width:100%}.small-offset-0{margin-left:0% !important}.small-offset-1{margin-left:8.33333% !important}.small-offset-2{margin-left:16.66667% !important}.small-offset-3{margin-left:25% !important}.small-offset-4{margin-left:33.33333% !important}.small-offset-5{margin-left:41.66667% !important}.small-offset-6{margin-left:50% !important}.small-offset-7{margin-left:58.33333% !important}.small-offset-8{margin-left:66.66667% !important}.small-offset-9{margin-left:75% !important}.small-offset-10{margin-left:83.33333% !important}.small-offset-11{margin-left:91.66667% !important}.small-reset-order{margin-left:0;margin-right:0;left:auto;right:auto;float:left}.column.small-centered,.columns.small-centered{margin-left:auto;margin-right:auto;float:none}.column.small-uncentered,.columns.small-uncentered{margin-left:0;margin-right:0;float:left}.column.small-centered:last-child,.columns.small-centered:last-child{float:none}.column.small-uncentered:last-child,.columns.small-uncentered:last-child{float:left}.column.small-uncentered.opposite,.columns.small-uncentered.opposite{float:right}}@media only screen and (min-width: 40.063em){.medium-push-0{position:relative;left:0%;right:auto}.medium-pull-0{position:relative;right:0%;left:auto}.medium-push-1{position:relative;left:8.33333%;right:auto}.medium-pull-1{position:relative;right:8.33333%;left:auto}.medium-push-2{position:relative;left:16.66667%;right:auto}.medium-pull-2{position:relative;right:16.66667%;left:auto}.medium-push-3{position:relative;left:25%;right:auto}.medium-pull-3{position:relative;right:25%;left:auto}.medium-push-4{position:relative;left:33.33333%;right:auto}.medium-pull-4{position:relative;right:33.33333%;left:auto}.medium-push-5{position:relative;left:41.66667%;right:auto}.medium-pull-5{position:relative;right:41.66667%;left:auto}.medium-push-6{position:relative;left:50%;right:auto}.medium-pull-6{position:relative;right:50%;left:auto}.medium-push-7{position:relative;left:58.33333%;right:auto}.medium-pull-7{position:relative;right:58.33333%;left:auto}.medium-push-8{position:relative;left:66.66667%;right:auto}.medium-pull-8{position:relative;right:66.66667%;left:auto}.medium-push-9{position:relative;left:75%;right:auto}.medium-pull-9{position:relative;right:75%;left:auto}.medium-push-10{position:relative;left:83.33333%;right:auto}.medium-pull-10{position:relative;right:83.33333%;left:auto}.medium-push-11{position:relative;left:91.66667%;right:auto}.medium-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.medium-1{width:8.33333%}.medium-2{width:16.66667%}.medium-3{width:25%}.medium-4{width:33.33333%}.medium-5{width:41.66667%}.medium-6{width:50%}.medium-7{width:58.33333%}.medium-8{width:66.66667%}.medium-9{width:75%}.medium-10{width:83.33333%}.medium-11{width:91.66667%}.medium-12{width:100%}.medium-offset-0{margin-left:0% !important}.medium-offset-1{margin-left:8.33333% !important}.medium-offset-2{margin-left:16.66667% !important}.medium-offset-3{margin-left:25% !important}.medium-offset-4{margin-left:33.33333% !important}.medium-offset-5{margin-left:41.66667% !important}.medium-offset-6{margin-left:50% !important}.medium-offset-7{margin-left:58.33333% !important}.medium-offset-8{margin-left:66.66667% !important}.medium-offset-9{margin-left:75% !important}.medium-offset-10{margin-left:83.33333% !important}.medium-offset-11{margin-left:91.66667% !important}.medium-reset-order{margin-left:0;margin-right:0;left:auto;right:auto;float:left}.column.medium-centered,.columns.medium-centered{margin-left:auto;margin-right:auto;float:none}.column.medium-uncentered,.columns.medium-uncentered{margin-left:0;margin-right:0;float:left}.column.medium-centered:last-child,.columns.medium-centered:last-child{float:none}.column.medium-uncentered:last-child,.columns.medium-uncentered:last-child{float:left}.column.medium-uncentered.opposite,.columns.medium-uncentered.opposite{float:right}.push-0{position:relative;left:0%;right:auto}.pull-0{position:relative;right:0%;left:auto}.push-1{position:relative;left:8.33333%;right:auto}.pull-1{position:relative;right:8.33333%;left:auto}.push-2{position:relative;left:16.66667%;right:auto}.pull-2{position:relative;right:16.66667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.33333%;right:auto}.pull-4{position:relative;right:33.33333%;left:auto}.push-5{position:relative;left:41.66667%;right:auto}.pull-5{position:relative;right:41.66667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.33333%;right:auto}.pull-7{position:relative;right:58.33333%;left:auto}.push-8{position:relative;left:66.66667%;right:auto}.pull-8{position:relative;right:66.66667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.33333%;right:auto}.pull-10{position:relative;right:83.33333%;left:auto}.push-11{position:relative;left:91.66667%;right:auto}.pull-11{position:relative;right:91.66667%;left:auto}}@media only screen and (min-width: 64.063em){.large-push-0{position:relative;left:0%;right:auto}.large-pull-0{position:relative;right:0%;left:auto}.large-push-1{position:relative;left:8.33333%;right:auto}.large-pull-1{position:relative;right:8.33333%;left:auto}.large-push-2{position:relative;left:16.66667%;right:auto}.large-pull-2{position:relative;right:16.66667%;left:auto}.large-push-3{position:relative;left:25%;right:auto}.large-pull-3{position:relative;right:25%;left:auto}.large-push-4{position:relative;left:33.33333%;right:auto}.large-pull-4{position:relative;right:33.33333%;left:auto}.large-push-5{position:relative;left:41.66667%;right:auto}.large-pull-5{position:relative;right:41.66667%;left:auto}.large-push-6{position:relative;left:50%;right:auto}.large-pull-6{position:relative;right:50%;left:auto}.large-push-7{position:relative;left:58.33333%;right:auto}.large-pull-7{position:relative;right:58.33333%;left:auto}.large-push-8{position:relative;left:66.66667%;right:auto}.large-pull-8{position:relative;right:66.66667%;left:auto}.large-push-9{position:relative;left:75%;right:auto}.large-pull-9{position:relative;right:75%;left:auto}.large-push-10{position:relative;left:83.33333%;right:auto}.large-pull-10{position:relative;right:83.33333%;left:auto}.large-push-11{position:relative;left:91.66667%;right:auto}.large-pull-11{position:relative;right:91.66667%;left:auto}.column,.columns{position:relative;padding-left:0.9375rem;padding-right:0.9375rem;float:left}.large-1{width:8.33333%}.large-2{width:16.66667%}.large-3{width:25%}.large-4{width:33.33333%}.large-5{width:41.66667%}.large-6{width:50%}.large-7{width:58.33333%}.large-8{width:66.66667%}.large-9{width:75%}.large-10{width:83.33333%}.large-11{width:91.66667%}.large-12{width:100%}.large-offset-0{margin-left:0% !important}.large-offset-1{margin-left:8.33333% !important}.large-offset-2{margin-left:16.66667% !important}.large-offset-3{margin-left:25% !important}.large-offset-4{margin-left:33.33333% !important}.large-offset-5{margin-left:41.66667% !important}.large-offset-6{margin-left:50% !important}.large-offset-7{margin-left:58.33333% !important}.large-offset-8{margin-left:66.66667% !important}.large-offset-9{margin-left:75% !important}.large-offset-10{margin-left:83.33333% !important}.large-offset-11{margin-left:91.66667% !important}.large-reset-order{margin-left:0;margin-right:0;left:auto;right:auto;float:left}.column.large-centered,.columns.large-centered{margin-left:auto;margin-right:auto;float:none}.column.large-uncentered,.columns.large-uncentered{margin-left:0;margin-right:0;float:left}.column.large-centered:last-child,.columns.large-centered:last-child{float:none}.column.large-uncentered:last-child,.columns.large-uncentered:last-child{float:left}.column.large-uncentered.opposite,.columns.large-uncentered.opposite{float:right}.push-0{position:relative;left:0%;right:auto}.pull-0{position:relative;right:0%;left:auto}.push-1{position:relative;left:8.33333%;right:auto}.pull-1{position:relative;right:8.33333%;left:auto}.push-2{position:relative;left:16.66667%;right:auto}.pull-2{position:relative;right:16.66667%;left:auto}.push-3{position:relative;left:25%;right:auto}.pull-3{position:relative;right:25%;left:auto}.push-4{position:relative;left:33.33333%;right:auto}.pull-4{position:relative;right:33.33333%;left:auto}.push-5{position:relative;left:41.66667%;right:auto}.pull-5{position:relative;right:41.66667%;left:auto}.push-6{position:relative;left:50%;right:auto}.pull-6{position:relative;right:50%;left:auto}.push-7{position:relative;left:58.33333%;right:auto}.pull-7{position:relative;right:58.33333%;left:auto}.push-8{position:relative;left:66.66667%;right:auto}.pull-8{position:relative;right:66.66667%;left:auto}.push-9{position:relative;left:75%;right:auto}.pull-9{position:relative;right:75%;left:auto}.push-10{position:relative;left:83.33333%;right:auto}.pull-10{position:relative;right:83.33333%;left:auto}.push-11{position:relative;left:91.66667%;right:auto}.pull-11{position:relative;right:91.66667%;left:auto}}button,.button{border-style:solid;border-width:0px;cursor:pointer;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-weight:normal;line-height:normal;margin:0 0 1.25rem;position:relative;text-decoration:none;text-align:center;-webkit-appearance:none;-webkit-border-radius:0;display:inline-block;padding-top:1rem;padding-right:2rem;padding-bottom:1.0625rem;padding-left:2rem;font-size:1rem;background-color:#008cba;border-color:#007095;color:#fff;transition:background-color 300ms ease-out}button:hover,button:focus,.button:hover,.button:focus{background-color:#007095}button:hover,button:focus,.button:hover,.button:focus{color:#fff}button.secondary,.button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{background-color:#b9b9b9}button.secondary:hover,button.secondary:focus,.button.secondary:hover,.button.secondary:focus{color:#333}button.success,.button.success{background-color:#43ac6a;border-color:#368a55;color:#fff}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{background-color:#368a55}button.success:hover,button.success:focus,.button.success:hover,.button.success:focus{color:#fff}button.alert,.button.alert{background-color:#f04124;border-color:#cf2a0e;color:#fff}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{background-color:#cf2a0e}button.alert:hover,button.alert:focus,.button.alert:hover,.button.alert:focus{color:#fff}button.large,.button.large{padding-top:1.125rem;padding-right:2.25rem;padding-bottom:1.1875rem;padding-left:2.25rem;font-size:1.25rem}button.small,.button.small{padding-top:0.875rem;padding-right:1.75rem;padding-bottom:0.9375rem;padding-left:1.75rem;font-size:0.8125rem}button.tiny,.button.tiny{padding-top:0.625rem;padding-right:1.25rem;padding-bottom:0.6875rem;padding-left:1.25rem;font-size:0.6875rem}button.expand,.button.expand{padding-right:0;padding-left:0;width:100%}button.left-align,.button.left-align{text-align:left;text-indent:0.75rem}button.right-align,.button.right-align{text-align:right;padding-right:0.75rem}button.radius,.button.radius{border-radius:3px}button.round,.button.round{border-radius:1000px}button.disabled,button[disabled],.button.disabled,.button[disabled]{background-color:#008cba;border-color:#007095;color:#fff;cursor:default;opacity:0.7;box-shadow:none}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#007095}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{color:#fff}button.disabled:hover,button.disabled:focus,button[disabled]:hover,button[disabled]:focus,.button.disabled:hover,.button.disabled:focus,.button[disabled]:hover,.button[disabled]:focus{background-color:#008cba}button.disabled.secondary,button[disabled].secondary,.button.disabled.secondary,.button[disabled].secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333;cursor:default;opacity:0.7;box-shadow:none}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#b9b9b9}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{color:#333}button.disabled.secondary:hover,button.disabled.secondary:focus,button[disabled].secondary:hover,button[disabled].secondary:focus,.button.disabled.secondary:hover,.button.disabled.secondary:focus,.button[disabled].secondary:hover,.button[disabled].secondary:focus{background-color:#e7e7e7}button.disabled.success,button[disabled].success,.button.disabled.success,.button[disabled].success{background-color:#43ac6a;border-color:#368a55;color:#fff;cursor:default;opacity:0.7;box-shadow:none}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#368a55}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{color:#fff}button.disabled.success:hover,button.disabled.success:focus,button[disabled].success:hover,button[disabled].success:focus,.button.disabled.success:hover,.button.disabled.success:focus,.button[disabled].success:hover,.button[disabled].success:focus{background-color:#43ac6a}button.disabled.alert,button[disabled].alert,.button.disabled.alert,.button[disabled].alert{background-color:#f04124;border-color:#cf2a0e;color:#fff;cursor:default;opacity:0.7;box-shadow:none}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#cf2a0e}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{color:#fff}button.disabled.alert:hover,button.disabled.alert:focus,button[disabled].alert:hover,button[disabled].alert:focus,.button.disabled.alert:hover,.button.disabled.alert:focus,.button[disabled].alert:hover,.button[disabled].alert:focus{background-color:#f04124}button::-moz-focus-inner{border:0;padding:0}@media only screen and (min-width: 40.063em){button,.button{display:inline-block}}meta.foundation-mq-topbar{font-family:"/only screen and (min-width:40.063em)/";width:40.063em}.contain-to-grid{width:100%;background:#333}.contain-to-grid .top-bar{margin-bottom:0}.fixed{width:100%;left:0;position:fixed;top:0;z-index:99}.fixed.expanded:not(.top-bar){overflow-y:auto;height:auto;width:100%;max-height:100%}.fixed.expanded:not(.top-bar) .title-area{position:fixed;width:100%;z-index:99}.fixed.expanded:not(.top-bar) .top-bar-section{z-index:98;margin-top:45px}.top-bar{overflow:hidden;height:45px;line-height:45px;position:relative;background:#333;margin-bottom:0}.top-bar ul{margin-bottom:0;list-style:none}.top-bar .row{max-width:none}.top-bar form,.top-bar input{margin-bottom:0}.top-bar input{height:1.8rem;padding-top:.35rem;padding-bottom:.35rem;font-size:0.75rem}.top-bar .button,.top-bar button{padding-top:.45rem;padding-bottom:.35rem;margin-bottom:0;font-size:0.75rem}.top-bar .title-area{position:relative;margin:0}.top-bar .name{height:45px;margin:0;font-size:16px}.top-bar .name h1{line-height:45px;font-size:1.0625rem;margin:0}.top-bar .name h1 a{font-weight:normal;color:#fff;width:75%;display:block;padding:0 15px}.top-bar .toggle-topbar{position:absolute;right:0;top:0}.top-bar .toggle-topbar a{color:#fff;text-transform:uppercase;font-size:0.8125rem;font-weight:bold;position:relative;display:block;padding:0 15px;height:45px;line-height:45px}.top-bar .toggle-topbar.menu-icon{top:50%;margin-top:-16px}.top-bar .toggle-topbar.menu-icon a{height:34px;line-height:33px;padding:0 40px 0 15px;color:#fff;position:relative}.top-bar .toggle-topbar.menu-icon a span::after{content:"";position:absolute;display:block;height:0;top:50%;margin-top:-8px;right:15px;box-shadow:0 0px 0 1px #fff,0 7px 0 1px #fff,0 14px 0 1px #fff;width:16px}.top-bar .toggle-topbar.menu-icon a span:hover:after{box-shadow:0 0px 0 1px #fff,0 7px 0 1px #fff,0 14px 0 1px #fff}.top-bar.expanded{height:auto;background:transparent}.top-bar.expanded .title-area{background:#333}.top-bar.expanded .toggle-topbar a{color:#888}.top-bar.expanded .toggle-topbar a::after{box-shadow:0 10px 0 1px #888,0 16px 0 1px #888,0 22px 0 1px #888}.top-bar-section{left:0;position:relative;width:auto;transition:left 300ms ease-out}.top-bar-section ul{padding:0;width:100%;height:auto;display:block;font-size:16px;margin:0}.top-bar-section .divider,.top-bar-section [role="separator"]{border-top:solid 1px #1a1a1a;clear:both;height:1px;width:100%}.top-bar-section ul li{background:#333}.top-bar-section ul li>a{display:block;width:100%;color:#fff;padding:12px 0 12px 0;padding-left:15px;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-size:0.8125rem;font-weight:normal;text-transform:none}.top-bar-section ul li>a.button{font-size:0.8125rem;padding-right:15px;padding-left:15px;background-color:#008cba;border-color:#007095;color:#fff}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{background-color:#007095}.top-bar-section ul li>a.button:hover,.top-bar-section ul li>a.button:focus{color:#fff}.top-bar-section ul li>a.button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{background-color:#b9b9b9}.top-bar-section ul li>a.button.secondary:hover,.top-bar-section ul li>a.button.secondary:focus{color:#333}.top-bar-section ul li>a.button.success{background-color:#43ac6a;border-color:#368a55;color:#fff}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{background-color:#368a55}.top-bar-section ul li>a.button.success:hover,.top-bar-section ul li>a.button.success:focus{color:#fff}.top-bar-section ul li>a.button.alert{background-color:#f04124;border-color:#cf2a0e;color:#fff}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{background-color:#cf2a0e}.top-bar-section ul li>a.button.alert:hover,.top-bar-section ul li>a.button.alert:focus{color:#fff}.top-bar-section ul li>button{font-size:0.8125rem;padding-right:15px;padding-left:15px;background-color:#008cba;border-color:#007095;color:#fff}.top-bar-section ul li>button:hover,.top-bar-section ul li>button:focus{background-color:#007095}.top-bar-section ul li>button:hover,.top-bar-section ul li>button:focus{color:#fff}.top-bar-section ul li>button.secondary{background-color:#e7e7e7;border-color:#b9b9b9;color:#333}.top-bar-section ul li>button.secondary:hover,.top-bar-section ul li>button.secondary:focus{background-color:#b9b9b9}.top-bar-section ul li>button.secondary:hover,.top-bar-section ul li>button.secondary:focus{color:#333}.top-bar-section ul li>button.success{background-color:#43ac6a;border-color:#368a55;color:#fff}.top-bar-section ul li>button.success:hover,.top-bar-section ul li>button.success:focus{background-color:#368a55}.top-bar-section ul li>button.success:hover,.top-bar-section ul li>button.success:focus{color:#fff}.top-bar-section ul li>button.alert{background-color:#f04124;border-color:#cf2a0e;color:#fff}.top-bar-section ul li>button.alert:hover,.top-bar-section ul li>button.alert:focus{background-color:#cf2a0e}.top-bar-section ul li>button.alert:hover,.top-bar-section ul li>button.alert:focus{color:#fff}.top-bar-section ul li:hover:not(.has-form)>a{background-color:#555;background:#272727;color:#fff}.top-bar-section ul li.active>a{background:#008cba;color:#fff}.top-bar-section ul li.active>a:hover{background:#0078a0;color:#fff}.top-bar-section .has-form{padding:15px}.top-bar-section .has-dropdown{position:relative}.top-bar-section .has-dropdown>a:after{content:"";display:block;width:0;height:0;border:inset 5px;border-color:transparent transparent transparent rgba(255,255,255,0.4);border-left-style:solid;margin-right:15px;margin-top:-4.5px;position:absolute;top:50%;right:0}.top-bar-section .has-dropdown.moved{position:static}.top-bar-section .has-dropdown.moved>.dropdown{display:block;position:static !important;height:auto;width:auto;overflow:visible;clip:auto;position:absolute !important;width:100%}.top-bar-section .has-dropdown.moved>a:after{display:none}.top-bar-section .dropdown{padding:0;position:absolute;left:100%;top:0;z-index:99;display:block;position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}.top-bar-section .dropdown li{width:100%;height:auto}.top-bar-section .dropdown li a{font-weight:normal;padding:8px 15px}.top-bar-section .dropdown li a.parent-link{font-weight:normal}.top-bar-section .dropdown li.title h5,.top-bar-section .dropdown li.parent-link{margin-bottom:0;margin-top:0}.top-bar-section .dropdown li.title h5 a,.top-bar-section .dropdown li.parent-link a{color:#fff;line-height:22.5px;display:block}.top-bar-section .dropdown li.title h5 a:hover,.top-bar-section .dropdown li.parent-link a:hover{background:none}.top-bar-section .dropdown li.has-form{padding:8px 15px}.top-bar-section .dropdown li .button,.top-bar-section .dropdown li button{top:auto}.top-bar-section .dropdown label{padding:8px 15px 2px;margin-bottom:0;text-transform:uppercase;color:#777;font-weight:bold;font-size:0.625rem}.js-generated{display:block}@media only screen and (min-width: 40.063em){.top-bar{background:#333;overflow:visible}.top-bar:before,.top-bar:after{content:" ";display:table}.top-bar:after{clear:both}.top-bar .toggle-topbar{display:none}.top-bar .title-area{float:left}.top-bar .name h1 a{width:auto}.top-bar input,.top-bar .button,.top-bar button{font-size:0.875rem;position:relative;top:7px}.top-bar.expanded{background:#333}.contain-to-grid .top-bar{max-width:62.5rem;margin:0 auto;margin-bottom:0}.top-bar-section{transition:none 0 0;left:0 !important}.top-bar-section ul{width:auto;height:auto !important;display:inline}.top-bar-section ul li{float:left}.top-bar-section ul li .js-generated{display:none}.top-bar-section li.hover>a:not(.button){background-color:#555;background:#272727;color:#fff}.top-bar-section li:not(.has-form) a:not(.button){padding:0 15px;line-height:45px;background:#333}.top-bar-section li:not(.has-form) a:not(.button):hover{background-color:#555;background:#272727}.top-bar-section li.active:not(.has-form) a:not(.button){padding:0 15px;line-height:45px;color:#fff;background:#008cba}.top-bar-section li.active:not(.has-form) a:not(.button):hover{background:#0078a0;color:#fff}.top-bar-section .has-dropdown>a{padding-right:35px !important}.top-bar-section .has-dropdown>a:after{content:"";display:block;width:0;height:0;border:inset 5px;border-color:rgba(255,255,255,0.4) transparent transparent transparent;border-top-style:solid;margin-top:-2.5px;top:22.5px}.top-bar-section .has-dropdown.moved{position:relative}.top-bar-section .has-dropdown.moved>.dropdown{display:block;position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}.top-bar-section .has-dropdown.hover>.dropdown,.top-bar-section .has-dropdown.not-click:hover>.dropdown{display:block;position:static !important;height:auto;width:auto;overflow:visible;clip:auto;position:absolute !important}.top-bar-section .has-dropdown .dropdown li.has-dropdown>a:after{border:none;content:"\00bb";top:1rem;margin-top:-1px;right:5px;line-height:1.2}.top-bar-section .dropdown{left:0;top:auto;background:transparent;min-width:100%}.top-bar-section .dropdown li a{color:#fff;line-height:45px;white-space:nowrap;padding:12px 15px;background:#333}.top-bar-section .dropdown li:not(.has-form):not(.active)>a:not(.button){color:#fff;background:#333}.top-bar-section .dropdown li:not(.has-form):not(.active):hover>a:not(.button){color:#fff;background-color:#555;background:#272727}.top-bar-section .dropdown li label{white-space:nowrap;background:#333}.top-bar-section .dropdown li .dropdown{left:100%;top:0}.top-bar-section>ul>.divider,.top-bar-section>ul>[role="separator"]{border-bottom:none;border-top:none;border-right:solid 1px #4e4e4e;clear:none;height:45px;width:0}.top-bar-section .has-form{background:#333;padding:0 15px;height:45px}.top-bar-section .right li .dropdown{left:auto;right:0}.top-bar-section .right li .dropdown li .dropdown{right:100%}.top-bar-section .left li .dropdown{right:auto;left:0}.top-bar-section .left li .dropdown li .dropdown{left:100%}.no-js .top-bar-section ul li:hover>a{background-color:#555;background:#272727;color:#fff}.no-js .top-bar-section ul li:active>a{background:#008cba;color:#fff}.no-js .top-bar-section .has-dropdown:hover>.dropdown{display:block;position:static !important;height:auto;width:auto;overflow:visible;clip:auto;position:absolute !important}}.breadcrumbs{display:block;padding:0.5625rem 0.875rem 0.5625rem;overflow:hidden;margin-left:0;list-style:none;border-style:solid;border-width:1px;background-color:#f4f4f4;border-color:#dcdcdc;border-radius:3px}.breadcrumbs>*{margin:0;float:left;font-size:0.6875rem;line-height:0.6875rem;text-transform:uppercase;color:#008cba}.breadcrumbs>*:hover a,.breadcrumbs>*:focus a{text-decoration:underline}.breadcrumbs>* a{color:#008cba}.breadcrumbs>*.current{cursor:default;color:#333}.breadcrumbs>*.current a{cursor:default;color:#333}.breadcrumbs>*.current:hover,.breadcrumbs>*.current:hover a,.breadcrumbs>*.current:focus,.breadcrumbs>*.current:focus a{text-decoration:none}.breadcrumbs>*.unavailable{color:#999}.breadcrumbs>*.unavailable a{color:#999}.breadcrumbs>*.unavailable:hover,.breadcrumbs>*.unavailable:hover a,.breadcrumbs>*.unavailable:focus,.breadcrumbs>*.unavailable a:focus{text-decoration:none;color:#999;cursor:default}.breadcrumbs>*:before{content:"/";color:#aaa;margin:0 0.75rem;position:relative;top:1px}.breadcrumbs>*:first-child:before{content:" ";margin:0}[aria-label="breadcrumbs"] [aria-hidden="true"]:after{content:"/"}.alert-box{border-style:solid;border-width:1px;display:block;font-weight:normal;margin-bottom:1.25rem;position:relative;padding:0.875rem 1.5rem 0.875rem 0.875rem;font-size:0.8125rem;transition:opacity 300ms ease-out;background-color:#008cba;border-color:#0078a0;color:#fff}.alert-box .close{font-size:1.375rem;padding:9px 6px 4px;line-height:0;position:absolute;top:50%;margin-top:-0.6875rem;right:0.25rem;color:#333;opacity:0.3}.alert-box .close:hover,.alert-box .close:focus{opacity:0.5}.alert-box.radius{border-radius:3px}.alert-box.round{border-radius:1000px}.alert-box.success{background-color:#43ac6a;border-color:#3a945b;color:#fff}.alert-box.alert{background-color:#f04124;border-color:#de2d0f;color:#fff}.alert-box.secondary{background-color:#e7e7e7;border-color:#c7c7c7;color:#4f4f4f}.alert-box.warning{background-color:#f08a24;border-color:#de770f;color:#fff}.alert-box.info{background-color:#a0d3e8;border-color:#74bfdd;color:#4f4f4f}.alert-box.alert-close{opacity:0}.inline-list{margin:0 auto 1.0625rem auto;margin-left:-1.375rem;margin-right:0;padding:0;list-style:none;overflow:hidden}.inline-list>li{list-style:none;float:left;margin-left:1.375rem;display:block}.inline-list>li>*{display:block}.button-group{list-style:none;margin:0;left:0}.button-group:before,.button-group:after{content:" ";display:table}.button-group:after{clear:both}.button-group>li{margin:0 -2px;float:none;display:inline-block}.button-group>li>button,.button-group>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group>li:first-child button,.button-group>li:first-child .button{border-left:0}.button-group.stack>li{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.stack>li>button,.button-group.stack>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack>li:first-child button,.button-group.stack>li:first-child .button{border-left:0}.button-group.stack>li>button,.button-group.stack>li .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.stack>li:first-child button,.button-group.stack>li:first-child .button{border-top:0}.button-group.stack-for-small>li{margin:0 -2px;float:none;display:inline-block}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-left:0}@media only screen and (max-width: 40em){.button-group.stack-for-small>li{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-left:0}.button-group.stack-for-small>li>button,.button-group.stack-for-small>li .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.stack-for-small>li:first-child button,.button-group.stack-for-small>li:first-child .button{border-top:0}}.button-group.radius>*{margin:0 -2px;float:none;display:inline-block}.button-group.radius>*>button,.button-group.radius>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius>*:first-child button,.button-group.radius>*:first-child .button{border-left:0}.button-group.radius>*,.button-group.radius>*>a,.button-group.radius>*>button,.button-group.radius>*>.button{border-radius:0}.button-group.radius>*:first-child,.button-group.radius>*:first-child>a,.button-group.radius>*:first-child>button,.button-group.radius>*:first-child>.button{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.button-group.radius>*:last-child,.button-group.radius>*:last-child>a,.button-group.radius>*:last-child>button,.button-group.radius>*:last-child>.button{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.button-group.radius.stack>*{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.radius.stack>*>button,.button-group.radius.stack>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack>*:first-child button,.button-group.radius.stack>*:first-child .button{border-left:0}.button-group.radius.stack>*>button,.button-group.radius.stack>* .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.radius.stack>*:first-child button,.button-group.radius.stack>*:first-child .button{border-top:0}.button-group.radius.stack>*,.button-group.radius.stack>*>a,.button-group.radius.stack>*>button,.button-group.radius.stack>*>.button{border-radius:0}.button-group.radius.stack>*:first-child,.button-group.radius.stack>*:first-child>a,.button-group.radius.stack>*:first-child>button,.button-group.radius.stack>*:first-child>.button{-webkit-top-left-radius:3px;-webkit-top-right-radius:3px;border-top-left-radius:3px;border-top-right-radius:3px}.button-group.radius.stack>*:last-child,.button-group.radius.stack>*:last-child>a,.button-group.radius.stack>*:last-child>button,.button-group.radius.stack>*:last-child>.button{-webkit-bottom-left-radius:3px;-webkit-bottom-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px}@media only screen and (min-width: 40.063em){.button-group.radius.stack-for-small>*{margin:0 -2px;float:none;display:inline-block}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-left:0}.button-group.radius.stack-for-small>*,.button-group.radius.stack-for-small>*>a,.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>*>.button{border-radius:0}.button-group.radius.stack-for-small>*:first-child,.button-group.radius.stack-for-small>*:first-child>a,.button-group.radius.stack-for-small>*:first-child>button,.button-group.radius.stack-for-small>*:first-child>.button{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.button-group.radius.stack-for-small>*:last-child,.button-group.radius.stack-for-small>*:last-child>a,.button-group.radius.stack-for-small>*:last-child>button,.button-group.radius.stack-for-small>*:last-child>.button{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}}@media only screen and (max-width: 40em){.button-group.radius.stack-for-small>*{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-left:0}.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>* .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.radius.stack-for-small>*:first-child button,.button-group.radius.stack-for-small>*:first-child .button{border-top:0}.button-group.radius.stack-for-small>*,.button-group.radius.stack-for-small>*>a,.button-group.radius.stack-for-small>*>button,.button-group.radius.stack-for-small>*>.button{border-radius:0}.button-group.radius.stack-for-small>*:first-child,.button-group.radius.stack-for-small>*:first-child>a,.button-group.radius.stack-for-small>*:first-child>button,.button-group.radius.stack-for-small>*:first-child>.button{-webkit-top-left-radius:3px;-webkit-top-right-radius:3px;border-top-left-radius:3px;border-top-right-radius:3px}.button-group.radius.stack-for-small>*:last-child,.button-group.radius.stack-for-small>*:last-child>a,.button-group.radius.stack-for-small>*:last-child>button,.button-group.radius.stack-for-small>*:last-child>.button{-webkit-bottom-left-radius:3px;-webkit-bottom-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px}}.button-group.round>*{margin:0 -2px;float:none;display:inline-block}.button-group.round>*>button,.button-group.round>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round>*:first-child button,.button-group.round>*:first-child .button{border-left:0}.button-group.round>*,.button-group.round>*>a,.button-group.round>*>button,.button-group.round>*>.button{border-radius:0}.button-group.round>*:first-child,.button-group.round>*:first-child>a,.button-group.round>*:first-child>button,.button-group.round>*:first-child>.button{-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.button-group.round>*:last-child,.button-group.round>*:last-child>a,.button-group.round>*:last-child>button,.button-group.round>*:last-child>.button{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}.button-group.round.stack>*{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.round.stack>*>button,.button-group.round.stack>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack>*:first-child button,.button-group.round.stack>*:first-child .button{border-left:0}.button-group.round.stack>*>button,.button-group.round.stack>* .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.round.stack>*:first-child button,.button-group.round.stack>*:first-child .button{border-top:0}.button-group.round.stack>*,.button-group.round.stack>*>a,.button-group.round.stack>*>button,.button-group.round.stack>*>.button{border-radius:0}.button-group.round.stack>*:first-child,.button-group.round.stack>*:first-child>a,.button-group.round.stack>*:first-child>button,.button-group.round.stack>*:first-child>.button{-webkit-top-left-radius:1rem;-webkit-top-right-radius:1rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.button-group.round.stack>*:last-child,.button-group.round.stack>*:last-child>a,.button-group.round.stack>*:last-child>button,.button-group.round.stack>*:last-child>.button{-webkit-bottom-left-radius:1rem;-webkit-bottom-right-radius:1rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}@media only screen and (min-width: 40.063em){.button-group.round.stack-for-small>*{margin:0 -2px;float:none;display:inline-block}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-left:0}.button-group.round.stack-for-small>*,.button-group.round.stack-for-small>*>a,.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>*>.button{border-radius:0}.button-group.round.stack-for-small>*:first-child,.button-group.round.stack-for-small>*:first-child>a,.button-group.round.stack-for-small>*:first-child>button,.button-group.round.stack-for-small>*:first-child>.button{-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.button-group.round.stack-for-small>*:last-child,.button-group.round.stack-for-small>*:last-child>a,.button-group.round.stack-for-small>*:last-child>button,.button-group.round.stack-for-small>*:last-child>.button{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}}@media only screen and (max-width: 40em){.button-group.round.stack-for-small>*{margin:0 -2px;float:none;display:inline-block;display:block;margin:0}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-left:0}.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>* .button{border-top:1px solid;border-color:rgba(255,255,255,0.5);border-left-width:0px;margin:0;display:block}.button-group.round.stack-for-small>*:first-child button,.button-group.round.stack-for-small>*:first-child .button{border-top:0}.button-group.round.stack-for-small>*,.button-group.round.stack-for-small>*>a,.button-group.round.stack-for-small>*>button,.button-group.round.stack-for-small>*>.button{border-radius:0}.button-group.round.stack-for-small>*:first-child,.button-group.round.stack-for-small>*:first-child>a,.button-group.round.stack-for-small>*:first-child>button,.button-group.round.stack-for-small>*:first-child>.button{-webkit-top-left-radius:1rem;-webkit-top-right-radius:1rem;border-top-left-radius:1rem;border-top-right-radius:1rem}.button-group.round.stack-for-small>*:last-child,.button-group.round.stack-for-small>*:last-child>a,.button-group.round.stack-for-small>*:last-child>button,.button-group.round.stack-for-small>*:last-child>.button{-webkit-bottom-left-radius:1rem;-webkit-bottom-right-radius:1rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}}.button-group.even-2 li{margin:0 -2px;float:none;display:inline-block;width:50%}.button-group.even-2 li>button,.button-group.even-2 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-2 li:first-child button,.button-group.even-2 li:first-child .button{border-left:0}.button-group.even-2 li button,.button-group.even-2 li .button{width:100%}.button-group.even-3 li{margin:0 -2px;float:none;display:inline-block;width:33.33333%}.button-group.even-3 li>button,.button-group.even-3 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-3 li:first-child button,.button-group.even-3 li:first-child .button{border-left:0}.button-group.even-3 li button,.button-group.even-3 li .button{width:100%}.button-group.even-4 li{margin:0 -2px;float:none;display:inline-block;width:25%}.button-group.even-4 li>button,.button-group.even-4 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-4 li:first-child button,.button-group.even-4 li:first-child .button{border-left:0}.button-group.even-4 li button,.button-group.even-4 li .button{width:100%}.button-group.even-5 li{margin:0 -2px;float:none;display:inline-block;width:20%}.button-group.even-5 li>button,.button-group.even-5 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-5 li:first-child button,.button-group.even-5 li:first-child .button{border-left:0}.button-group.even-5 li button,.button-group.even-5 li .button{width:100%}.button-group.even-6 li{margin:0 -2px;float:none;display:inline-block;width:16.66667%}.button-group.even-6 li>button,.button-group.even-6 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-6 li:first-child button,.button-group.even-6 li:first-child .button{border-left:0}.button-group.even-6 li button,.button-group.even-6 li .button{width:100%}.button-group.even-7 li{margin:0 -2px;float:none;display:inline-block;width:14.28571%}.button-group.even-7 li>button,.button-group.even-7 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-7 li:first-child button,.button-group.even-7 li:first-child .button{border-left:0}.button-group.even-7 li button,.button-group.even-7 li .button{width:100%}.button-group.even-8 li{margin:0 -2px;float:none;display:inline-block;width:12.5%}.button-group.even-8 li>button,.button-group.even-8 li .button{border-left:1px solid;border-color:rgba(255,255,255,0.5)}.button-group.even-8 li:first-child button,.button-group.even-8 li:first-child .button{border-left:0}.button-group.even-8 li button,.button-group.even-8 li .button{width:100%}.button-bar:before,.button-bar:after{content:" ";display:table}.button-bar:after{clear:both}.button-bar .button-group{float:left;margin-right:0.625rem}.button-bar .button-group div{overflow:hidden}.panel{border-style:solid;border-width:1px;border-color:#d8d8d8;margin-bottom:1.25rem;padding:1.25rem;background:#f2f2f2}.panel>:first-child{margin-top:0}.panel>:last-child{margin-bottom:0}.panel h1,.panel h2,.panel h3,.panel h4,.panel h5,.panel h6,.panel p,.panel li,.panel dl{color:#333}.panel h1,.panel h2,.panel h3,.panel h4,.panel h5,.panel h6{line-height:1;margin-bottom:0.625rem}.panel h1.subheader,.panel h2.subheader,.panel h3.subheader,.panel h4.subheader,.panel h5.subheader,.panel h6.subheader{line-height:1.4}.panel.callout{border-style:solid;border-width:1px;border-color:#b6edff;margin-bottom:1.25rem;padding:1.25rem;background:#ecfaff}.panel.callout>:first-child{margin-top:0}.panel.callout>:last-child{margin-bottom:0}.panel.callout h1,.panel.callout h2,.panel.callout h3,.panel.callout h4,.panel.callout h5,.panel.callout h6,.panel.callout p,.panel.callout li,.panel.callout dl{color:#333}.panel.callout h1,.panel.callout h2,.panel.callout h3,.panel.callout h4,.panel.callout h5,.panel.callout h6{line-height:1;margin-bottom:0.625rem}.panel.callout h1.subheader,.panel.callout h2.subheader,.panel.callout h3.subheader,.panel.callout h4.subheader,.panel.callout h5.subheader,.panel.callout h6.subheader{line-height:1.4}.panel.callout a:not(.button){color:#008cba}.panel.radius{border-radius:3px}.dropdown.button,button.dropdown{position:relative;padding-right:3.5625rem}.dropdown.button:after,button.dropdown:after{position:absolute;content:"";width:0;height:0;display:block;border-style:solid;border-color:#fff transparent transparent transparent;top:50%}.dropdown.button:after,button.dropdown:after{border-width:0.375rem;right:1.40625rem;margin-top:-0.15625rem}.dropdown.button:after,button.dropdown:after{border-color:#fff transparent transparent transparent}.dropdown.button.tiny,button.dropdown.tiny{padding-right:2.625rem}.dropdown.button.tiny:before,button.dropdown.tiny:before{border-width:0.375rem;right:1.125rem;margin-top:-0.125rem}.dropdown.button.tiny:after,button.dropdown.tiny:after{border-color:#fff transparent transparent transparent}.dropdown.button.small,button.dropdown.small{padding-right:3.0625rem}.dropdown.button.small:after,button.dropdown.small:after{border-width:0.4375rem;right:1.3125rem;margin-top:-0.15625rem}.dropdown.button.small:after,button.dropdown.small:after{border-color:#fff transparent transparent transparent}.dropdown.button.large,button.dropdown.large{padding-right:3.625rem}.dropdown.button.large:after,button.dropdown.large:after{border-width:0.3125rem;right:1.71875rem;margin-top:-0.15625rem}.dropdown.button.large:after,button.dropdown.large:after{border-color:#fff transparent transparent transparent}.dropdown.button.secondary:after,button.dropdown.secondary:after{border-color:#333 transparent transparent transparent}.th{line-height:0;display:inline-block;border:solid 4px #fff;max-width:100%;box-shadow:0 0 0 1px rgba(0,0,0,0.2);transition:all 200ms ease-out}.th:hover,.th:focus{box-shadow:0 0 6px 1px rgba(0,140,186,0.5)}.th.radius{border-radius:3px}.toolbar{background:#333;width:100%;font-size:0;display:inline-block}.toolbar.label-bottom .tab .tab-content i,.toolbar.label-bottom .tab .tab-content img{margin-bottom:10px}.toolbar.label-right .tab .tab-content i,.toolbar.label-right .tab .tab-content img{margin-right:10px;display:inline-block}.toolbar.label-right .tab .tab-content label{display:inline-block}.toolbar.vertical.label-right .tab .tab-content{text-align:left}.toolbar.vertical{height:100%;width:auto}.toolbar.vertical .tab{width:auto;margin:auto;float:none}.toolbar .tab{text-align:center;width:25%;margin:0 auto;display:block;padding:20px;float:left}.toolbar .tab:hover{background:rgba(255,255,255,0.1)}.toolbar .tab-content{font-size:16px;text-align:center}.toolbar .tab-content label{color:#ccc}.toolbar .tab-content i{font-size:30px;display:block;margin:0 auto;color:#ccc;vertical-align:middle}.toolbar .tab-content img{width:30px;height:30px;display:block;margin:0 auto}.pricing-table{border:solid 1px #ddd;margin-left:0;margin-bottom:1.25rem}.pricing-table *{list-style:none;line-height:1}.pricing-table .title{background-color:#333;padding:0.9375rem 1.25rem;text-align:center;color:#eee;font-weight:normal;font-size:1rem;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif}.pricing-table .price{background-color:#f6f6f6;padding:0.9375rem 1.25rem;text-align:center;color:#333;font-weight:normal;font-size:2rem;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif}.pricing-table .description{background-color:#fff;padding:0.9375rem;text-align:center;color:#777;font-size:0.75rem;font-weight:normal;line-height:1.4;border-bottom:dotted 1px #ddd}.pricing-table .bullet-item{background-color:#fff;padding:0.9375rem;text-align:center;color:#333;font-size:0.875rem;font-weight:normal;border-bottom:dotted 1px #ddd}.pricing-table .cta-button{background-color:#fff;text-align:center;padding:1.25rem 1.25rem 0}@-webkit-keyframes rotate{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotate{from{-moz-transform:rotate(0deg)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotate{from{-o-transform:rotate(0deg)}to{-o-transform:rotate(360deg)}}@keyframes rotate{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.slideshow-wrapper{position:relative}.slideshow-wrapper ul{list-style-type:none;margin:0}.slideshow-wrapper ul li,.slideshow-wrapper ul li .orbit-caption{display:none}.slideshow-wrapper ul li:first-child{display:block}.slideshow-wrapper .orbit-container{background-color:transparent}.slideshow-wrapper .orbit-container li{display:block}.slideshow-wrapper .orbit-container li .orbit-caption{display:block}.slideshow-wrapper .orbit-container .orbit-bullets li{display:inline-block}.slideshow-wrapper .preloader{display:block;width:40px;height:40px;position:absolute;top:50%;left:50%;margin-top:-20px;margin-left:-20px;border:solid 3px;border-color:#555 #fff;border-radius:1000px;animation-name:rotate;animation-duration:1.5s;animation-iteration-count:infinite;animation-timing-function:linear}.orbit-container{overflow:hidden;width:100%;position:relative;background:none}.orbit-container .orbit-slides-container{list-style:none;margin:0;padding:0;position:relative;-webkit-transform:translateZ(0)}.orbit-container .orbit-slides-container img{display:block;max-width:100%}.orbit-container .orbit-slides-container>*{position:absolute;top:0;width:100%;margin-left:100%}.orbit-container .orbit-slides-container>*:first-child{margin-left:0%}.orbit-container .orbit-slides-container>* .orbit-caption{position:absolute;bottom:0;background-color:rgba(51,51,51,0.8);color:#fff;width:100%;padding:0.625rem 0.875rem;font-size:0.875rem}.orbit-container .orbit-slide-number{position:absolute;top:10px;left:10px;font-size:12px;color:#fff;background:rgba(0,0,0,0);z-index:10}.orbit-container .orbit-slide-number span{font-weight:700;padding:0.3125rem}.orbit-container .orbit-timer{position:absolute;top:12px;right:10px;height:6px;width:100px;z-index:10}.orbit-container .orbit-timer .orbit-progress{height:3px;background-color:rgba(255,255,255,0.3);display:block;width:0%;position:relative;right:20px;top:5px}.orbit-container .orbit-timer>span{display:none;position:absolute;top:0px;right:0;width:11px;height:14px;border:solid 4px #fff;border-top:none;border-bottom:none}.orbit-container .orbit-timer.paused>span{right:-4px;top:0px;width:11px;height:14px;border:inset 8px;border-left-style:solid;border-color:transparent;border-left-color:#fff}.orbit-container .orbit-timer.paused>span.dark{border-left-color:#333}.orbit-container:hover .orbit-timer>span{display:block}.orbit-container .orbit-prev,.orbit-container .orbit-next{position:absolute;top:45%;margin-top:-25px;width:36px;height:60px;line-height:50px;color:white;background-color:transparent;text-indent:-9999px !important;z-index:10}.orbit-container .orbit-prev:hover,.orbit-container .orbit-next:hover{background-color:rgba(0,0,0,0.3)}.orbit-container .orbit-prev>span,.orbit-container .orbit-next>span{position:absolute;top:50%;margin-top:-10px;display:block;width:0;height:0;border:inset 10px}.orbit-container .orbit-prev{left:0}.orbit-container .orbit-prev>span{border-right-style:solid;border-color:transparent;border-right-color:#fff}.orbit-container .orbit-prev:hover>span{border-right-color:#fff}.orbit-container .orbit-next{right:0}.orbit-container .orbit-next>span{border-color:transparent;border-left-style:solid;border-left-color:#fff;left:50%;margin-left:-4px}.orbit-container .orbit-next:hover>span{border-left-color:#fff}.orbit-bullets-container{text-align:center}.orbit-bullets{margin:0 auto 30px auto;overflow:hidden;position:relative;top:10px;float:none;text-align:center;display:block}.orbit-bullets li{cursor:pointer;display:inline-block;width:0.5625rem;height:0.5625rem;background:#ccc;float:none;margin-right:6px;border-radius:1000px}.orbit-bullets li.active{background:#999}.orbit-bullets li:last-child{margin-right:0}.touch .orbit-container .orbit-prev,.touch .orbit-container .orbit-next{display:none}.touch .orbit-bullets{display:none}@media only screen and (min-width: 40.063em){.touch .orbit-container .orbit-prev,.touch .orbit-container .orbit-next{display:inherit}.touch .orbit-bullets{display:block}}@media only screen and (max-width: 40em){.orbit-stack-on-small .orbit-slides-container{height:auto !important}.orbit-stack-on-small .orbit-slides-container>*{position:relative;margin:0% !important;opacity:1 !important}.orbit-stack-on-small .orbit-slide-number{display:none}.orbit-timer{display:none}.orbit-next,.orbit-prev{display:none}.orbit-bullets{display:none}}[data-magellan-expedition],[data-magellan-expedition-clone]{background:#fff;z-index:50;min-width:100%;padding:10px}[data-magellan-expedition] .sub-nav,[data-magellan-expedition-clone] .sub-nav{margin-bottom:0}[data-magellan-expedition] .sub-nav dd,[data-magellan-expedition-clone] .sub-nav dd{margin-bottom:0}[data-magellan-expedition] .sub-nav a,[data-magellan-expedition-clone] .sub-nav a{line-height:1.8em}.icon-bar{width:100%;font-size:0;display:inline-block;background:#333}.icon-bar>*{text-align:center;font-size:1rem;width:25%;margin:0 auto;display:block;padding:1.25rem;float:left}.icon-bar>* i,.icon-bar>* img{display:block;margin:0 auto}.icon-bar>* i+label,.icon-bar>* img+label{margin-top:.0625rem}.icon-bar>* i{font-size:1.875rem;vertical-align:middle}.icon-bar>* img{width:1.875rem;height:1.875rem}.icon-bar.label-right>* i,.icon-bar.label-right>* img{margin:0 0.0625rem 0 0;display:inline-block}.icon-bar.label-right>* i+label,.icon-bar.label-right>* img+label{margin-top:0}.icon-bar.label-right>* label{display:inline-block}.icon-bar.vertical.label-right>*{text-align:left}.icon-bar.vertical,.icon-bar.small-vertical{height:100%;width:auto}.icon-bar.vertical .item,.icon-bar.small-vertical .item{width:auto;margin:auto;float:none}@media only screen and (min-width: 40.063em){.icon-bar.medium-vertical{height:100%;width:auto}.icon-bar.medium-vertical .item{width:auto;margin:auto;float:none}}@media only screen and (min-width: 64.063em){.icon-bar.large-vertical{height:100%;width:auto}.icon-bar.large-vertical .item{width:auto;margin:auto;float:none}}.icon-bar>*{font-size:1rem;padding:1.25rem}.icon-bar>* i+label,.icon-bar>* img+label{margin-top:.0625rem}.icon-bar>* i{font-size:1.875rem}.icon-bar>* img{width:1.875rem;height:1.875rem}.icon-bar>*:hover{background:#008cba}.icon-bar>* label{color:#fff}.icon-bar>* i{color:#fff}.icon-bar.two-up .item{width:50%}.icon-bar.two-up.vertical .item,.icon-bar.two-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.063em){.icon-bar.two-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.063em){.icon-bar.two-up.large-vertical .item{width:auto}}.icon-bar.three-up .item{width:33.3333%}.icon-bar.three-up.vertical .item,.icon-bar.three-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.063em){.icon-bar.three-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.063em){.icon-bar.three-up.large-vertical .item{width:auto}}.icon-bar.four-up .item{width:25%}.icon-bar.four-up.vertical .item,.icon-bar.four-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.063em){.icon-bar.four-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.063em){.icon-bar.four-up.large-vertical .item{width:auto}}.icon-bar.five-up .item{width:20%}.icon-bar.five-up.vertical .item,.icon-bar.five-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.063em){.icon-bar.five-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.063em){.icon-bar.five-up.large-vertical .item{width:auto}}.icon-bar.six-up .item{width:16.66667%}.icon-bar.six-up.vertical .item,.icon-bar.six-up.small-vertical .item{width:auto}@media only screen and (min-width: 40.063em){.icon-bar.six-up.medium-vertical .item{width:auto}}@media only screen and (min-width: 64.063em){.icon-bar.six-up.large-vertical .item{width:auto}}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.text-justify{text-align:justify !important}@media only screen and (max-width: 40em){.small-only-text-left{text-align:left !important}.small-only-text-right{text-align:right !important}.small-only-text-center{text-align:center !important}.small-only-text-justify{text-align:justify !important}}@media only screen{.small-text-left{text-align:left !important}.small-text-right{text-align:right !important}.small-text-center{text-align:center !important}.small-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.063em) and (max-width: 64em){.medium-only-text-left{text-align:left !important}.medium-only-text-right{text-align:right !important}.medium-only-text-center{text-align:center !important}.medium-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 40.063em){.medium-text-left{text-align:left !important}.medium-text-right{text-align:right !important}.medium-text-center{text-align:center !important}.medium-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.063em) and (max-width: 90em){.large-only-text-left{text-align:left !important}.large-only-text-right{text-align:right !important}.large-only-text-center{text-align:center !important}.large-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 64.063em){.large-text-left{text-align:left !important}.large-text-right{text-align:right !important}.large-text-center{text-align:center !important}.large-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.063em) and (max-width: 120em){.xlarge-only-text-left{text-align:left !important}.xlarge-only-text-right{text-align:right !important}.xlarge-only-text-center{text-align:center !important}.xlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 90.063em){.xlarge-text-left{text-align:left !important}.xlarge-text-right{text-align:right !important}.xlarge-text-center{text-align:center !important}.xlarge-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.063em) and (max-width: 99999999em){.xxlarge-only-text-left{text-align:left !important}.xxlarge-only-text-right{text-align:right !important}.xxlarge-only-text-center{text-align:center !important}.xxlarge-only-text-justify{text-align:justify !important}}@media only screen and (min-width: 120.063em){.xxlarge-text-left{text-align:left !important}.xxlarge-text-right{text-align:right !important}.xxlarge-text-center{text-align:center !important}.xxlarge-text-justify{text-align:justify !important}}div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}a{color:#008cba;text-decoration:none;line-height:inherit}a:hover,a:focus{color:#0078a0}a img{border:none}p{font-family:inherit;font-weight:normal;font-size:1rem;line-height:1.6;margin-bottom:1.25rem;text-rendering:optimizeLegibility}p.lead{font-size:1.21875rem;line-height:1.6}p aside{font-size:0.875rem;line-height:1.35;font-style:italic}h1,h2,h3,h4,h5,h6{font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-weight:normal;font-style:normal;color:#222;text-rendering:optimizeLegibility;margin-top:0.2rem;margin-bottom:0.5rem;line-height:1.4}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-size:60%;color:#6f6f6f;line-height:0}h1{font-size:2.125rem}h2{font-size:1.6875rem}h3{font-size:1.375rem}h4{font-size:1.125rem}h5{font-size:1.125rem}h6{font-size:1rem}.subheader{line-height:1.4;color:#6f6f6f;font-weight:normal;margin-top:0.2rem;margin-bottom:0.5rem}hr{border:solid #ddd;border-width:1px 0 0;clear:both;margin:1.25rem 0 1.1875rem;height:0}em,i{font-style:italic;line-height:inherit}strong,b{font-weight:bold;line-height:inherit}small{font-size:60%;line-height:inherit}code{font-family:Consolas,"Liberation Mono",Courier,monospace;font-weight:normal;color:#333;background-color:#f8f8f8;border-width:1px;border-style:solid;border-color:#dfdfdf;padding:0.125rem 0.3125rem 0.0625rem}ul,ol,dl{font-size:1rem;line-height:1.6;margin-bottom:1.25rem;list-style-position:outside;font-family:inherit}ul{margin-left:1.1rem}ul.no-bullet{margin-left:0}ul.no-bullet li ul,ul.no-bullet li ol{margin-left:1.25rem;margin-bottom:0;list-style:none}ul li ul,ul li ol{margin-left:1.25rem;margin-bottom:0}ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}ul.square{list-style-type:square;margin-left:1.1rem}ul.circle{list-style-type:circle;margin-left:1.1rem}ul.disc{list-style-type:disc;margin-left:1.1rem}ul.no-bullet{list-style:none}ol{margin-left:1.4rem}ol li ul,ol li ol{margin-left:1.25rem;margin-bottom:0}dl dt{margin-bottom:0.3rem;font-weight:bold}dl dd{margin-bottom:0.75rem}abbr,acronym{text-transform:uppercase;font-size:90%;color:#222;border-bottom:1px dotted #ddd;cursor:help}abbr{text-transform:none}blockquote{margin:0 0 1.25rem;padding:0.5625rem 1.25rem 0 1.1875rem;border-left:1px solid #ddd}blockquote cite{display:block;font-size:0.8125rem;color:#555}blockquote cite:before{content:"\2014 \0020"}blockquote cite a,blockquote cite a:visited{color:#555}blockquote,blockquote p{line-height:1.6;color:#6f6f6f}.vcard{display:inline-block;margin:0 0 1.25rem 0;border:1px solid #ddd;padding:0.625rem 0.75rem}.vcard li{margin:0;display:block}.vcard .fn{font-weight:bold;font-size:0.9375rem}.vevent .summary{font-weight:bold}.vevent abbr{cursor:default;text-decoration:none;font-weight:bold;border:none;padding:0 0.0625rem}@media only screen and (min-width: 40.063em){h1,h2,h3,h4,h5,h6{line-height:1.4}h1{font-size:2.75rem}h2{font-size:2.3125rem}h3{font-size:1.6875rem}h4{font-size:1.4375rem}h5{font-size:1.125rem}h6{font-size:1rem}}.print-only{display:none !important}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.hide-on-print{display:none !important}.print-only{display:block !important}.hide-for-print{display:none !important}.show-for-print{display:inherit !important}}.tabs{margin-bottom:0 !important;margin-left:0}.tabs:before,.tabs:after{content:" ";display:table}.tabs:after{clear:both}.tabs dd,.tabs .tab-title{position:relative;margin-bottom:0 !important;list-style:none;float:left}.tabs dd>a,.tabs .tab-title>a{display:block;background-color:#efefef;color:#222;padding:1rem 2rem;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-size:1rem}.tabs dd>a:hover,.tabs .tab-title>a:hover{background-color:#e1e1e1}.tabs dd.active a,.tabs .tab-title.active a{background-color:#fff;color:#222}.tabs.radius dd:first-child a,.tabs.radius .tab:first-child a{-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.tabs.radius dd:last-child a,.tabs.radius .tab:last-child a{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.tabs.vertical dd,.tabs.vertical .tab-title{position:inherit;float:none;display:block;top:auto}.tabs-content{margin-bottom:1.5rem;width:100%}.tabs-content:before,.tabs-content:after{content:" ";display:table}.tabs-content:after{clear:both}.tabs-content>.content{display:none;float:left;padding:0.9375rem 0;width:100%}.tabs-content>.content.active{display:block;float:none}.tabs-content>.content.contained{padding:0.9375rem}.tabs-content.vertical{display:block}.tabs-content.vertical>.content{padding:0 0.9375rem}@media only screen and (min-width: 40.063em){.tabs.vertical{width:20%;max-width:20%;float:left;margin:0 0 1.25rem}.tabs-content.vertical{width:80%;max-width:80%;float:left;margin-left:-1px;padding-left:1rem}}.no-js .tabs-content>.content{display:block;float:none}ul.pagination{display:block;min-height:1.5rem;margin-left:-0.3125rem}ul.pagination li{height:1.5rem;color:#222;font-size:0.875rem;margin-left:0.3125rem}ul.pagination li a,ul.pagination li button{display:block;padding:0.0625rem 0.625rem 0.0625rem;color:#999;background:none;border-radius:3px;font-weight:normal;font-size:1em;line-height:inherit;transition:background-color 300ms ease-out}ul.pagination li:hover a,ul.pagination li a:focus,ul.pagination li:hover button,ul.pagination li button:focus{background:#e6e6e6}ul.pagination li.unavailable a,ul.pagination li.unavailable button{cursor:default;color:#999}ul.pagination li.unavailable:hover a,ul.pagination li.unavailable a:focus,ul.pagination li.unavailable:hover button,ul.pagination li.unavailable button:focus{background:transparent}ul.pagination li.current a,ul.pagination li.current button{background:#008cba;color:#fff;font-weight:bold;cursor:default}ul.pagination li.current a:hover,ul.pagination li.current a:focus,ul.pagination li.current button:hover,ul.pagination li.current button:focus{background:#008cba}ul.pagination li{float:left;display:block}.pagination-centered{text-align:center}.pagination-centered ul.pagination li{float:none;display:inline-block}.side-nav{display:block;margin:0;padding:0.875rem 0;list-style-type:none;list-style-position:outside;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif}.side-nav li{margin:0 0 0.4375rem 0;font-size:0.875rem}.side-nav li a:not(.button){display:block;color:#008cba;margin:0;padding:0.4375rem 0.875rem}.side-nav li a:not(.button):hover,.side-nav li a:not(.button):focus{background:rgba(0,0,0,0.025);color:#1cc7ff}.side-nav li.active>a:first-child:not(.button){color:#1cc7ff;font-weight:normal;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif}.side-nav li.divider{border-top:1px solid;height:0;padding:0;list-style:none;border-top-color:#fff}.side-nav li.heading{color:#008cba;font-size:0.875rem;font-weight:bold;text-transform:uppercase}.accordion{margin-bottom:0}.accordion:before,.accordion:after{content:" ";display:table}.accordion:after{clear:both}.accordion .accordion-navigation,.accordion dd{display:block;margin-bottom:0 !important}.accordion .accordion-navigation.active>a,.accordion dd.active>a{background:#e8e8e8}.accordion .accordion-navigation>a,.accordion dd>a{background:#efefef;color:#222;padding:1rem;display:block;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-size:1rem}.accordion .accordion-navigation>a:hover,.accordion dd>a:hover{background:#e3e3e3}.accordion .accordion-navigation>.content,.accordion dd>.content{display:none;padding:0.9375rem}.accordion .accordion-navigation>.content.active,.accordion dd>.content.active{display:block;background:#fff}.split.button{position:relative;padding-right:5.0625rem}.split.button span{display:block;height:100%;position:absolute;right:0;top:0;border-left:solid 1px}.split.button span:after{position:absolute;content:"";width:0;height:0;display:block;border-style:inset;top:50%;left:50%}.split.button span:active{background-color:rgba(0,0,0,0.1)}.split.button span{border-left-color:rgba(255,255,255,0.5)}.split.button span{width:3.09375rem}.split.button span:after{border-top-style:solid;border-width:0.375rem;top:48%;margin-left:-0.375rem}.split.button span:after{border-color:#fff transparent transparent transparent}.split.button.secondary span{border-left-color:rgba(255,255,255,0.5)}.split.button.secondary span:after{border-color:#fff transparent transparent transparent}.split.button.alert span{border-left-color:rgba(255,255,255,0.5)}.split.button.success span{border-left-color:rgba(255,255,255,0.5)}.split.button.tiny{padding-right:3.75rem}.split.button.tiny span{width:2.25rem}.split.button.tiny span:after{border-top-style:solid;border-width:0.375rem;top:48%;margin-left:-0.375rem}.split.button.small{padding-right:4.375rem}.split.button.small span{width:2.625rem}.split.button.small span:after{border-top-style:solid;border-width:0.4375rem;top:48%;margin-left:-0.375rem}.split.button.large{padding-right:5.5rem}.split.button.large span{width:3.4375rem}.split.button.large span:after{border-top-style:solid;border-width:0.3125rem;top:48%;margin-left:-0.375rem}.split.button.expand{padding-left:2rem}.split.button.secondary span:after{border-color:#333 transparent transparent transparent}.split.button.radius span{-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.split.button.round span{-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}.reveal-modal-bg{position:fixed;top:0;bottom:0;left:0;right:0;background:#000;background:rgba(0,0,0,0.45);z-index:1004;display:none;left:0}.reveal-modal,dialog{visibility:hidden;display:none;position:absolute;z-index:1005;width:100vw;top:0;border-radius:3px;left:0;background-color:#fff;padding:1.25rem;border:solid 1px #666;box-shadow:0 0 10px rgba(0,0,0,0.4);padding:1.875rem}@media only screen and (max-width: 40em){.reveal-modal,dialog{min-height:100vh}}.reveal-modal .column,dialog .column,.reveal-modal .columns,dialog .columns{min-width:0}.reveal-modal>:first-child,dialog>:first-child{margin-top:0}.reveal-modal>:last-child,dialog>:last-child{margin-bottom:0}@media only screen and (min-width: 40.063em){.reveal-modal,dialog{width:80%;max-width:62.5rem;left:0;right:0;margin:0 auto}}@media only screen and (min-width: 40.063em){.reveal-modal,dialog{top:6.25rem}}.reveal-modal.radius,dialog.radius{border-radius:3px}.reveal-modal.round,dialog.round{border-radius:1000px}.reveal-modal.collapse,dialog.collapse{padding:0}@media only screen and (min-width: 40.063em){.reveal-modal.tiny,dialog.tiny{width:30%;max-width:62.5rem;left:0;right:0;margin:0 auto}}@media only screen and (min-width: 40.063em){.reveal-modal.small,dialog.small{width:40%;max-width:62.5rem;left:0;right:0;margin:0 auto}}@media only screen and (min-width: 40.063em){.reveal-modal.medium,dialog.medium{width:60%;max-width:62.5rem;left:0;right:0;margin:0 auto}}@media only screen and (min-width: 40.063em){.reveal-modal.large,dialog.large{width:70%;max-width:62.5rem;left:0;right:0;margin:0 auto}}@media only screen and (min-width: 40.063em){.reveal-modal.xlarge,dialog.xlarge{width:95%;max-width:62.5rem;left:0;right:0;margin:0 auto}}.reveal-modal.full,dialog.full{top:0;left:0;height:100%;height:100vh;min-height:100vh;margin-left:0 !important}@media only screen and (min-width: 40.063em){.reveal-modal.full,dialog.full{width:100vw;max-width:62.5rem;left:0;right:0;margin:0 auto}}.reveal-modal .close-reveal-modal,dialog .close-reveal-modal{font-size:2.5rem;line-height:1;position:absolute;top:0.5rem;right:0.6875rem;color:#aaa;font-weight:bold;cursor:pointer}dialog::backdrop{position:fixed;top:0;bottom:0;left:0;right:0;background:#000;background:rgba(0,0,0,0.45);display:none;left:0}@media print{dialog,.reveal-modal,dialog{display:none;background:#fff !important}}.has-tip{border-bottom:dotted 1px #ccc;cursor:help;font-weight:bold;color:#333}.has-tip:hover,.has-tip:focus{border-bottom:dotted 1px #003f54;color:#008cba}.has-tip.tip-left,.has-tip.tip-right{float:none !important}.tooltip{display:none;position:absolute;z-index:999;font-weight:normal;font-size:0.875rem;line-height:1.3;padding:0.75rem;max-width:300px;left:50%;width:100%;color:#fff;background:#333}.tooltip>.nub{display:block;left:5px;position:absolute;width:0;height:0;border:solid 5px;border-color:transparent transparent #333 transparent;top:-10px;pointer-events:none}.tooltip>.nub.rtl{left:auto;right:5px}.tooltip.radius{border-radius:3px}.tooltip.round{border-radius:1000px}.tooltip.round>.nub{left:2rem}.tooltip.opened{color:#008cba !important;border-bottom:dotted 1px #003f54 !important}.tap-to-close{display:block;font-size:0.625rem;color:#777;font-weight:normal}@media only screen and (min-width: 40.063em){.tooltip>.nub{border-color:transparent transparent #333 transparent;top:-10px}.tooltip.tip-top>.nub{border-color:#333 transparent transparent transparent;top:auto;bottom:-10px}.tooltip.tip-left,.tooltip.tip-right{float:none !important}.tooltip.tip-left>.nub{border-color:transparent transparent transparent #333;right:-10px;left:auto;top:50%;margin-top:-5px}.tooltip.tip-right>.nub{border-color:transparent #333 transparent transparent;right:auto;left:-10px;top:50%;margin-top:-5px}}.clearing-thumbs,[data-clearing]{margin-bottom:0;margin-left:0;list-style:none}.clearing-thumbs:before,.clearing-thumbs:after,[data-clearing]:before,[data-clearing]:after{content:" ";display:table}.clearing-thumbs:after,[data-clearing]:after{clear:both}.clearing-thumbs li,[data-clearing] li{float:left;margin-right:10px}.clearing-thumbs[class*="block-grid-"] li,[data-clearing][class*="block-grid-"] li{margin-right:0}.clearing-blackout{background:#333;position:fixed;width:100%;height:100%;top:0;left:0;z-index:998}.clearing-blackout .clearing-close{display:block}.clearing-container{position:relative;z-index:998;height:100%;overflow:hidden;margin:0}.clearing-touch-label{position:absolute;top:50%;left:50%;color:#aaa;font-size:0.6em}.visible-img{height:95%;position:relative}.visible-img img{position:absolute;left:50%;top:50%;margin-left:-50%;max-height:100%;max-width:100%}.clearing-caption{color:#ccc;font-size:0.875em;line-height:1.3;margin-bottom:0;text-align:center;bottom:0;background:#333;width:100%;padding:10px 30px 20px;position:absolute;left:0}.clearing-close{z-index:999;padding-left:20px;padding-top:10px;font-size:30px;line-height:1;color:#ccc;display:none}.clearing-close:hover,.clearing-close:focus{color:#ccc}.clearing-assembled .clearing-container{height:100%}.clearing-assembled .clearing-container .carousel>ul{display:none}.clearing-feature li{display:none}.clearing-feature li.clearing-featured-img{display:block}@media only screen and (min-width: 40.063em){.clearing-main-prev,.clearing-main-next{position:absolute;height:100%;width:40px;top:0}.clearing-main-prev>span,.clearing-main-next>span{position:absolute;top:50%;display:block;width:0;height:0;border:solid 12px}.clearing-main-prev>span:hover,.clearing-main-next>span:hover{opacity:0.8}.clearing-main-prev{left:0}.clearing-main-prev>span{left:5px;border-color:transparent;border-right-color:#ccc}.clearing-main-next{right:0}.clearing-main-next>span{border-color:transparent;border-left-color:#ccc}.clearing-main-prev.disabled,.clearing-main-next.disabled{opacity:0.3}.clearing-assembled .clearing-container .carousel{background:rgba(51,51,51,0.8);height:120px;margin-top:10px;text-align:center}.clearing-assembled .clearing-container .carousel>ul{display:inline-block;z-index:999;height:100%;position:relative;float:none}.clearing-assembled .clearing-container .carousel>ul li{display:block;width:120px;min-height:inherit;float:left;overflow:hidden;margin-right:0;padding:0;position:relative;cursor:pointer;opacity:0.4;clear:none}.clearing-assembled .clearing-container .carousel>ul li.fix-height img{height:100%;max-width:none}.clearing-assembled .clearing-container .carousel>ul li a.th{border:none;box-shadow:none;display:block}.clearing-assembled .clearing-container .carousel>ul li img{cursor:pointer !important;width:100% !important}.clearing-assembled .clearing-container .carousel>ul li.visible{opacity:1}.clearing-assembled .clearing-container .carousel>ul li:hover{opacity:0.8}.clearing-assembled .clearing-container .visible-img{background:#333;overflow:hidden;height:85%}.clearing-close{position:absolute;top:10px;right:20px;padding-left:0;padding-top:0}}.progress{background-color:#f6f6f6;height:1.5625rem;border:1px solid #fff;padding:0.125rem;margin-bottom:0.625rem}.progress .meter{background:#008cba;height:100%;display:block}.progress.secondary .meter{background:#e7e7e7;height:100%;display:block}.progress.success .meter{background:#43ac6a;height:100%;display:block}.progress.alert .meter{background:#f04124;height:100%;display:block}.progress.radius{border-radius:3px}.progress.radius .meter{border-radius:2px}.progress.round{border-radius:1000px}.progress.round .meter{border-radius:999px}.sub-nav{display:block;width:auto;overflow:hidden;margin:-0.25rem 0 1.125rem;padding-top:0.25rem;margin-right:0;margin-left:-0.75rem}.sub-nav dt{text-transform:uppercase}.sub-nav dt,.sub-nav dd,.sub-nav li{float:left;display:inline;margin-left:1rem;margin-bottom:0.625rem;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;font-weight:normal;font-size:0.875rem;color:#999}.sub-nav dt a,.sub-nav dd a,.sub-nav li a{text-decoration:none;color:#999;padding:0.1875rem 1rem}.sub-nav dt a:hover,.sub-nav dd a:hover,.sub-nav li a:hover{color:#737373}.sub-nav dt.active a,.sub-nav dd.active a,.sub-nav li.active a{border-radius:3px;font-weight:normal;background:#008cba;padding:0.1875rem 1rem;cursor:default;color:#fff}.sub-nav dt.active a:hover,.sub-nav dd.active a:hover,.sub-nav li.active a:hover{background:#0078a0}.joyride-list{display:none}.joyride-tip-guide{display:none;position:absolute;background:#333;color:#fff;z-index:101;top:0;left:2.5%;font-family:inherit;font-weight:normal;width:95%}.lt-ie9 .joyride-tip-guide{max-width:800px;left:50%;margin-left:-400px}.joyride-content-wrapper{width:100%;padding:1.125rem 1.25rem 1.5rem}.joyride-content-wrapper .button{margin-bottom:0 !important}.joyride-content-wrapper .joyride-prev-tip{margin-right:10px}.joyride-tip-guide .joyride-nub{display:block;position:absolute;left:22px;width:0;height:0;border:10px solid #333}.joyride-tip-guide .joyride-nub.top{border-top-style:solid;border-color:#333;border-top-color:transparent !important;border-left-color:transparent !important;border-right-color:transparent !important;top:-20px}.joyride-tip-guide .joyride-nub.bottom{border-bottom-style:solid;border-color:#333 !important;border-bottom-color:transparent !important;border-left-color:transparent !important;border-right-color:transparent !important;bottom:-20px}.joyride-tip-guide .joyride-nub.right{right:-20px}.joyride-tip-guide .joyride-nub.left{left:-20px}.joyride-tip-guide h1,.joyride-tip-guide h2,.joyride-tip-guide h3,.joyride-tip-guide h4,.joyride-tip-guide h5,.joyride-tip-guide h6{line-height:1.25;margin:0;font-weight:bold;color:#fff}.joyride-tip-guide p{margin:0 0 1.125rem 0;font-size:0.875rem;line-height:1.3}.joyride-timer-indicator-wrap{width:50px;height:3px;border:solid 1px #555;position:absolute;right:1.0625rem;bottom:1rem}.joyride-timer-indicator{display:block;width:0;height:inherit;background:#666}.joyride-close-tip{position:absolute;right:12px;top:10px;color:#777 !important;text-decoration:none;font-size:24px;font-weight:normal;line-height:0.5 !important}.joyride-close-tip:hover,.joyride-close-tip:focus{color:#eee !important}.joyride-modal-bg{position:fixed;height:100%;width:100%;background:transparent;background:rgba(0,0,0,0.5);z-index:100;display:none;top:0;left:0;cursor:pointer}.joyride-expose-wrapper{background-color:#fff;position:absolute;border-radius:3px;z-index:102;box-shadow:0 0 15px #fff}.joyride-expose-cover{background:transparent;border-radius:3px;position:absolute;z-index:9999;top:0;left:0}@media only screen and (min-width: 40.063em){.joyride-tip-guide{width:300px;left:inherit}.joyride-tip-guide .joyride-nub.bottom{border-color:#333 !important;border-bottom-color:transparent !important;border-left-color:transparent !important;border-right-color:transparent !important;bottom:-20px}.joyride-tip-guide .joyride-nub.right{border-color:#333 !important;border-top-color:transparent !important;border-right-color:transparent !important;border-bottom-color:transparent !important;top:22px;left:auto;right:-20px}.joyride-tip-guide .joyride-nub.left{border-color:#333 !important;border-top-color:transparent !important;border-left-color:transparent !important;border-bottom-color:transparent !important;top:22px;left:-20px;right:auto}}.label{font-weight:normal;font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif;text-align:center;text-decoration:none;line-height:1;white-space:nowrap;display:inline-block;position:relative;margin-bottom:inherit;padding:0.25rem 0.5rem 0.375rem;font-size:0.6875rem;background-color:#008cba;color:#fff}.label.radius{border-radius:3px}.label.round{border-radius:1000px}.label.alert{background-color:#f04124;color:#fff}.label.warning{background-color:#f08a24;color:#fff}.label.success{background-color:#43ac6a;color:#fff}.label.secondary{background-color:#e7e7e7;color:#333}.off-canvas-wrap{-webkit-backface-visibility:hidden;position:relative;width:100%;overflow:hidden}.off-canvas-wrap.move-right,.off-canvas-wrap.move-left{min-height:100%;-webkit-overflow-scrolling:touch}.inner-wrap{-webkit-backface-visibility:hidden;position:relative;width:100%;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.inner-wrap:before,.inner-wrap:after{content:" ";display:table}.inner-wrap:after{clear:both}.tab-bar{-webkit-backface-visibility:hidden;background:#333;color:#fff;height:2.8125rem;line-height:2.8125rem;position:relative}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4,.tab-bar h5,.tab-bar h6{color:#fff;font-weight:bold;line-height:2.8125rem;margin:0}.tab-bar h1,.tab-bar h2,.tab-bar h3,.tab-bar h4{font-size:1.125rem}.left-small{width:2.8125rem;height:2.8125rem;position:absolute;top:0;border-right:solid 1px #1a1a1a;left:0}.right-small{width:2.8125rem;height:2.8125rem;position:absolute;top:0;border-left:solid 1px #1a1a1a;right:0}.tab-bar-section{padding:0 0.625rem;position:absolute;text-align:center;height:2.8125rem;top:0}@media only screen and (min-width: 40.063em){.tab-bar-section.left,.tab-bar-section.right{text-align:left}}.tab-bar-section.left{left:0;right:2.8125rem}.tab-bar-section.right{left:2.8125rem;right:0}.tab-bar-section.middle{left:2.8125rem;right:2.8125rem}.tab-bar .menu-icon{text-indent:2.1875rem;width:2.8125rem;height:2.8125rem;display:block;padding:0;color:#fff;position:relative;transform:translate3d(0, 0, 0)}.tab-bar .menu-icon span::after{content:"";position:absolute;display:block;height:0;top:50%;margin-top:-0.5rem;left:0.90625rem;box-shadow:0 0px 0 1px #fff,0 7px 0 1px #fff,0 14px 0 1px #fff;width:1rem}.tab-bar .menu-icon span:hover:after{box-shadow:0 0px 0 1px #b3b3b3,0 7px 0 1px #b3b3b3,0 14px 0 1px #b3b3b3}.left-off-canvas-menu{-webkit-backface-visibility:hidden;width:15.625rem;top:0;bottom:0;position:absolute;overflow-y:auto;background:#333;z-index:1001;box-sizing:content-box;transition:transform 500ms ease 0s;-webkit-overflow-scrolling:touch;-ms-transform:translate(-100.5%, 0);-webkit-transform:translate3d(-100.5%, 0, 0);-moz-transform:translate3d(-100.5%, 0, 0);-ms-transform:translate3d(-100.5%, 0, 0);-o-transform:translate3d(-100.5%, 0, 0);transform:translate3d(-100.5%, 0, 0);left:0}.left-off-canvas-menu *{-webkit-backface-visibility:hidden}.right-off-canvas-menu{-webkit-backface-visibility:hidden;width:15.625rem;top:0;bottom:0;position:absolute;overflow-y:auto;background:#333;z-index:1001;box-sizing:content-box;transition:transform 500ms ease 0s;-webkit-overflow-scrolling:touch;-ms-transform:translate(100.5%, 0);-webkit-transform:translate3d(100.5%, 0, 0);-moz-transform:translate3d(100.5%, 0, 0);-ms-transform:translate3d(100.5%, 0, 0);-o-transform:translate3d(100.5%, 0, 0);transform:translate3d(100.5%, 0, 0);right:0}.right-off-canvas-menu *{-webkit-backface-visibility:hidden}ul.off-canvas-list{list-style-type:none;padding:0;margin:0}ul.off-canvas-list li label{display:block;padding:0.3rem 0.9375rem;color:#999;text-transform:uppercase;font-size:0.75rem;font-weight:bold;background:#444;border-top:1px solid #5e5e5e;border-bottom:none;margin:0}ul.off-canvas-list li a{display:block;padding:0.66667rem;color:rgba(255,255,255,0.7);border-bottom:1px solid #262626;transition:background 300ms ease}ul.off-canvas-list li a:hover{background:#242424}.move-right>.inner-wrap{-ms-transform:translate(15.625rem, 0);-webkit-transform:translate3d(15.625rem, 0, 0);-moz-transform:translate3d(15.625rem, 0, 0);-ms-transform:translate3d(15.625rem, 0, 0);-o-transform:translate3d(15.625rem, 0, 0);transform:translate3d(15.625rem, 0, 0)}.move-right .exit-off-canvas{-webkit-backface-visibility:hidden;transition:background 300ms ease;cursor:pointer;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);display:block;position:absolute;background:rgba(255,255,255,0.2);top:0;bottom:0;left:0;right:0;z-index:1002;-webkit-tap-highlight-color:rgba(0,0,0,0)}@media only screen and (min-width: 40.063em){.move-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.move-left>.inner-wrap{-ms-transform:translate(-15.625rem, 0);-webkit-transform:translate3d(-15.625rem, 0, 0);-moz-transform:translate3d(-15.625rem, 0, 0);-ms-transform:translate3d(-15.625rem, 0, 0);-o-transform:translate3d(-15.625rem, 0, 0);transform:translate3d(-15.625rem, 0, 0)}.move-left .exit-off-canvas{-webkit-backface-visibility:hidden;transition:background 300ms ease;cursor:pointer;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);display:block;position:absolute;background:rgba(255,255,255,0.2);top:0;bottom:0;left:0;right:0;z-index:1002;-webkit-tap-highlight-color:rgba(0,0,0,0)}@media only screen and (min-width: 40.063em){.move-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap .left-off-canvas-menu,.offcanvas-overlap .right-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap .exit-off-canvas{-webkit-backface-visibility:hidden;transition:background 300ms ease;cursor:pointer;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);display:block;position:absolute;background:rgba(255,255,255,0.2);top:0;bottom:0;left:0;right:0;z-index:1002;-webkit-tap-highlight-color:rgba(0,0,0,0)}@media only screen and (min-width: 40.063em){.offcanvas-overlap .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap-left .right-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-left .exit-off-canvas{-webkit-backface-visibility:hidden;transition:background 300ms ease;cursor:pointer;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);display:block;position:absolute;background:rgba(255,255,255,0.2);top:0;bottom:0;left:0;right:0;z-index:1002;-webkit-tap-highlight-color:rgba(0,0,0,0)}@media only screen and (min-width: 40.063em){.offcanvas-overlap-left .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.offcanvas-overlap-right .left-off-canvas-menu{-ms-transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;transform:none;z-index:1003}.offcanvas-overlap-right .exit-off-canvas{-webkit-backface-visibility:hidden;transition:background 300ms ease;cursor:pointer;box-shadow:-4px 0 4px rgba(0,0,0,0.5),4px 0 4px rgba(0,0,0,0.5);display:block;position:absolute;background:rgba(255,255,255,0.2);top:0;bottom:0;left:0;right:0;z-index:1002;-webkit-tap-highlight-color:rgba(0,0,0,0)}@media only screen and (min-width: 40.063em){.offcanvas-overlap-right .exit-off-canvas:hover{background:rgba(255,255,255,0.05)}}.no-csstransforms .left-off-canvas-menu{left:-15.625rem}.no-csstransforms .right-off-canvas-menu{right:-15.625rem}.no-csstransforms .move-left>.inner-wrap{right:15.625rem}.no-csstransforms .move-right>.inner-wrap{left:15.625rem}.left-submenu{-webkit-backface-visibility:hidden;width:15.625rem;top:0;bottom:0;position:absolute;margin:0;overflow-y:auto;background:#333;z-index:1002;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-transform:translate(-100%, 0);-webkit-transform:translate3d(-100%, 0, 0);-moz-transform:translate3d(-100%, 0, 0);-ms-transform:translate3d(-100%, 0, 0);-o-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.left-submenu *{-webkit-backface-visibility:hidden}.left-submenu .back>a{padding:0.3rem 0.9375rem;color:#999;text-transform:uppercase;font-weight:bold;background:#444;border-top:1px solid #5e5e5e;border-bottom:none;margin:0}.left-submenu .back>a:hover{background:#303030;border-top:1px solid #5e5e5e;border-bottom:none}.left-submenu .back>a:before{content:"\AB";margin-right:0.5rem;display:inline}.left-submenu.move-right{-ms-transform:translate(0%, 0);-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate3d(0%, 0, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.right-submenu{-webkit-backface-visibility:hidden;width:15.625rem;top:0;bottom:0;position:absolute;margin:0;overflow-y:auto;background:#333;z-index:1002;box-sizing:content-box;-webkit-overflow-scrolling:touch;-ms-transform:translate(100%, 0);-webkit-transform:translate3d(100%, 0, 0);-moz-transform:translate3d(100%, 0, 0);-ms-transform:translate3d(100%, 0, 0);-o-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);right:0;-webkit-transition:-webkit-transform 500ms ease;-moz-transition:-moz-transform 500ms ease;-ms-transition:-ms-transform 500ms ease;-o-transition:-o-transform 500ms ease;transition:transform 500ms ease}.right-submenu *{-webkit-backface-visibility:hidden}.right-submenu .back>a{padding:0.3rem 0.9375rem;color:#999;text-transform:uppercase;font-weight:bold;background:#444;border-top:1px solid #5e5e5e;border-bottom:none;margin:0}.right-submenu .back>a:hover{background:#303030;border-top:1px solid #5e5e5e;border-bottom:none}.right-submenu .back>a:after{content:"\BB";margin-left:0.5rem;display:inline}.right-submenu.move-left{-ms-transform:translate(0%, 0);-webkit-transform:translate3d(0%, 0, 0);-moz-transform:translate3d(0%, 0, 0);-ms-transform:translate3d(0%, 0, 0);-o-transform:translate3d(0%, 0, 0);transform:translate3d(0%, 0, 0)}.left-off-canvas-menu ul.off-canvas-list li.has-submenu>a:after{content:"\BB";margin-left:0.5rem;display:inline}.right-off-canvas-menu ul.off-canvas-list li.has-submenu>a:before{content:"\AB";margin-right:0.5rem;display:inline}.f-dropdown{position:absolute;left:-9999px;list-style:none;margin-left:0;width:100%;max-height:none;height:auto;background:#fff;border:solid 1px #ccc;font-size:0.875rem;z-index:99;margin-top:2px;max-width:200px}.f-dropdown>*:first-child{margin-top:0}.f-dropdown>*:last-child{margin-bottom:0}.f-dropdown:before{content:"";display:block;width:0;height:0;border:inset 6px;border-color:transparent transparent #fff transparent;border-bottom-style:solid;position:absolute;top:-12px;left:10px;z-index:99}.f-dropdown:after{content:"";display:block;width:0;height:0;border:inset 7px;border-color:transparent transparent #ccc transparent;border-bottom-style:solid;position:absolute;top:-14px;left:9px;z-index:98}.f-dropdown.right:before{left:auto;right:10px}.f-dropdown.right:after{left:auto;right:9px}.f-dropdown.drop-right{position:absolute;left:-9999px;list-style:none;margin-left:0;width:100%;max-height:none;height:auto;background:#fff;border:solid 1px #ccc;font-size:0.875rem;z-index:99;margin-top:0;margin-left:2px;max-width:200px}.f-dropdown.drop-right>*:first-child{margin-top:0}.f-dropdown.drop-right>*:last-child{margin-bottom:0}.f-dropdown.drop-right:before{content:"";display:block;width:0;height:0;border:inset 6px;border-color:transparent #fff transparent transparent;border-right-style:solid;position:absolute;top:10px;left:-12px;z-index:99}.f-dropdown.drop-right:after{content:"";display:block;width:0;height:0;border:inset 7px;border-color:transparent #ccc transparent transparent;border-right-style:solid;position:absolute;top:9px;left:-14px;z-index:98}.f-dropdown.drop-left{position:absolute;left:-9999px;list-style:none;margin-left:0;width:100%;max-height:none;height:auto;background:#fff;border:solid 1px #ccc;font-size:0.875rem;z-index:99;margin-top:0;margin-left:-2px;max-width:200px}.f-dropdown.drop-left>*:first-child{margin-top:0}.f-dropdown.drop-left>*:last-child{margin-bottom:0}.f-dropdown.drop-left:before{content:"";display:block;width:0;height:0;border:inset 6px;border-color:transparent transparent transparent #fff;border-left-style:solid;position:absolute;top:10px;right:-12px;left:auto;z-index:99}.f-dropdown.drop-left:after{content:"";display:block;width:0;height:0;border:inset 7px;border-color:transparent transparent transparent #ccc;border-left-style:solid;position:absolute;top:9px;right:-14px;left:auto;z-index:98}.f-dropdown.drop-top{position:absolute;left:-9999px;list-style:none;margin-left:0;width:100%;max-height:none;height:auto;background:#fff;border:solid 1px #ccc;font-size:0.875rem;z-index:99;margin-top:-2px;margin-left:0;max-width:200px}.f-dropdown.drop-top>*:first-child{margin-top:0}.f-dropdown.drop-top>*:last-child{margin-bottom:0}.f-dropdown.drop-top:before{content:"";display:block;width:0;height:0;border:inset 6px;border-color:#fff transparent transparent transparent;border-top-style:solid;position:absolute;top:auto;bottom:-12px;left:10px;right:auto;z-index:99}.f-dropdown.drop-top:after{content:"";display:block;width:0;height:0;border:inset 7px;border-color:#ccc transparent transparent transparent;border-top-style:solid;position:absolute;top:auto;bottom:-14px;left:9px;right:auto;z-index:98}.f-dropdown li{font-size:0.875rem;cursor:pointer;line-height:1.125rem;margin:0}.f-dropdown li:hover,.f-dropdown li:focus{background:#eee}.f-dropdown li a{display:block;padding:0.5rem;color:#555}.f-dropdown.content{position:absolute;left:-9999px;list-style:none;margin-left:0;padding:1.25rem;width:100%;height:auto;max-height:none;background:#fff;border:solid 1px #ccc;font-size:0.875rem;z-index:99;max-width:200px}.f-dropdown.content>*:first-child{margin-top:0}.f-dropdown.content>*:last-child{margin-bottom:0}.f-dropdown.tiny{max-width:200px}.f-dropdown.small{max-width:300px}.f-dropdown.medium{max-width:500px}.f-dropdown.large{max-width:800px}table{background:#fff;margin-bottom:1.25rem;border:solid 1px #ddd;table-layout:fixed;width:100%}table caption{background:transparent;color:#222;font-size:1rem;font-weight:bold}table thead{background:#f5f5f5}table thead tr th,table thead tr td{padding:0.5rem 0.625rem 0.625rem;font-size:0.875rem;font-weight:bold;color:#222}table tfoot{background:#f5f5f5}table tfoot tr th,table tfoot tr td{padding:0.5rem 0.625rem 0.625rem;font-size:0.875rem;font-weight:bold;color:#222}table tr th,table tr td{padding:0.5625rem 0.625rem;font-size:0.875rem;color:#222;text-align:left}table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f9f9f9}table thead tr th,table tfoot tr th,table tfoot tr td,table tbody tr th,table tbody tr td,table tr td{display:table-cell;line-height:1.125rem}form{margin:0 0 1rem}form .row .row{margin:0 -0.5rem}form .row .row .column,form .row .row .columns{padding:0 0.5rem}form .row .row.collapse{margin:0}form .row .row.collapse .column,form .row .row.collapse .columns{padding:0}form .row .row.collapse input{-webkit-border-bottom-right-radius:0;-webkit-border-top-right-radius:0;border-bottom-right-radius:0;border-top-right-radius:0}form .row input.column,form .row input.columns,form .row textarea.column,form .row textarea.columns{padding-left:0.5rem}label{font-size:0.875rem;color:#4d4d4d;cursor:pointer;display:block;font-weight:normal;line-height:1.5;margin-bottom:0}label.right{float:none !important;text-align:right}label.inline{margin:0 0 1rem 0;padding:0.5625rem 0}label small{text-transform:capitalize;color:#676767}select::-ms-expand{display:none}.prefix,.postfix{display:block;position:relative;z-index:2;text-align:center;width:100%;padding-top:0;padding-bottom:0;border-style:solid;border-width:1px;overflow:hidden;font-size:0.875rem;height:2.3125rem;line-height:2.3125rem}.postfix.button{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;text-align:center;line-height:2.125rem;border:none}.prefix.button{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;text-align:center;line-height:2.125rem;border:none}.prefix.button.radius{border-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}.postfix.button.radius{border-radius:0;-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}.prefix.button.round{border-radius:0;-webkit-border-bottom-left-radius:1000px;-webkit-border-top-left-radius:1000px;border-bottom-left-radius:1000px;border-top-left-radius:1000px}.postfix.button.round{border-radius:0;-webkit-border-bottom-right-radius:1000px;-webkit-border-top-right-radius:1000px;border-bottom-right-radius:1000px;border-top-right-radius:1000px}span.prefix,label.prefix{background:#f2f2f2;border-right:none;color:#333;border-color:#ccc}span.prefix.radius,label.prefix.radius{border-radius:0;-webkit-border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-bottom-left-radius:3px;border-top-left-radius:3px}span.postfix,label.postfix{background:#f2f2f2;border-left:none;color:#333;border-color:#ccc}span.postfix.radius,label.postfix.radius{border-radius:0;-webkit-border-bottom-right-radius:3px;-webkit-border-top-right-radius:3px;border-bottom-right-radius:3px;border-top-right-radius:3px}input[type="text"],input[type="password"],input[type="date"],input[type="datetime"],input[type="datetime-local"],input[type="month"],input[type="week"],input[type="email"],input[type="number"],input[type="search"],input[type="tel"],input[type="time"],input[type="url"],input[type="color"],textarea{-webkit-appearance:none;-webkit-border-radius:0px;background-color:#fff;font-family:inherit;border:1px solid #ccc;box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);color:rgba(0,0,0,0.75);display:block;font-size:0.875rem;margin:0 0 1rem 0;padding:0.5rem;height:2.3125rem;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;transition:box-shadow 0.45s,border-color 0.45s ease-in-out}input[type="text"]:focus,input[type="password"]:focus,input[type="date"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="month"]:focus,input[type="week"]:focus,input[type="email"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="time"]:focus,input[type="url"]:focus,input[type="color"]:focus,textarea:focus{box-shadow:0 0 5px #999;border-color:#999}input[type="text"]:focus,input[type="password"]:focus,input[type="date"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="month"]:focus,input[type="week"]:focus,input[type="email"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="time"]:focus,input[type="url"]:focus,input[type="color"]:focus,textarea:focus{background:#fafafa;border-color:#999;outline:none}input[type="text"]:disabled,input[type="password"]:disabled,input[type="date"]:disabled,input[type="datetime"]:disabled,input[type="datetime-local"]:disabled,input[type="month"]:disabled,input[type="week"]:disabled,input[type="email"]:disabled,input[type="number"]:disabled,input[type="search"]:disabled,input[type="tel"]:disabled,input[type="time"]:disabled,input[type="url"]:disabled,input[type="color"]:disabled,textarea:disabled{background-color:#ddd;cursor:default}input[type="text"][disabled],input[type="text"][readonly],fieldset[disabled] input[type="text"],input[type="password"][disabled],input[type="password"][readonly],fieldset[disabled] input[type="password"],input[type="date"][disabled],input[type="date"][readonly],fieldset[disabled] input[type="date"],input[type="datetime"][disabled],input[type="datetime"][readonly],fieldset[disabled] input[type="datetime"],input[type="datetime-local"][disabled],input[type="datetime-local"][readonly],fieldset[disabled] input[type="datetime-local"],input[type="month"][disabled],input[type="month"][readonly],fieldset[disabled] input[type="month"],input[type="week"][disabled],input[type="week"][readonly],fieldset[disabled] input[type="week"],input[type="email"][disabled],input[type="email"][readonly],fieldset[disabled] input[type="email"],input[type="number"][disabled],input[type="number"][readonly],fieldset[disabled] input[type="number"],input[type="search"][disabled],input[type="search"][readonly],fieldset[disabled] input[type="search"],input[type="tel"][disabled],input[type="tel"][readonly],fieldset[disabled] input[type="tel"],input[type="time"][disabled],input[type="time"][readonly],fieldset[disabled] input[type="time"],input[type="url"][disabled],input[type="url"][readonly],fieldset[disabled] input[type="url"],input[type="color"][disabled],input[type="color"][readonly],fieldset[disabled] input[type="color"],textarea[disabled],textarea[readonly],fieldset[disabled] textarea{background-color:#ddd;cursor:default}input[type="text"].radius,input[type="password"].radius,input[type="date"].radius,input[type="datetime"].radius,input[type="datetime-local"].radius,input[type="month"].radius,input[type="week"].radius,input[type="email"].radius,input[type="number"].radius,input[type="search"].radius,input[type="tel"].radius,input[type="time"].radius,input[type="url"].radius,input[type="color"].radius,textarea.radius{border-radius:3px}input[type="submit"]{-webkit-appearance:none;-webkit-border-radius:0px}textarea[rows]{height:auto}select{-webkit-appearance:none !important;-webkit-border-radius:0px;background-color:#fafafa;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+);background-position:100% center;background-repeat:no-repeat;border:1px solid #ccc;padding:0.5rem;font-size:0.875rem;color:rgba(0,0,0,0.75);line-height:normal;border-radius:0;height:2.3125rem}select.radius{border-radius:3px}select:hover{background-color:#f3f3f3;border-color:#999}select:disabled{background-color:#ddd;cursor:default}input[type="file"],input[type="checkbox"],input[type="radio"],select{margin:0 0 1rem 0}input[type="checkbox"]+label,input[type="radio"]+label{display:inline-block;margin-left:0.5rem;margin-right:1rem;margin-bottom:0;vertical-align:baseline}input[type="file"]{width:100%}fieldset{border:1px solid #ddd;padding:1.25rem;margin:1.125rem 0}fieldset legend{font-weight:bold;background:#fff;padding:0 0.1875rem;margin:0;margin-left:-0.1875rem}[data-abide] .error small.error,[data-abide] .error span.error,[data-abide] span.error,[data-abide] small.error{display:block;padding:0.375rem 0.5625rem 0.5625rem;margin-top:-1px;margin-bottom:1rem;font-size:0.75rem;font-weight:normal;font-style:italic;background:#f04124;color:#fff}[data-abide] span.error,[data-abide] small.error{display:none}span.error,small.error{display:block;padding:0.375rem 0.5625rem 0.5625rem;margin-top:-1px;margin-bottom:1rem;font-size:0.75rem;font-weight:normal;font-style:italic;background:#f04124;color:#fff}.error input,.error textarea,.error select{margin-bottom:0}.error input[type="checkbox"],.error input[type="radio"]{margin-bottom:1rem}.error label,.error label.error{color:#f04124}.error small.error{display:block;padding:0.375rem 0.5625rem 0.5625rem;margin-top:-1px;margin-bottom:1rem;font-size:0.75rem;font-weight:normal;font-style:italic;background:#f04124;color:#fff}.error>label>small{color:#676767;background:transparent;padding:0;text-transform:capitalize;font-style:normal;font-size:60%;margin:0;display:inline}.error span.error-message{display:block}input.error,textarea.error,select.error{margin-bottom:0}label.error{color:#f04124}.range-slider{display:block;position:relative;width:100%;height:1rem;border:1px solid #ddd;margin:1.25rem 0;-ms-touch-action:none;touch-action:none;background:#fafafa}.range-slider.vertical-range{display:block;position:relative;width:100%;height:1rem;border:1px solid #ddd;margin:1.25rem 0;-ms-touch-action:none;touch-action:none;display:inline-block;width:1rem;height:12.5rem}.range-slider.vertical-range .range-slider-handle{margin-top:0;margin-left:-0.5rem;position:absolute;bottom:-10.5rem}.range-slider.vertical-range .range-slider-active-segment{width:0.875rem;height:auto;bottom:0}.range-slider.radius{background:#fafafa;border-radius:3px}.range-slider.radius .range-slider-handle{background:#008cba;border-radius:3px}.range-slider.radius .range-slider-handle:hover{background:#007ba4}.range-slider.round{background:#fafafa;border-radius:1000px}.range-slider.round .range-slider-handle{background:#008cba;border-radius:1000px}.range-slider.round .range-slider-handle:hover{background:#007ba4}.range-slider.disabled,.range-slider[disabled]{background:#fafafa;cursor:default;opacity:0.7}.range-slider.disabled .range-slider-handle,.range-slider[disabled] .range-slider-handle{background:#008cba;cursor:default;opacity:0.7}.range-slider.disabled .range-slider-handle:hover,.range-slider[disabled] .range-slider-handle:hover{background:#007ba4}.range-slider-active-segment{display:inline-block;position:absolute;height:0.875rem;background:#e5e5e5}.range-slider-handle{display:inline-block;position:absolute;z-index:1;top:-0.3125rem;width:2rem;height:1.375rem;border:1px solid none;cursor:pointer;background:#008cba}.range-slider-handle:hover{background:#007ba4}[class*="block-grid-"]{display:block;padding:0;margin:0 -0.625rem}[class*="block-grid-"]:before,[class*="block-grid-"]:after{content:" ";display:table}[class*="block-grid-"]:after{clear:both}[class*="block-grid-"]>li{display:block;height:auto;float:left;padding:0 0.625rem 1.25rem}@media only screen{.small-block-grid-1>li{width:100%;list-style:none}.small-block-grid-1>li:nth-of-type(1n){clear:none}.small-block-grid-1>li:nth-of-type(1n+1){clear:both}.small-block-grid-2>li{width:50%;list-style:none}.small-block-grid-2>li:nth-of-type(1n){clear:none}.small-block-grid-2>li:nth-of-type(2n+1){clear:both}.small-block-grid-3>li{width:33.33333%;list-style:none}.small-block-grid-3>li:nth-of-type(1n){clear:none}.small-block-grid-3>li:nth-of-type(3n+1){clear:both}.small-block-grid-4>li{width:25%;list-style:none}.small-block-grid-4>li:nth-of-type(1n){clear:none}.small-block-grid-4>li:nth-of-type(4n+1){clear:both}.small-block-grid-5>li{width:20%;list-style:none}.small-block-grid-5>li:nth-of-type(1n){clear:none}.small-block-grid-5>li:nth-of-type(5n+1){clear:both}.small-block-grid-6>li{width:16.66667%;list-style:none}.small-block-grid-6>li:nth-of-type(1n){clear:none}.small-block-grid-6>li:nth-of-type(6n+1){clear:both}.small-block-grid-7>li{width:14.28571%;list-style:none}.small-block-grid-7>li:nth-of-type(1n){clear:none}.small-block-grid-7>li:nth-of-type(7n+1){clear:both}.small-block-grid-8>li{width:12.5%;list-style:none}.small-block-grid-8>li:nth-of-type(1n){clear:none}.small-block-grid-8>li:nth-of-type(8n+1){clear:both}.small-block-grid-9>li{width:11.11111%;list-style:none}.small-block-grid-9>li:nth-of-type(1n){clear:none}.small-block-grid-9>li:nth-of-type(9n+1){clear:both}.small-block-grid-10>li{width:10%;list-style:none}.small-block-grid-10>li:nth-of-type(1n){clear:none}.small-block-grid-10>li:nth-of-type(10n+1){clear:both}.small-block-grid-11>li{width:9.09091%;list-style:none}.small-block-grid-11>li:nth-of-type(1n){clear:none}.small-block-grid-11>li:nth-of-type(11n+1){clear:both}.small-block-grid-12>li{width:8.33333%;list-style:none}.small-block-grid-12>li:nth-of-type(1n){clear:none}.small-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 40.063em){.medium-block-grid-1>li{width:100%;list-style:none}.medium-block-grid-1>li:nth-of-type(1n){clear:none}.medium-block-grid-1>li:nth-of-type(1n+1){clear:both}.medium-block-grid-2>li{width:50%;list-style:none}.medium-block-grid-2>li:nth-of-type(1n){clear:none}.medium-block-grid-2>li:nth-of-type(2n+1){clear:both}.medium-block-grid-3>li{width:33.33333%;list-style:none}.medium-block-grid-3>li:nth-of-type(1n){clear:none}.medium-block-grid-3>li:nth-of-type(3n+1){clear:both}.medium-block-grid-4>li{width:25%;list-style:none}.medium-block-grid-4>li:nth-of-type(1n){clear:none}.medium-block-grid-4>li:nth-of-type(4n+1){clear:both}.medium-block-grid-5>li{width:20%;list-style:none}.medium-block-grid-5>li:nth-of-type(1n){clear:none}.medium-block-grid-5>li:nth-of-type(5n+1){clear:both}.medium-block-grid-6>li{width:16.66667%;list-style:none}.medium-block-grid-6>li:nth-of-type(1n){clear:none}.medium-block-grid-6>li:nth-of-type(6n+1){clear:both}.medium-block-grid-7>li{width:14.28571%;list-style:none}.medium-block-grid-7>li:nth-of-type(1n){clear:none}.medium-block-grid-7>li:nth-of-type(7n+1){clear:both}.medium-block-grid-8>li{width:12.5%;list-style:none}.medium-block-grid-8>li:nth-of-type(1n){clear:none}.medium-block-grid-8>li:nth-of-type(8n+1){clear:both}.medium-block-grid-9>li{width:11.11111%;list-style:none}.medium-block-grid-9>li:nth-of-type(1n){clear:none}.medium-block-grid-9>li:nth-of-type(9n+1){clear:both}.medium-block-grid-10>li{width:10%;list-style:none}.medium-block-grid-10>li:nth-of-type(1n){clear:none}.medium-block-grid-10>li:nth-of-type(10n+1){clear:both}.medium-block-grid-11>li{width:9.09091%;list-style:none}.medium-block-grid-11>li:nth-of-type(1n){clear:none}.medium-block-grid-11>li:nth-of-type(11n+1){clear:both}.medium-block-grid-12>li{width:8.33333%;list-style:none}.medium-block-grid-12>li:nth-of-type(1n){clear:none}.medium-block-grid-12>li:nth-of-type(12n+1){clear:both}}@media only screen and (min-width: 64.063em){.large-block-grid-1>li{width:100%;list-style:none}.large-block-grid-1>li:nth-of-type(1n){clear:none}.large-block-grid-1>li:nth-of-type(1n+1){clear:both}.large-block-grid-2>li{width:50%;list-style:none}.large-block-grid-2>li:nth-of-type(1n){clear:none}.large-block-grid-2>li:nth-of-type(2n+1){clear:both}.large-block-grid-3>li{width:33.33333%;list-style:none}.large-block-grid-3>li:nth-of-type(1n){clear:none}.large-block-grid-3>li:nth-of-type(3n+1){clear:both}.large-block-grid-4>li{width:25%;list-style:none}.large-block-grid-4>li:nth-of-type(1n){clear:none}.large-block-grid-4>li:nth-of-type(4n+1){clear:both}.large-block-grid-5>li{width:20%;list-style:none}.large-block-grid-5>li:nth-of-type(1n){clear:none}.large-block-grid-5>li:nth-of-type(5n+1){clear:both}.large-block-grid-6>li{width:16.66667%;list-style:none}.large-block-grid-6>li:nth-of-type(1n){clear:none}.large-block-grid-6>li:nth-of-type(6n+1){clear:both}.large-block-grid-7>li{width:14.28571%;list-style:none}.large-block-grid-7>li:nth-of-type(1n){clear:none}.large-block-grid-7>li:nth-of-type(7n+1){clear:both}.large-block-grid-8>li{width:12.5%;list-style:none}.large-block-grid-8>li:nth-of-type(1n){clear:none}.large-block-grid-8>li:nth-of-type(8n+1){clear:both}.large-block-grid-9>li{width:11.11111%;list-style:none}.large-block-grid-9>li:nth-of-type(1n){clear:none}.large-block-grid-9>li:nth-of-type(9n+1){clear:both}.large-block-grid-10>li{width:10%;list-style:none}.large-block-grid-10>li:nth-of-type(1n){clear:none}.large-block-grid-10>li:nth-of-type(10n+1){clear:both}.large-block-grid-11>li{width:9.09091%;list-style:none}.large-block-grid-11>li:nth-of-type(1n){clear:none}.large-block-grid-11>li:nth-of-type(11n+1){clear:both}.large-block-grid-12>li{width:8.33333%;list-style:none}.large-block-grid-12>li:nth-of-type(1n){clear:none}.large-block-grid-12>li:nth-of-type(12n+1){clear:both}}.flex-video{position:relative;padding-top:1.5625rem;padding-bottom:67.5%;height:0;margin-bottom:1rem;overflow:hidden}.flex-video.widescreen{padding-bottom:56.34%}.flex-video.vimeo{padding-top:0}.flex-video iframe,.flex-video object,.flex-video embed,.flex-video video{position:absolute;top:0;left:0;width:100%;height:100%}.keystroke,kbd{background-color:#ededed;border-color:#ddd;color:#222;border-style:solid;border-width:1px;margin:0;font-family:"Consolas","Menlo","Courier",monospace;font-size:inherit;padding:0.125rem 0.25rem 0;border-radius:3px}div.switch label{display:block;margin-bottom:1rem;position:relative;color:transparent;background:#ddd;text-indent:100%;width:4rem;height:2rem;cursor:pointer;transition:left 0.15s ease-out}div.switch input{display:none}div.switch input+label{margin-left:0;margin-right:0}div.switch label:after{content:"";display:block;background:#fff;position:absolute;top:.25rem;left:.25rem;width:1.5rem;height:1.5rem;-webkit-transition:left 0.15s ease-out;-moz-transition:left 0.15s ease-out;transition:left 0.15s ease-out;-webkit-transform:translate3d(0, 0, 0);-moz-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}div.switch input:checked+label{background:#008cba}div.switch input:checked+label:after{left:2.25rem}div.switch label{width:4rem;height:2rem}div.switch label:after{width:1.5rem;height:1.5rem}div.switch input:checked+label:after{left:2.25rem}div.switch label{color:transparent;background:#ddd}div.switch label:after{background:#fff}div.switch input:checked+label{background:#008cba}div.switch.large label{width:5rem;height:2.5rem}div.switch.large label:after{width:2rem;height:2rem}div.switch.large input:checked+label:after{left:2.75rem}div.switch.small label{width:3.5rem;height:1.75rem}div.switch.small label:after{width:1.25rem;height:1.25rem}div.switch.small input:checked+label:after{left:2rem}div.switch.tiny label{width:3rem;height:1.5rem}div.switch.tiny label:after{width:1rem;height:1rem}div.switch.tiny input:checked+label:after{left:1.75rem}div.switch.radius label{border-radius:4px}div.switch.radius label:after{border-radius:3px}div.switch.round{border-radius:1000px}div.switch.round label{border-radius:2rem}div.switch.round label:after{border-radius:2rem}@media only screen{.show-for-small-only,.show-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.hide-for-small-only,.hide-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.visible-for-small-only,.visible-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.hidden-for-small-only,.hidden-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}table.show-for-small-only,table.show-for-small-up,table.show-for-small,table.show-for-small-down,table.hide-for-medium-only,table.hide-for-medium-up,table.hide-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table}thead.show-for-small-only,thead.show-for-small-up,thead.show-for-small,thead.show-for-small-down,thead.hide-for-medium-only,thead.hide-for-medium-up,thead.hide-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.show-for-small-only,tbody.show-for-small-up,tbody.show-for-small,tbody.show-for-small-down,tbody.hide-for-medium-only,tbody.hide-for-medium-up,tbody.hide-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.show-for-small-only,tr.show-for-small-up,tr.show-for-small,tr.show-for-small-down,tr.hide-for-medium-only,tr.hide-for-medium-up,tr.hide-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row !important}th.show-for-small-only,td.show-for-small-only,th.show-for-small-up,td.show-for-small-up,th.show-for-small,td.show-for-small,th.show-for-small-down,td.show-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.hide-for-medium-up,td.hide-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 40.063em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.show-for-medium-only,.show-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.hide-for-medium-only,.hide-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.visible-for-medium-only,.visible-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.hidden-for-medium-only,.hidden-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.show-for-medium-only,table.show-for-medium-up,table.show-for-medium,table.show-for-medium-down,table.hide-for-large-only,table.hide-for-large-up,table.hide-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.show-for-medium-only,thead.show-for-medium-up,thead.show-for-medium,thead.show-for-medium-down,thead.hide-for-large-only,thead.hide-for-large-up,thead.hide-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.show-for-medium-only,tbody.show-for-medium-up,tbody.show-for-medium,tbody.show-for-medium-down,tbody.hide-for-large-only,tbody.hide-for-large-up,tbody.hide-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.show-for-medium-only,tr.show-for-medium-up,tr.show-for-medium,tr.show-for-medium-down,tr.hide-for-large-only,tr.hide-for-large-up,tr.hide-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row !important}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.show-for-medium-only,td.show-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.show-for-medium,td.show-for-medium,th.show-for-medium-down,td.show-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.hide-for-large-up,td.hide-for-large-up,th.hide-for-large,td.hide-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 64.063em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.show-for-large-only,.show-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.hide-for-large-only,.hide-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.visible-for-large-only,.visible-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.hidden-for-large-only,.hidden-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.show-for-large-only,table.show-for-large-up,table.show-for-large,table.show-for-large-down,table.hide-for-xlarge-only,table.hide-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.show-for-large-only,thead.show-for-large-up,thead.show-for-large,thead.show-for-large-down,thead.hide-for-xlarge-only,thead.hide-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.show-for-large-only,tbody.show-for-large-up,tbody.show-for-large,tbody.show-for-large-down,tbody.hide-for-xlarge-only,tbody.hide-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.show-for-large-only,tr.show-for-large-up,tr.show-for-large,tr.show-for-large-down,tr.hide-for-xlarge-only,tr.hide-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row !important}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.show-for-large-only,td.show-for-large-only,th.show-for-large-up,td.show-for-large-up,th.show-for-large,td.show-for-large,th.show-for-large-down,td.show-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.hide-for-xlarge-up,td.hide-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 90.063em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.show-for-xlarge-only,.show-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.hide-for-xlarge-only,.hide-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.visible-for-xlarge-only,.visible-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.hidden-for-xlarge-only,.hidden-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.show-for-xlarge-only,table.show-for-xlarge-up,table.hide-for-xxlarge-only,table.hide-for-xxlarge-up{display:table}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.show-for-xlarge-only,thead.show-for-xlarge-up,thead.hide-for-xxlarge-only,thead.hide-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.show-for-xlarge-only,tbody.show-for-xlarge-up,tbody.hide-for-xxlarge-only,tbody.hide-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.show-for-xlarge-only,tr.show-for-xlarge-up,tr.hide-for-xxlarge-only,tr.hide-for-xxlarge-up{display:table-row !important}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.show-for-xlarge-only,td.show-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.hide-for-xxlarge-only,td.hide-for-xxlarge-only,th.hide-for-xxlarge-up,td.hide-for-xxlarge-up{display:table-cell !important}}@media only screen and (min-width: 120.063em){.hide-for-small-only,.show-for-small-up,.hide-for-small,.hide-for-small-down,.hide-for-medium-only,.show-for-medium-up,.hide-for-medium,.hide-for-medium-down,.hide-for-large-only,.show-for-large-up,.hide-for-large,.hide-for-large-down,.hide-for-xlarge-only,.show-for-xlarge-up,.show-for-xxlarge-only,.show-for-xxlarge-up{display:inherit !important}.show-for-small-only,.hide-for-small-up,.show-for-small,.show-for-small-down,.show-for-medium-only,.hide-for-medium-up,.show-for-medium,.show-for-medium-down,.show-for-large-only,.hide-for-large-up,.show-for-large,.show-for-large-down,.show-for-xlarge-only,.hide-for-xlarge-up,.hide-for-xxlarge-only,.hide-for-xxlarge-up{display:none !important}.hidden-for-small-only,.visible-for-small-up,.hidden-for-small,.hidden-for-small-down,.hidden-for-medium-only,.visible-for-medium-up,.hidden-for-medium,.hidden-for-medium-down,.hidden-for-large-only,.visible-for-large-up,.hidden-for-large,.hidden-for-large-down,.hidden-for-xlarge-only,.visible-for-xlarge-up,.visible-for-xxlarge-only,.visible-for-xxlarge-up{position:static !important;height:auto;width:auto;overflow:visible;clip:auto}.visible-for-small-only,.hidden-for-small-up,.visible-for-small,.visible-for-small-down,.visible-for-medium-only,.hidden-for-medium-up,.visible-for-medium,.visible-for-medium-down,.visible-for-large-only,.hidden-for-large-up,.visible-for-large,.visible-for-large-down,.visible-for-xlarge-only,.hidden-for-xlarge-up,.hidden-for-xxlarge-only,.hidden-for-xxlarge-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}table.hide-for-small-only,table.show-for-small-up,table.hide-for-small,table.hide-for-small-down,table.hide-for-medium-only,table.show-for-medium-up,table.hide-for-medium,table.hide-for-medium-down,table.hide-for-large-only,table.show-for-large-up,table.hide-for-large,table.hide-for-large-down,table.hide-for-xlarge-only,table.show-for-xlarge-up,table.show-for-xxlarge-only,table.show-for-xxlarge-up{display:table}thead.hide-for-small-only,thead.show-for-small-up,thead.hide-for-small,thead.hide-for-small-down,thead.hide-for-medium-only,thead.show-for-medium-up,thead.hide-for-medium,thead.hide-for-medium-down,thead.hide-for-large-only,thead.show-for-large-up,thead.hide-for-large,thead.hide-for-large-down,thead.hide-for-xlarge-only,thead.show-for-xlarge-up,thead.show-for-xxlarge-only,thead.show-for-xxlarge-up{display:table-header-group !important}tbody.hide-for-small-only,tbody.show-for-small-up,tbody.hide-for-small,tbody.hide-for-small-down,tbody.hide-for-medium-only,tbody.show-for-medium-up,tbody.hide-for-medium,tbody.hide-for-medium-down,tbody.hide-for-large-only,tbody.show-for-large-up,tbody.hide-for-large,tbody.hide-for-large-down,tbody.hide-for-xlarge-only,tbody.show-for-xlarge-up,tbody.show-for-xxlarge-only,tbody.show-for-xxlarge-up{display:table-row-group !important}tr.hide-for-small-only,tr.show-for-small-up,tr.hide-for-small,tr.hide-for-small-down,tr.hide-for-medium-only,tr.show-for-medium-up,tr.hide-for-medium,tr.hide-for-medium-down,tr.hide-for-large-only,tr.show-for-large-up,tr.hide-for-large,tr.hide-for-large-down,tr.hide-for-xlarge-only,tr.show-for-xlarge-up,tr.show-for-xxlarge-only,tr.show-for-xxlarge-up{display:table-row !important}th.hide-for-small-only,td.hide-for-small-only,th.show-for-small-up,td.show-for-small-up,th.hide-for-small,td.hide-for-small,th.hide-for-small-down,td.hide-for-small-down,th.hide-for-medium-only,td.hide-for-medium-only,th.show-for-medium-up,td.show-for-medium-up,th.hide-for-medium,td.hide-for-medium,th.hide-for-medium-down,td.hide-for-medium-down,th.hide-for-large-only,td.hide-for-large-only,th.show-for-large-up,td.show-for-large-up,th.hide-for-large,td.hide-for-large,th.hide-for-large-down,td.hide-for-large-down,th.hide-for-xlarge-only,td.hide-for-xlarge-only,th.show-for-xlarge-up,td.show-for-xlarge-up,th.show-for-xxlarge-only,td.show-for-xxlarge-only,th.show-for-xxlarge-up,td.show-for-xxlarge-up{display:table-cell !important}}.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.hide-for-landscape,table.show-for-portrait{display:table}thead.hide-for-landscape,thead.show-for-portrait{display:table-header-group !important}tbody.hide-for-landscape,tbody.show-for-portrait{display:table-row-group !important}tr.hide-for-landscape,tr.show-for-portrait{display:table-row !important}td.hide-for-landscape,td.show-for-portrait,th.hide-for-landscape,th.show-for-portrait{display:table-cell !important}@media only screen and (orientation: landscape){.show-for-landscape,.hide-for-portrait{display:inherit !important}.hide-for-landscape,.show-for-portrait{display:none !important}table.show-for-landscape,table.hide-for-portrait{display:table}thead.show-for-landscape,thead.hide-for-portrait{display:table-header-group !important}tbody.show-for-landscape,tbody.hide-for-portrait{display:table-row-group !important}tr.show-for-landscape,tr.hide-for-portrait{display:table-row !important}td.show-for-landscape,td.hide-for-portrait,th.show-for-landscape,th.hide-for-portrait{display:table-cell !important}}@media only screen and (orientation: portrait){.show-for-portrait,.hide-for-landscape{display:inherit !important}.hide-for-portrait,.show-for-landscape{display:none !important}table.show-for-portrait,table.hide-for-landscape{display:table}thead.show-for-portrait,thead.hide-for-landscape{display:table-header-group !important}tbody.show-for-portrait,tbody.hide-for-landscape{display:table-row-group !important}tr.show-for-portrait,tr.hide-for-landscape{display:table-row !important}td.show-for-portrait,td.hide-for-landscape,th.show-for-portrait,th.hide-for-landscape{display:table-cell !important}}.show-for-touch{display:none !important}.hide-for-touch{display:inherit !important}.touch .show-for-touch{display:inherit !important}.touch .hide-for-touch{display:none !important}table.hide-for-touch{display:table}.touch table.show-for-touch{display:table}thead.hide-for-touch{display:table-header-group !important}.touch thead.show-for-touch{display:table-header-group !important}tbody.hide-for-touch{display:table-row-group !important}.touch tbody.show-for-touch{display:table-row-group !important}tr.hide-for-touch{display:table-row !important}.touch tr.show-for-touch{display:table-row !important}td.hide-for-touch{display:table-cell !important}.touch td.show-for-touch{display:table-cell !important}th.hide-for-touch{display:table-cell !important}.touch th.show-for-touch{display:table-cell !important}@media print{.show-for-print{display:block}.hide-for-print{display:none}table.show-for-print{display:table}thead.show-for-print{display:table-header-group !important}tbody.show-for-print{display:table-row-group !important}tr.show-for-print{display:table-row !important}td.show-for-print{display:table-cell !important}th.show-for-print{display:table-cell !important}} diff --git a/webroot/css/cake.css b/webroot/css/cake.css deleted file mode 100644 index d9982b3..0000000 --- a/webroot/css/cake.css +++ /dev/null @@ -1,384 +0,0 @@ -a.disabled { - pointer-events: none; -} - -a:hover { - color: #15848F; -} - -a { - color: #1798A5; -} - -.side-nav li a:not(.button) { - color: #15848F; -} - -.side-nav li a:not(.button):hover { - color: #15848F; -} - -header { - background-color: #15848F; - color: #ffffff; - font-size: 30px; - height: 84px; - line-height: 64px; - padding: 16px 0px; - box-shadow: 0px 1px rgba(0, 0, 0, 0.24); -} - -header .header-title { - padding-left:80px -} - - -legend { - color:#15848F; -} - -.row { - max-width: 80rem; -} - -.actions.columns { - margin-top:1rem; - border-left: 5px solid #15848F; - padding-left: 15px; - padding: 32px 20px; -} - -.actions.columns h3 { - color:#15848F; -} - -.index table { - margin-top: 2rem; - border: 0; -} - -.index table thead { - height: 3.5rem; -} - -.header-help { - float: right; - margin-right:2rem; - margin-top: -80px; - font-size:16px; -} - -.header-help span { - font-weight: normal; - text-align: center; - text-decoration: none; - line-height: 1; - white-space: nowrap; - display: inline-block; - padding: 0.25rem 0.5rem 0.375rem; - font-size: 0.8rem; - background-color: #0097a7; - color: #FFF; - border-radius: 1000px; -} - -.header-help a { - color: #fff; -} - -ul.pagination li a { - color: rgba(0, 0 ,0 , 0.54); -} - -ul.pagination li.active a { - background: none repeat scroll 0% 0% #DCE47E; - color: #FFF; - font-weight: bold; - cursor: default; -} - -.paginator { - text-align: center; -} - -.paginator ul.pagination li { - float: none; - display: inline-block; -} - -.paginator p { - text-align: right; - color: rgba(0, 0 ,0 , 0.54); -} - -button { - background: #8D6E65; -} - -.form button:hover, .form button:focus { - background: #7A6058; - box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.26) !important; -} - -.form button[type="submit"] { - float: right; - text-transform: uppercase; - box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.26); -} - -.form .error-message { - display: block; - padding: 0.375rem 0.5625rem 0.5625rem; - margin-top: -1px; - margin-bottom: 1rem; - font-size: 0.75rem; - font-weight: normal; - font-style: italic; - color: rgba(0, 0, 0, 0.54); -} - -.required > label { - font-weight: bold; -} -.required > label:after { - content: ' *'; - color: #C3232D; -} - -select[multiple] { - min-height:150px; - background: none; -} -input[type=checkbox], -input[type=radio] { - margin-right: 0.5em; -} - -.date select, -.time select, -.datetime select { - display: inline; - width: auto; - margin-right: 10px; -} - -.error label, -.error label.error { - color: #C3232D; -} - -div.message { - border-style: solid; - border-width: 1px; - display: block; - font-weight: normal; - position: relative; - padding: 0.875rem 1.5rem 0.875rem 20%; - transition: opacity 300ms ease-out 0s; - background-color: #DCE47E; - border-color: #DCE47E; - color: #626262; -} - -div.message.error { - background-color: #C3232D; - border-color: #C3232D; - color: #FFF; -} - -div.message:before { - line-height: 0px; - font-size: 20px; - height: 12px; - width: 12px; - border-radius: 15px; - text-align: center; - vertical-align: middle; - display: inline-block; - position: relative; - left: -11px; - background-color: #FFF; - padding: 12px 14px 12px 10px; - content: "i"; - color: #DCE47E; -} - -div.message.error:before { - padding: 11px 16px 14px 7px; - color: #C3232D; - content: "x"; -} - -.view h2 { - color: #6F6F6F; -} - -.view .columns.strings { - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin-right:0.7rem; -} - -.view .numbers { - background-color: #B7E3EC; - color: #FFF; - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin-right: 0.7rem; -} - -.view .columns.dates { - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin-right:0.7rem; - background-color:#DCE47E; - color: #fff; -} - -.view .columns.booleans { - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin-right:0.7rem; - background-color: #8D6E65; - color: #fff; -} - -.view .strings p { - border-bottom: 1px solid #eee; -} -.view .numbers .subheader, .view .dates .subheader { - color:#747474; -} -.view .booleans .subheader { - color: #E9E9E9 -} - -.view .texts .columns { - margin-top:1.2rem; - border-bottom: 1px solid #eee; -} - - -/** Notices and Errors **/ -.cake-error, -.cake-debug, -.notice, -p.error, -p.notice { - display: block; - clear: both; - background-repeat: repeat-x; - margin-bottom: 18px; - padding: 7px 14px; - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); -} - -.cake-debug, -.notice, -p.notice { - color: #000000; - background: #ffcc00; -} - -.cake-error, -p.error { - color: #fff; - background: #C3232D; -} - -pre { - background: none repeat scroll 0% 0% #FFF; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin: 15px 0px; - color: rgba(0, 0 ,0 , 0.74); - padding:5px; -} - -.cake-error .cake-stack-trace { - margin-top:10px; -} - -.cake-stack-trace code { - background: inherit; - border:0; -} - -.cake-code-dump .code-highlight { - display: block; - background-color: #FFC600; -} - -.cake-error a, -.cake-error a:hover { - color:#fff; - text-decoration: underline; -} - -.home header { - width: 100%; - height: 85%; - position: relative; - display: table; -} - -.home h1 { - font-family: "Gill Sans MT", Calibri, sans-serif; -} - -.home header .header-image { - display: table-cell; - vertical-align: middle; - text-align: center; -} - -.home header h1 { - color: #fff; -} - -.home .checks { - padding:30px; - color: #626262; - border-radius: 3px; - box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.24); - margin-top:50px; -} - -.checks.platform { - background-color: #B7E3EC; -} - -.checks.filesystem { - background: #DCE47E; -} - -.checks.database { - background-color: #DFF0D8; - padding-bottom: 10px; - margin-bottom: 30px; -} - -.home .checks .success:before, .home .checks .problem:before { - line-height: 0px; - font-size: 28px; - height: 12px; - width: 12px; - border-radius: 15px; - text-align: center; - vertical-align: middle; - display: inline-block; - position: relative; - left: -11px; -} - -.home .checks .success:before { - content: "✓"; - color: green; - margin-right: 9px; -} - -.home .checks .problem:before { - content: "✘"; - color: red; - margin-right: 9px; -} diff --git a/webroot/css/custom.css b/webroot/css/custom.css deleted file mode 100644 index c4988b0..0000000 --- a/webroot/css/custom.css +++ /dev/null @@ -1,24 +0,0 @@ -.index { - margin-top: 1rem; - padding-left: 15px; - padding: 32px 20px; -} - -.index h3 { - color: #15848F; -} - -li.active>a:not(.button) { - background-color:#D8D8D8; -} - -.side-nav li.active>a:first-child:not(.button) { - color: black; - font-weight: bold; -} - -.header-title a { - color: #FFFFFF; - font-weight: bold; -} -