diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..422e619 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.php] +indent_style = tab +indent_size = 2 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9437702 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +api/vendor/ + +# OS generated files +.DS_Store +.DS_Store? +._* +Thumbs.db + +# Logs +*.log + +# Dependency directories +node_modules +bower_components + +# Build Systems +.sass-cache +*.css.map +build/ +dist/ \ No newline at end of file diff --git a/README.md b/README.md index 52cbf09..55ec010 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,41 @@ # Foodbank -Rules Engine and API for Feeding America / Foodbank Project. +Rules Engine and API for Feeding America / Foodbank Project. PHP and MySQL. + +## API + +Everything is located in the `/api` directory. You will need [composer](https://getcomposer.org/) installed. + +The entire API runs from `index.php`. This way everything routes to http://foodbankurl.com/api/. + +Propel was used to generate the ORM. The ORM lives under: + +``` +/api + /generated-classes # All of the main ORM classes used in our application. + /generated-conf # Configuration for the ORM + /generated-sql # Explicit creation queries for our DB structure. +``` + +The Routing is handled through the `routes` folder, and are [Slim](http://www.slimframework.com/) routes. + +### Development + +``` +cd api +composer install +php -S localhost:8000 +``` + +A `Foodbank.postman_collection.json` file has been added. You can import this to Postman to test routes. + +### Helpful URLs + +[Propel ORM Calls](http://propelorm.org/documentation/03-basic-crud.html) + +[PHPMyAdmin](http://www.develop.digitalmediauconn.org/phpmyadmin/) + +[Routing with Slim](http://www.slimframework.com/docs/objects/router.html#how-to-create-routes) ## Contact diff --git a/api/.htaccess b/api/.htaccess new file mode 100644 index 0000000..11b28de --- /dev/null +++ b/api/.htaccess @@ -0,0 +1,4 @@ +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^ index.php [QSA,L] \ No newline at end of file diff --git a/api/Foodbank.postman_collection.json b/api/Foodbank.postman_collection.json new file mode 100644 index 0000000..8a9179b --- /dev/null +++ b/api/Foodbank.postman_collection.json @@ -0,0 +1,25 @@ +{ + "variables": [], + "info": { + "name": "Foodbank", + "_postman_id": "a8e172cf-8f6b-3abf-a0ee-90832eecb2bf", + "description": "", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "GET All Categories", + "request": { + "url": "http://localhost:8000/category/all", + "method": "GET", + "header": [], + "body": { + "mode": "formdata", + "formdata": [] + }, + "description": "" + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/api/composer.json b/api/composer.json new file mode 100644 index 0000000..2b1a290 --- /dev/null +++ b/api/composer.json @@ -0,0 +1,14 @@ +{ + "name": "brian/foodbank", + "type": "project", + "authors": [ + { + "name": "briankelleher", + "email": "bkelleher4@gmail.com" + } + ], + "require": { + "propel/propel": "~2.0@dev", + "slim/slim": "~3.0" + } +} diff --git a/api/composer.lock b/api/composer.lock new file mode 100644 index 0000000..4cf48b4 --- /dev/null +++ b/api/composer.lock @@ -0,0 +1,883 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "bcabdd706f796d0db77a591eea6cbe9b", + "packages": [ + { + "name": "container-interop/container-interop", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "time": "2014-12-30T15:22:37+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/8ea928195fa9b907f0d6e48312d323c1a13cc2af", + "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "time": "2016-06-12T19:08:51+00:00" + }, + { + "name": "pimple/pimple", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2015-09-11T15:10:35+00:00" + }, + { + "name": "propel/propel", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/propelorm/Propel2.git", + "reference": "58d57adc9509e47af757b00458d83c24b273fbfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/propelorm/Propel2/zipball/58d57adc9509e47af757b00458d83c24b273fbfa", + "reference": "58d57adc9509e47af757b00458d83c24b273fbfa", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "psr/log": "~1.0", + "symfony/config": "~2.3||~3.0", + "symfony/console": "~2.3||~3.0", + "symfony/filesystem": "~2.3||~3.0", + "symfony/finder": "~2.3||~3.0", + "symfony/validator": "~2.3||~3.0", + "symfony/yaml": "~2.3||~3.0" + }, + "require-dev": { + "behat/behat": "~2.4", + "monolog/monolog": "~1.3", + "phpunit/phpunit": "~4.0||~5.0" + }, + "suggest": { + "monolog/monolog": "The recommended logging library to use with Propel." + }, + "bin": [ + "bin/propel" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "Propel": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "william.durand1@gmail.com" + } + ], + "description": "Propel2 is an open-source Object-Relational Mapping (ORM) for PHP 5.5 and up.", + "homepage": "http://www.propelorm.org/", + "keywords": [ + "Active Record", + "orm", + "persistence" + ], + "time": "2016-10-15 23:21:13" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "slim/slim", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/184352bc1913d7ba552ab4131d62f4730ddb0893", + "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "^1.1", + "nikic/fast-route": "^1.0", + "php": ">=5.5.0", + "pimple/pimple": "^3.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "http://slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "time": "2016-07-26T15:12:13+00:00" + }, + { + "name": "symfony/config", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "949e7e846743a7f9e46dc50eb639d5fde1f53341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/949e7e846743a7f9e46dc50eb639d5fde1f53341", + "reference": "949e7e846743a7f9e46dc50eb639d5fde1f53341", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2016-09-25T08:27:07+00:00" + }, + { + "name": "symfony/console", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/c99da1119ae61e15de0e4829196b9fba6f73d065", + "reference": "c99da1119ae61e15de0e4829196b9fba6f73d065", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2016-10-06T01:44:51+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", + "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2016-09-06T11:02:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "0565b61bf098cb4dc09f4f103f033138ae4f42c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0565b61bf098cb4dc09f4f103f033138ae4f42c6", + "reference": "0565b61bf098cb4dc09f4f103f033138ae4f42c6", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2016-10-18T04:30:12+00:00" + }, + { + "name": "symfony/finder", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", + "reference": "205b5ffbb518a98ba2ae60a52656c4a31ab00c6f", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2016-09-28T00:11:12+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "dff51f72b0706335131b00a7f49606168c582594" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18T14:26:46+00:00" + }, + { + "name": "symfony/translation", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "ff1285087397d2f64041b35e591f3025881c90cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/ff1285087397d2f64041b35e591f3025881c90cd", + "reference": "ff1285087397d2f64041b35e591f3025881c90cd", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2016-10-18T04:30:12+00:00" + }, + { + "name": "symfony/validator", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "709dffa9193ee2b88e1fb1760cc0ba5780f1a8b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/709dffa9193ee2b88e1fb1760cc0ba5780f1a8b2", + "reference": "709dffa9193ee2b88e1fb1760cc0ba5780f1a8b2", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation": "~2.8|~3.0" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "egulias/email-validator": "~1.2,>=1.2.1", + "symfony/cache": "~3.1", + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "egulias/email-validator": "Strict (RFC compliant) email validation", + "psr/cache-implementation": "For using the metadata cache.", + "symfony/config": "", + "symfony/expression-language": "For using the Expression validator", + "symfony/http-foundation": "", + "symfony/intl": "", + "symfony/property-access": "For using the Expression validator", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Validator Component", + "homepage": "https://symfony.com", + "time": "2016-10-19T22:38:53+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27", + "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2016-10-24T18:41:13+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "propel/propel": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/api/config.php b/api/config.php new file mode 100644 index 0000000..c07ab83 --- /dev/null +++ b/api/config.php @@ -0,0 +1,4 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another Category instance. If + * obj is an instance of Category, delegates to + * equals(Category). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|Category The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [name] column value. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\Category The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[CategoryTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [name] column. + * + * @param string $v new value + * @return $this|\Category The current object (for fluent API support) + */ + public function setName($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[CategoryTableMap::COL_NAME] = true; + } + + return $this; + } // setName() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : CategoryTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : CategoryTableMap::translateFieldName('Name', TableMap::TYPE_PHPNAME, $indexType)]; + $this->name = (null !== $col) ? (string) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 2; // 2 = CategoryTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\Category'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(CategoryTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildCategoryQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->collCategoryRankNutrients = null; + + $this->collFoods = null; + + $this->collSubcategories = null; + + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see Category::setDeleted() + * @see Category::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildCategoryQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + CategoryTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + if ($this->categoryRankNutrientsScheduledForDeletion !== null) { + if (!$this->categoryRankNutrientsScheduledForDeletion->isEmpty()) { + \CategoryRankNutrientQuery::create() + ->filterByPrimaryKeys($this->categoryRankNutrientsScheduledForDeletion->getPrimaryKeys(false)) + ->delete($con); + $this->categoryRankNutrientsScheduledForDeletion = null; + } + } + + if ($this->collCategoryRankNutrients !== null) { + foreach ($this->collCategoryRankNutrients as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->foodsScheduledForDeletion !== null) { + if (!$this->foodsScheduledForDeletion->isEmpty()) { + foreach ($this->foodsScheduledForDeletion as $food) { + // need to save related object because we set the relation to null + $food->save($con); + } + $this->foodsScheduledForDeletion = null; + } + } + + if ($this->collFoods !== null) { + foreach ($this->collFoods as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->subcategoriesScheduledForDeletion !== null) { + if (!$this->subcategoriesScheduledForDeletion->isEmpty()) { + foreach ($this->subcategoriesScheduledForDeletion as $subcategory) { + // need to save related object because we set the relation to null + $subcategory->save($con); + } + $this->subcategoriesScheduledForDeletion = null; + } + } + + if ($this->collSubcategories !== null) { + foreach ($this->collSubcategories as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[CategoryTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . CategoryTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(CategoryTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(CategoryTableMap::COL_NAME)) { + $modifiedColumns[':p' . $index++] = 'name'; + } + + $sql = sprintf( + 'INSERT INTO Category (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'name': + $stmt->bindValue($identifier, $this->name, PDO::PARAM_STR); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = CategoryTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['Category'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['Category'][$this->hashCode()] = true; + $keys = CategoryTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->collCategoryRankNutrients) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'categoryRankNutrients'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category_Rank_Nutrients'; + break; + default: + $key = 'CategoryRankNutrients'; + } + + $result[$key] = $this->collCategoryRankNutrients->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + if (null !== $this->collFoods) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'foods'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Foods'; + break; + default: + $key = 'Foods'; + } + + $result[$key] = $this->collFoods->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + if (null !== $this->collSubcategories) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'subcategories'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Subcategories'; + break; + default: + $key = 'Subcategories'; + } + + $result[$key] = $this->collSubcategories->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\Category + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = CategoryTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\Category + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = CategoryTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setName($arr[$keys[1]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\Category The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(CategoryTableMap::DATABASE_NAME); + + if ($this->isColumnModified(CategoryTableMap::COL_ID)) { + $criteria->add(CategoryTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(CategoryTableMap::COL_NAME)) { + $criteria->add(CategoryTableMap::COL_NAME, $this->name); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildCategoryQuery::create(); + $criteria->add(CategoryTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Category (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setName($this->getName()); + + if ($deepCopy) { + // important: temporarily setNew(false) because this affects the behavior of + // the getter/setter methods for fkey referrer objects. + $copyObj->setNew(false); + + foreach ($this->getCategoryRankNutrients() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addCategoryRankNutrient($relObj->copy($deepCopy)); + } + } + + foreach ($this->getFoods() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addFood($relObj->copy($deepCopy)); + } + } + + foreach ($this->getSubcategories() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addSubcategory($relObj->copy($deepCopy)); + } + } + + } // if ($deepCopy) + + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Category Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + + /** + * Initializes a collection based on the name of a relation. + * Avoids crafting an 'init[$relationName]s' method name + * that wouldn't work when StandardEnglishPluralizer is used. + * + * @param string $relationName The name of the relation to initialize + * @return void + */ + public function initRelation($relationName) + { + if ('CategoryRankNutrient' == $relationName) { + return $this->initCategoryRankNutrients(); + } + if ('Food' == $relationName) { + return $this->initFoods(); + } + if ('Subcategory' == $relationName) { + return $this->initSubcategories(); + } + } + + /** + * Clears out the collCategoryRankNutrients collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addCategoryRankNutrients() + */ + public function clearCategoryRankNutrients() + { + $this->collCategoryRankNutrients = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collCategoryRankNutrients collection loaded partially. + */ + public function resetPartialCategoryRankNutrients($v = true) + { + $this->collCategoryRankNutrientsPartial = $v; + } + + /** + * Initializes the collCategoryRankNutrients collection. + * + * By default this just sets the collCategoryRankNutrients collection to an empty array (like clearcollCategoryRankNutrients()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initCategoryRankNutrients($overrideExisting = true) + { + if (null !== $this->collCategoryRankNutrients && !$overrideExisting) { + return; + } + + $collectionClassName = CategoryRankNutrientTableMap::getTableMap()->getCollectionClassName(); + + $this->collCategoryRankNutrients = new $collectionClassName; + $this->collCategoryRankNutrients->setModel('\CategoryRankNutrient'); + } + + /** + * Gets an array of ChildCategoryRankNutrient objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildCategory is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + * @throws PropelException + */ + public function getCategoryRankNutrients(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + // return empty collection + $this->initCategoryRankNutrients(); + } else { + $collCategoryRankNutrients = ChildCategoryRankNutrientQuery::create(null, $criteria) + ->filterByCategory($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collCategoryRankNutrientsPartial && count($collCategoryRankNutrients)) { + $this->initCategoryRankNutrients(false); + + foreach ($collCategoryRankNutrients as $obj) { + if (false == $this->collCategoryRankNutrients->contains($obj)) { + $this->collCategoryRankNutrients->append($obj); + } + } + + $this->collCategoryRankNutrientsPartial = true; + } + + return $collCategoryRankNutrients; + } + + if ($partial && $this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $obj) { + if ($obj->isNew()) { + $collCategoryRankNutrients[] = $obj; + } + } + } + + $this->collCategoryRankNutrients = $collCategoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + } + } + + return $this->collCategoryRankNutrients; + } + + /** + * Sets a collection of ChildCategoryRankNutrient objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $categoryRankNutrients A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function setCategoryRankNutrients(Collection $categoryRankNutrients, ConnectionInterface $con = null) + { + /** @var ChildCategoryRankNutrient[] $categoryRankNutrientsToDelete */ + $categoryRankNutrientsToDelete = $this->getCategoryRankNutrients(new Criteria(), $con)->diff($categoryRankNutrients); + + + $this->categoryRankNutrientsScheduledForDeletion = $categoryRankNutrientsToDelete; + + foreach ($categoryRankNutrientsToDelete as $categoryRankNutrientRemoved) { + $categoryRankNutrientRemoved->setCategory(null); + } + + $this->collCategoryRankNutrients = null; + foreach ($categoryRankNutrients as $categoryRankNutrient) { + $this->addCategoryRankNutrient($categoryRankNutrient); + } + + $this->collCategoryRankNutrients = $categoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + + return $this; + } + + /** + * Returns the number of related CategoryRankNutrient objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related CategoryRankNutrient objects. + * @throws PropelException + */ + public function countCategoryRankNutrients(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getCategoryRankNutrients()); + } + + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByCategory($this) + ->count($con); + } + + return count($this->collCategoryRankNutrients); + } + + /** + * Method called to associate a ChildCategoryRankNutrient object to this object + * through the ChildCategoryRankNutrient foreign key attribute. + * + * @param ChildCategoryRankNutrient $l ChildCategoryRankNutrient + * @return $this|\Category The current object (for fluent API support) + */ + public function addCategoryRankNutrient(ChildCategoryRankNutrient $l) + { + if ($this->collCategoryRankNutrients === null) { + $this->initCategoryRankNutrients(); + $this->collCategoryRankNutrientsPartial = true; + } + + if (!$this->collCategoryRankNutrients->contains($l)) { + $this->doAddCategoryRankNutrient($l); + + if ($this->categoryRankNutrientsScheduledForDeletion and $this->categoryRankNutrientsScheduledForDeletion->contains($l)) { + $this->categoryRankNutrientsScheduledForDeletion->remove($this->categoryRankNutrientsScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to add. + */ + protected function doAddCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + $this->collCategoryRankNutrients[]= $categoryRankNutrient; + $categoryRankNutrient->setCategory($this); + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to remove. + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function removeCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + if ($this->getCategoryRankNutrients()->contains($categoryRankNutrient)) { + $pos = $this->collCategoryRankNutrients->search($categoryRankNutrient); + $this->collCategoryRankNutrients->remove($pos); + if (null === $this->categoryRankNutrientsScheduledForDeletion) { + $this->categoryRankNutrientsScheduledForDeletion = clone $this->collCategoryRankNutrients; + $this->categoryRankNutrientsScheduledForDeletion->clear(); + } + $this->categoryRankNutrientsScheduledForDeletion[]= clone $categoryRankNutrient; + $categoryRankNutrient->setCategory(null); + } + + return $this; + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Category is new, it will return + * an empty collection; or if this Category has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Category. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinNutrient(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Nutrient', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Category is new, it will return + * an empty collection; or if this Category has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Category. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinRank(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Rank', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + /** + * Clears out the collFoods collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addFoods() + */ + public function clearFoods() + { + $this->collFoods = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collFoods collection loaded partially. + */ + public function resetPartialFoods($v = true) + { + $this->collFoodsPartial = $v; + } + + /** + * Initializes the collFoods collection. + * + * By default this just sets the collFoods collection to an empty array (like clearcollFoods()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initFoods($overrideExisting = true) + { + if (null !== $this->collFoods && !$overrideExisting) { + return; + } + + $collectionClassName = FoodTableMap::getTableMap()->getCollectionClassName(); + + $this->collFoods = new $collectionClassName; + $this->collFoods->setModel('\Food'); + } + + /** + * Gets an array of ChildFood objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildCategory is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildFood[] List of ChildFood objects + * @throws PropelException + */ + public function getFoods(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collFoodsPartial && !$this->isNew(); + if (null === $this->collFoods || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collFoods) { + // return empty collection + $this->initFoods(); + } else { + $collFoods = ChildFoodQuery::create(null, $criteria) + ->filterByCategory($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collFoodsPartial && count($collFoods)) { + $this->initFoods(false); + + foreach ($collFoods as $obj) { + if (false == $this->collFoods->contains($obj)) { + $this->collFoods->append($obj); + } + } + + $this->collFoodsPartial = true; + } + + return $collFoods; + } + + if ($partial && $this->collFoods) { + foreach ($this->collFoods as $obj) { + if ($obj->isNew()) { + $collFoods[] = $obj; + } + } + } + + $this->collFoods = $collFoods; + $this->collFoodsPartial = false; + } + } + + return $this->collFoods; + } + + /** + * Sets a collection of ChildFood objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $foods A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function setFoods(Collection $foods, ConnectionInterface $con = null) + { + /** @var ChildFood[] $foodsToDelete */ + $foodsToDelete = $this->getFoods(new Criteria(), $con)->diff($foods); + + + $this->foodsScheduledForDeletion = $foodsToDelete; + + foreach ($foodsToDelete as $foodRemoved) { + $foodRemoved->setCategory(null); + } + + $this->collFoods = null; + foreach ($foods as $food) { + $this->addFood($food); + } + + $this->collFoods = $foods; + $this->collFoodsPartial = false; + + return $this; + } + + /** + * Returns the number of related Food objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related Food objects. + * @throws PropelException + */ + public function countFoods(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collFoodsPartial && !$this->isNew(); + if (null === $this->collFoods || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collFoods) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getFoods()); + } + + $query = ChildFoodQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByCategory($this) + ->count($con); + } + + return count($this->collFoods); + } + + /** + * Method called to associate a ChildFood object to this object + * through the ChildFood foreign key attribute. + * + * @param ChildFood $l ChildFood + * @return $this|\Category The current object (for fluent API support) + */ + public function addFood(ChildFood $l) + { + if ($this->collFoods === null) { + $this->initFoods(); + $this->collFoodsPartial = true; + } + + if (!$this->collFoods->contains($l)) { + $this->doAddFood($l); + + if ($this->foodsScheduledForDeletion and $this->foodsScheduledForDeletion->contains($l)) { + $this->foodsScheduledForDeletion->remove($this->foodsScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildFood $food The ChildFood object to add. + */ + protected function doAddFood(ChildFood $food) + { + $this->collFoods[]= $food; + $food->setCategory($this); + } + + /** + * @param ChildFood $food The ChildFood object to remove. + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function removeFood(ChildFood $food) + { + if ($this->getFoods()->contains($food)) { + $pos = $this->collFoods->search($food); + $this->collFoods->remove($pos); + if (null === $this->foodsScheduledForDeletion) { + $this->foodsScheduledForDeletion = clone $this->collFoods; + $this->foodsScheduledForDeletion->clear(); + } + $this->foodsScheduledForDeletion[]= $food; + $food->setCategory(null); + } + + return $this; + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Category is new, it will return + * an empty collection; or if this Category has previously + * been saved, it will retrieve related Foods from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Category. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildFood[] List of ChildFood objects + */ + public function getFoodsJoinRank(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildFoodQuery::create(null, $criteria); + $query->joinWith('Rank', $joinBehavior); + + return $this->getFoods($query, $con); + } + + /** + * Clears out the collSubcategories collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addSubcategories() + */ + public function clearSubcategories() + { + $this->collSubcategories = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collSubcategories collection loaded partially. + */ + public function resetPartialSubcategories($v = true) + { + $this->collSubcategoriesPartial = $v; + } + + /** + * Initializes the collSubcategories collection. + * + * By default this just sets the collSubcategories collection to an empty array (like clearcollSubcategories()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initSubcategories($overrideExisting = true) + { + if (null !== $this->collSubcategories && !$overrideExisting) { + return; + } + + $collectionClassName = SubcategoryTableMap::getTableMap()->getCollectionClassName(); + + $this->collSubcategories = new $collectionClassName; + $this->collSubcategories->setModel('\Subcategory'); + } + + /** + * Gets an array of ChildSubcategory objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildCategory is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildSubcategory[] List of ChildSubcategory objects + * @throws PropelException + */ + public function getSubcategories(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collSubcategoriesPartial && !$this->isNew(); + if (null === $this->collSubcategories || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collSubcategories) { + // return empty collection + $this->initSubcategories(); + } else { + $collSubcategories = ChildSubcategoryQuery::create(null, $criteria) + ->filterByCategory($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collSubcategoriesPartial && count($collSubcategories)) { + $this->initSubcategories(false); + + foreach ($collSubcategories as $obj) { + if (false == $this->collSubcategories->contains($obj)) { + $this->collSubcategories->append($obj); + } + } + + $this->collSubcategoriesPartial = true; + } + + return $collSubcategories; + } + + if ($partial && $this->collSubcategories) { + foreach ($this->collSubcategories as $obj) { + if ($obj->isNew()) { + $collSubcategories[] = $obj; + } + } + } + + $this->collSubcategories = $collSubcategories; + $this->collSubcategoriesPartial = false; + } + } + + return $this->collSubcategories; + } + + /** + * Sets a collection of ChildSubcategory objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $subcategories A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function setSubcategories(Collection $subcategories, ConnectionInterface $con = null) + { + /** @var ChildSubcategory[] $subcategoriesToDelete */ + $subcategoriesToDelete = $this->getSubcategories(new Criteria(), $con)->diff($subcategories); + + + $this->subcategoriesScheduledForDeletion = $subcategoriesToDelete; + + foreach ($subcategoriesToDelete as $subcategoryRemoved) { + $subcategoryRemoved->setCategory(null); + } + + $this->collSubcategories = null; + foreach ($subcategories as $subcategory) { + $this->addSubcategory($subcategory); + } + + $this->collSubcategories = $subcategories; + $this->collSubcategoriesPartial = false; + + return $this; + } + + /** + * Returns the number of related Subcategory objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related Subcategory objects. + * @throws PropelException + */ + public function countSubcategories(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collSubcategoriesPartial && !$this->isNew(); + if (null === $this->collSubcategories || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collSubcategories) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getSubcategories()); + } + + $query = ChildSubcategoryQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByCategory($this) + ->count($con); + } + + return count($this->collSubcategories); + } + + /** + * Method called to associate a ChildSubcategory object to this object + * through the ChildSubcategory foreign key attribute. + * + * @param ChildSubcategory $l ChildSubcategory + * @return $this|\Category The current object (for fluent API support) + */ + public function addSubcategory(ChildSubcategory $l) + { + if ($this->collSubcategories === null) { + $this->initSubcategories(); + $this->collSubcategoriesPartial = true; + } + + if (!$this->collSubcategories->contains($l)) { + $this->doAddSubcategory($l); + + if ($this->subcategoriesScheduledForDeletion and $this->subcategoriesScheduledForDeletion->contains($l)) { + $this->subcategoriesScheduledForDeletion->remove($this->subcategoriesScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildSubcategory $subcategory The ChildSubcategory object to add. + */ + protected function doAddSubcategory(ChildSubcategory $subcategory) + { + $this->collSubcategories[]= $subcategory; + $subcategory->setCategory($this); + } + + /** + * @param ChildSubcategory $subcategory The ChildSubcategory object to remove. + * @return $this|ChildCategory The current object (for fluent API support) + */ + public function removeSubcategory(ChildSubcategory $subcategory) + { + if ($this->getSubcategories()->contains($subcategory)) { + $pos = $this->collSubcategories->search($subcategory); + $this->collSubcategories->remove($pos); + if (null === $this->subcategoriesScheduledForDeletion) { + $this->subcategoriesScheduledForDeletion = clone $this->collSubcategories; + $this->subcategoriesScheduledForDeletion->clear(); + } + $this->subcategoriesScheduledForDeletion[]= $subcategory; + $subcategory->setCategory(null); + } + + return $this; + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + $this->id = null; + $this->name = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + if ($this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $o) { + $o->clearAllReferences($deep); + } + } + if ($this->collFoods) { + foreach ($this->collFoods as $o) { + $o->clearAllReferences($deep); + } + } + if ($this->collSubcategories) { + foreach ($this->collSubcategories as $o) { + $o->clearAllReferences($deep); + } + } + } // if ($deep) + + $this->collCategoryRankNutrients = null; + $this->collFoods = null; + $this->collSubcategories = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(CategoryTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/CategoryQuery.php b/api/generated-classes/Base/CategoryQuery.php new file mode 100644 index 0000000..c5bd5b4 --- /dev/null +++ b/api/generated-classes/Base/CategoryQuery.php @@ -0,0 +1,634 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildCategory|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(CategoryTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = CategoryTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildCategory A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, name FROM Category WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildCategory $obj */ + $obj = new ChildCategory(); + $obj->hydrate($row); + CategoryTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildCategory|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(CategoryTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(CategoryTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(CategoryTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(CategoryTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the name column + * + * Example usage: + * + * $query->filterByName('fooValue'); // WHERE name = 'fooValue' + * $query->filterByName('%fooValue%', Criteria::LIKE); // WHERE name LIKE '%fooValue%' + * + * + * @param string $name The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function filterByName($name = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($name)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryTableMap::COL_NAME, $name, $comparison); + } + + /** + * Filter the query by a related \CategoryRankNutrient object + * + * @param \CategoryRankNutrient|ObjectCollection $categoryRankNutrient the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildCategoryQuery The current query, for fluid interface + */ + public function filterByCategoryRankNutrient($categoryRankNutrient, $comparison = null) + { + if ($categoryRankNutrient instanceof \CategoryRankNutrient) { + return $this + ->addUsingAlias(CategoryTableMap::COL_ID, $categoryRankNutrient->getCategoryId(), $comparison); + } elseif ($categoryRankNutrient instanceof ObjectCollection) { + return $this + ->useCategoryRankNutrientQuery() + ->filterByPrimaryKeys($categoryRankNutrient->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByCategoryRankNutrient() only accepts arguments of type \CategoryRankNutrient or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the CategoryRankNutrient relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function joinCategoryRankNutrient($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('CategoryRankNutrient'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'CategoryRankNutrient'); + } + + return $this; + } + + /** + * Use the CategoryRankNutrient relation CategoryRankNutrient object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryRankNutrientQuery A secondary query class using the current class as primary query + */ + public function useCategoryRankNutrientQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinCategoryRankNutrient($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'CategoryRankNutrient', '\CategoryRankNutrientQuery'); + } + + /** + * Filter the query by a related \Food object + * + * @param \Food|ObjectCollection $food the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildCategoryQuery The current query, for fluid interface + */ + public function filterByFood($food, $comparison = null) + { + if ($food instanceof \Food) { + return $this + ->addUsingAlias(CategoryTableMap::COL_ID, $food->getCategoryId(), $comparison); + } elseif ($food instanceof ObjectCollection) { + return $this + ->useFoodQuery() + ->filterByPrimaryKeys($food->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByFood() only accepts arguments of type \Food or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Food relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function joinFood($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Food'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Food'); + } + + return $this; + } + + /** + * Use the Food relation Food object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \FoodQuery A secondary query class using the current class as primary query + */ + public function useFoodQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinFood($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Food', '\FoodQuery'); + } + + /** + * Filter the query by a related \Subcategory object + * + * @param \Subcategory|ObjectCollection $subcategory the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildCategoryQuery The current query, for fluid interface + */ + public function filterBySubcategory($subcategory, $comparison = null) + { + if ($subcategory instanceof \Subcategory) { + return $this + ->addUsingAlias(CategoryTableMap::COL_ID, $subcategory->getCategoryId(), $comparison); + } elseif ($subcategory instanceof ObjectCollection) { + return $this + ->useSubcategoryQuery() + ->filterByPrimaryKeys($subcategory->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterBySubcategory() only accepts arguments of type \Subcategory or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Subcategory relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function joinSubcategory($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Subcategory'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Subcategory'); + } + + return $this; + } + + /** + * Use the Subcategory relation Subcategory object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \SubcategoryQuery A secondary query class using the current class as primary query + */ + public function useSubcategoryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinSubcategory($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Subcategory', '\SubcategoryQuery'); + } + + /** + * Exclude object from result + * + * @param ChildCategory $category Object to remove from the list of results + * + * @return $this|ChildCategoryQuery The current query, for fluid interface + */ + public function prune($category = null) + { + if ($category) { + $this->addUsingAlias(CategoryTableMap::COL_ID, $category->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Category table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + CategoryTableMap::clearInstancePool(); + CategoryTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(CategoryTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + CategoryTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + CategoryTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // CategoryQuery diff --git a/api/generated-classes/Base/CategoryRankNutrient.php b/api/generated-classes/Base/CategoryRankNutrient.php new file mode 100644 index 0000000..3bec93d --- /dev/null +++ b/api/generated-classes/Base/CategoryRankNutrient.php @@ -0,0 +1,1744 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another CategoryRankNutrient instance. If + * obj is an instance of CategoryRankNutrient, delegates to + * equals(CategoryRankNutrient). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|CategoryRankNutrient The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [units] column value. + * + * @return string + */ + public function getUnits() + { + return $this->units; + } + + /** + * Get the [threshold] column value. + * + * @return double + */ + public function getThreshold() + { + return $this->threshold; + } + + /** + * Get the [operator] column value. + * + * @return string + */ + public function getOperator() + { + return $this->operator; + } + + /** + * Get the [category_id] column value. + * + * @return int + */ + public function getCategoryId() + { + return $this->category_id; + } + + /** + * Get the [rank_id] column value. + * + * @return int + */ + public function getRankId() + { + return $this->rank_id; + } + + /** + * Get the [nutrient_id] column value. + * + * @return int + */ + public function getNutrientId() + { + return $this->nutrient_id; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [units] column. + * + * @param string $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setUnits($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->units !== $v) { + $this->units = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_UNITS] = true; + } + + return $this; + } // setUnits() + + /** + * Set the value of [threshold] column. + * + * @param double $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setThreshold($v) + { + if ($v !== null) { + $v = (double) $v; + } + + if ($this->threshold !== $v) { + $this->threshold = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_THRESHOLD] = true; + } + + return $this; + } // setThreshold() + + /** + * Set the value of [operator] column. + * + * @param string $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setOperator($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->operator !== $v) { + $this->operator = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_OPERATOR] = true; + } + + return $this; + } // setOperator() + + /** + * Set the value of [category_id] column. + * + * @param int $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setCategoryId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->category_id !== $v) { + $this->category_id = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_CATEGORY_ID] = true; + } + + if ($this->aCategory !== null && $this->aCategory->getId() !== $v) { + $this->aCategory = null; + } + + return $this; + } // setCategoryId() + + /** + * Set the value of [rank_id] column. + * + * @param int $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setRankId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->rank_id !== $v) { + $this->rank_id = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_RANK_ID] = true; + } + + if ($this->aRank !== null && $this->aRank->getId() !== $v) { + $this->aRank = null; + } + + return $this; + } // setRankId() + + /** + * Set the value of [nutrient_id] column. + * + * @param int $v new value + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + */ + public function setNutrientId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->nutrient_id !== $v) { + $this->nutrient_id = $v; + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_NUTRIENT_ID] = true; + } + + if ($this->aNutrient !== null && $this->aNutrient->getId() !== $v) { + $this->aNutrient = null; + } + + return $this; + } // setNutrientId() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : CategoryRankNutrientTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : CategoryRankNutrientTableMap::translateFieldName('Units', TableMap::TYPE_PHPNAME, $indexType)]; + $this->units = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : CategoryRankNutrientTableMap::translateFieldName('Threshold', TableMap::TYPE_PHPNAME, $indexType)]; + $this->threshold = (null !== $col) ? (double) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : CategoryRankNutrientTableMap::translateFieldName('Operator', TableMap::TYPE_PHPNAME, $indexType)]; + $this->operator = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : CategoryRankNutrientTableMap::translateFieldName('CategoryId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->category_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CategoryRankNutrientTableMap::translateFieldName('RankId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->rank_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : CategoryRankNutrientTableMap::translateFieldName('NutrientId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->nutrient_id = (null !== $col) ? (int) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 7; // 7 = CategoryRankNutrientTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\CategoryRankNutrient'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + if ($this->aCategory !== null && $this->category_id !== $this->aCategory->getId()) { + $this->aCategory = null; + } + if ($this->aRank !== null && $this->rank_id !== $this->aRank->getId()) { + $this->aRank = null; + } + if ($this->aNutrient !== null && $this->nutrient_id !== $this->aNutrient->getId()) { + $this->aNutrient = null; + } + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildCategoryRankNutrientQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->aNutrient = null; + $this->aCategory = null; + $this->aRank = null; + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see CategoryRankNutrient::setDeleted() + * @see CategoryRankNutrient::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildCategoryRankNutrientQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + CategoryRankNutrientTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + // We call the save method on the following object(s) if they + // were passed to this object by their corresponding set + // method. This object relates to these object(s) by a + // foreign key reference. + + if ($this->aNutrient !== null) { + if ($this->aNutrient->isModified() || $this->aNutrient->isNew()) { + $affectedRows += $this->aNutrient->save($con); + } + $this->setNutrient($this->aNutrient); + } + + if ($this->aCategory !== null) { + if ($this->aCategory->isModified() || $this->aCategory->isNew()) { + $affectedRows += $this->aCategory->save($con); + } + $this->setCategory($this->aCategory); + } + + if ($this->aRank !== null) { + if ($this->aRank->isModified() || $this->aRank->isNew()) { + $affectedRows += $this->aRank->save($con); + } + $this->setRank($this->aRank); + } + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[CategoryRankNutrientTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . CategoryRankNutrientTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_UNITS)) { + $modifiedColumns[':p' . $index++] = 'units'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_THRESHOLD)) { + $modifiedColumns[':p' . $index++] = 'threshold'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_OPERATOR)) { + $modifiedColumns[':p' . $index++] = 'operator'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_CATEGORY_ID)) { + $modifiedColumns[':p' . $index++] = 'category_id'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_RANK_ID)) { + $modifiedColumns[':p' . $index++] = 'rank_id'; + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_NUTRIENT_ID)) { + $modifiedColumns[':p' . $index++] = 'nutrient_id'; + } + + $sql = sprintf( + 'INSERT INTO Category_Rank_Nutrient (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'units': + $stmt->bindValue($identifier, $this->units, PDO::PARAM_STR); + break; + case 'threshold': + $stmt->bindValue($identifier, $this->threshold, PDO::PARAM_STR); + break; + case 'operator': + $stmt->bindValue($identifier, $this->operator, PDO::PARAM_STR); + break; + case 'category_id': + $stmt->bindValue($identifier, $this->category_id, PDO::PARAM_INT); + break; + case 'rank_id': + $stmt->bindValue($identifier, $this->rank_id, PDO::PARAM_INT); + break; + case 'nutrient_id': + $stmt->bindValue($identifier, $this->nutrient_id, PDO::PARAM_INT); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = CategoryRankNutrientTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getUnits(); + break; + case 2: + return $this->getThreshold(); + break; + case 3: + return $this->getOperator(); + break; + case 4: + return $this->getCategoryId(); + break; + case 5: + return $this->getRankId(); + break; + case 6: + return $this->getNutrientId(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['CategoryRankNutrient'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['CategoryRankNutrient'][$this->hashCode()] = true; + $keys = CategoryRankNutrientTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getUnits(), + $keys[2] => $this->getThreshold(), + $keys[3] => $this->getOperator(), + $keys[4] => $this->getCategoryId(), + $keys[5] => $this->getRankId(), + $keys[6] => $this->getNutrientId(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->aNutrient) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'nutrient'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Nutrient'; + break; + default: + $key = 'Nutrient'; + } + + $result[$key] = $this->aNutrient->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + if (null !== $this->aCategory) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'category'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category'; + break; + default: + $key = 'Category'; + } + + $result[$key] = $this->aCategory->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + if (null !== $this->aRank) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'rank'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Rank'; + break; + default: + $key = 'Rank'; + } + + $result[$key] = $this->aRank->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\CategoryRankNutrient + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = CategoryRankNutrientTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\CategoryRankNutrient + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setUnits($value); + break; + case 2: + $this->setThreshold($value); + break; + case 3: + $this->setOperator($value); + break; + case 4: + $this->setCategoryId($value); + break; + case 5: + $this->setRankId($value); + break; + case 6: + $this->setNutrientId($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = CategoryRankNutrientTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setUnits($arr[$keys[1]]); + } + if (array_key_exists($keys[2], $arr)) { + $this->setThreshold($arr[$keys[2]]); + } + if (array_key_exists($keys[3], $arr)) { + $this->setOperator($arr[$keys[3]]); + } + if (array_key_exists($keys[4], $arr)) { + $this->setCategoryId($arr[$keys[4]]); + } + if (array_key_exists($keys[5], $arr)) { + $this->setRankId($arr[$keys[5]]); + } + if (array_key_exists($keys[6], $arr)) { + $this->setNutrientId($arr[$keys[6]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\CategoryRankNutrient The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(CategoryRankNutrientTableMap::DATABASE_NAME); + + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_ID)) { + $criteria->add(CategoryRankNutrientTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_UNITS)) { + $criteria->add(CategoryRankNutrientTableMap::COL_UNITS, $this->units); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_THRESHOLD)) { + $criteria->add(CategoryRankNutrientTableMap::COL_THRESHOLD, $this->threshold); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_OPERATOR)) { + $criteria->add(CategoryRankNutrientTableMap::COL_OPERATOR, $this->operator); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_CATEGORY_ID)) { + $criteria->add(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $this->category_id); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_RANK_ID)) { + $criteria->add(CategoryRankNutrientTableMap::COL_RANK_ID, $this->rank_id); + } + if ($this->isColumnModified(CategoryRankNutrientTableMap::COL_NUTRIENT_ID)) { + $criteria->add(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $this->nutrient_id); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildCategoryRankNutrientQuery::create(); + $criteria->add(CategoryRankNutrientTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \CategoryRankNutrient (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setUnits($this->getUnits()); + $copyObj->setThreshold($this->getThreshold()); + $copyObj->setOperator($this->getOperator()); + $copyObj->setCategoryId($this->getCategoryId()); + $copyObj->setRankId($this->getRankId()); + $copyObj->setNutrientId($this->getNutrientId()); + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \CategoryRankNutrient Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + /** + * Declares an association between this object and a ChildNutrient object. + * + * @param ChildNutrient $v + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + * @throws PropelException + */ + public function setNutrient(ChildNutrient $v = null) + { + if ($v === null) { + $this->setNutrientId(NULL); + } else { + $this->setNutrientId($v->getId()); + } + + $this->aNutrient = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildNutrient object, it will not be re-added. + if ($v !== null) { + $v->addCategoryRankNutrient($this); + } + + + return $this; + } + + + /** + * Get the associated ChildNutrient object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildNutrient The associated ChildNutrient object. + * @throws PropelException + */ + public function getNutrient(ConnectionInterface $con = null) + { + if ($this->aNutrient === null && ($this->nutrient_id !== null)) { + $this->aNutrient = ChildNutrientQuery::create()->findPk($this->nutrient_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aNutrient->addCategoryRankNutrients($this); + */ + } + + return $this->aNutrient; + } + + /** + * Declares an association between this object and a ChildCategory object. + * + * @param ChildCategory $v + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + * @throws PropelException + */ + public function setCategory(ChildCategory $v = null) + { + if ($v === null) { + $this->setCategoryId(NULL); + } else { + $this->setCategoryId($v->getId()); + } + + $this->aCategory = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildCategory object, it will not be re-added. + if ($v !== null) { + $v->addCategoryRankNutrient($this); + } + + + return $this; + } + + + /** + * Get the associated ChildCategory object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildCategory The associated ChildCategory object. + * @throws PropelException + */ + public function getCategory(ConnectionInterface $con = null) + { + if ($this->aCategory === null && ($this->category_id !== null)) { + $this->aCategory = ChildCategoryQuery::create()->findPk($this->category_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aCategory->addCategoryRankNutrients($this); + */ + } + + return $this->aCategory; + } + + /** + * Declares an association between this object and a ChildRank object. + * + * @param ChildRank $v + * @return $this|\CategoryRankNutrient The current object (for fluent API support) + * @throws PropelException + */ + public function setRank(ChildRank $v = null) + { + if ($v === null) { + $this->setRankId(NULL); + } else { + $this->setRankId($v->getId()); + } + + $this->aRank = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildRank object, it will not be re-added. + if ($v !== null) { + $v->addCategoryRankNutrient($this); + } + + + return $this; + } + + + /** + * Get the associated ChildRank object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildRank The associated ChildRank object. + * @throws PropelException + */ + public function getRank(ConnectionInterface $con = null) + { + if ($this->aRank === null && ($this->rank_id !== null)) { + $this->aRank = ChildRankQuery::create()->findPk($this->rank_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aRank->addCategoryRankNutrients($this); + */ + } + + return $this->aRank; + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + if (null !== $this->aNutrient) { + $this->aNutrient->removeCategoryRankNutrient($this); + } + if (null !== $this->aCategory) { + $this->aCategory->removeCategoryRankNutrient($this); + } + if (null !== $this->aRank) { + $this->aRank->removeCategoryRankNutrient($this); + } + $this->id = null; + $this->units = null; + $this->threshold = null; + $this->operator = null; + $this->category_id = null; + $this->rank_id = null; + $this->nutrient_id = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + } // if ($deep) + + $this->aNutrient = null; + $this->aCategory = null; + $this->aRank = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(CategoryRankNutrientTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/CategoryRankNutrientQuery.php b/api/generated-classes/Base/CategoryRankNutrientQuery.php new file mode 100644 index 0000000..832818e --- /dev/null +++ b/api/generated-classes/Base/CategoryRankNutrientQuery.php @@ -0,0 +1,866 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildCategoryRankNutrient|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = CategoryRankNutrientTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildCategoryRankNutrient A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, units, threshold, operator, category_id, rank_id, nutrient_id FROM Category_Rank_Nutrient WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildCategoryRankNutrient $obj */ + $obj = new ChildCategoryRankNutrient(); + $obj->hydrate($row); + CategoryRankNutrientTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildCategoryRankNutrient|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the units column + * + * Example usage: + * + * $query->filterByUnits('fooValue'); // WHERE units = 'fooValue' + * $query->filterByUnits('%fooValue%', Criteria::LIKE); // WHERE units LIKE '%fooValue%' + * + * + * @param string $units The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByUnits($units = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($units)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_UNITS, $units, $comparison); + } + + /** + * Filter the query on the threshold column + * + * Example usage: + * + * $query->filterByThreshold(1234); // WHERE threshold = 1234 + * $query->filterByThreshold(array(12, 34)); // WHERE threshold IN (12, 34) + * $query->filterByThreshold(array('min' => 12)); // WHERE threshold > 12 + * + * + * @param mixed $threshold The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByThreshold($threshold = null, $comparison = null) + { + if (is_array($threshold)) { + $useMinMax = false; + if (isset($threshold['min'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_THRESHOLD, $threshold['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($threshold['max'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_THRESHOLD, $threshold['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_THRESHOLD, $threshold, $comparison); + } + + /** + * Filter the query on the operator column + * + * Example usage: + * + * $query->filterByOperator('fooValue'); // WHERE operator = 'fooValue' + * $query->filterByOperator('%fooValue%', Criteria::LIKE); // WHERE operator LIKE '%fooValue%' + * + * + * @param string $operator The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByOperator($operator = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($operator)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_OPERATOR, $operator, $comparison); + } + + /** + * Filter the query on the category_id column + * + * Example usage: + * + * $query->filterByCategoryId(1234); // WHERE category_id = 1234 + * $query->filterByCategoryId(array(12, 34)); // WHERE category_id IN (12, 34) + * $query->filterByCategoryId(array('min' => 12)); // WHERE category_id > 12 + * + * + * @see filterByCategory() + * + * @param mixed $categoryId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByCategoryId($categoryId = null, $comparison = null) + { + if (is_array($categoryId)) { + $useMinMax = false; + if (isset($categoryId['min'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $categoryId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($categoryId['max'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $categoryId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $categoryId, $comparison); + } + + /** + * Filter the query on the rank_id column + * + * Example usage: + * + * $query->filterByRankId(1234); // WHERE rank_id = 1234 + * $query->filterByRankId(array(12, 34)); // WHERE rank_id IN (12, 34) + * $query->filterByRankId(array('min' => 12)); // WHERE rank_id > 12 + * + * + * @see filterByRank() + * + * @param mixed $rankId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByRankId($rankId = null, $comparison = null) + { + if (is_array($rankId)) { + $useMinMax = false; + if (isset($rankId['min'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_RANK_ID, $rankId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($rankId['max'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_RANK_ID, $rankId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_RANK_ID, $rankId, $comparison); + } + + /** + * Filter the query on the nutrient_id column + * + * Example usage: + * + * $query->filterByNutrientId(1234); // WHERE nutrient_id = 1234 + * $query->filterByNutrientId(array(12, 34)); // WHERE nutrient_id IN (12, 34) + * $query->filterByNutrientId(array('min' => 12)); // WHERE nutrient_id > 12 + * + * + * @see filterByNutrient() + * + * @param mixed $nutrientId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByNutrientId($nutrientId = null, $comparison = null) + { + if (is_array($nutrientId)) { + $useMinMax = false; + if (isset($nutrientId['min'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $nutrientId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($nutrientId['max'])) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $nutrientId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $nutrientId, $comparison); + } + + /** + * Filter the query by a related \Nutrient object + * + * @param \Nutrient|ObjectCollection $nutrient The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByNutrient($nutrient, $comparison = null) + { + if ($nutrient instanceof \Nutrient) { + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $nutrient->getId(), $comparison); + } elseif ($nutrient instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_NUTRIENT_ID, $nutrient->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByNutrient() only accepts arguments of type \Nutrient or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Nutrient relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function joinNutrient($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Nutrient'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Nutrient'); + } + + return $this; + } + + /** + * Use the Nutrient relation Nutrient object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \NutrientQuery A secondary query class using the current class as primary query + */ + public function useNutrientQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinNutrient($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Nutrient', '\NutrientQuery'); + } + + /** + * Filter the query by a related \Category object + * + * @param \Category|ObjectCollection $category The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByCategory($category, $comparison = null) + { + if ($category instanceof \Category) { + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $category->getId(), $comparison); + } elseif ($category instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_CATEGORY_ID, $category->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByCategory() only accepts arguments of type \Category or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Category relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function joinCategory($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Category'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Category'); + } + + return $this; + } + + /** + * Use the Category relation Category object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryQuery A secondary query class using the current class as primary query + */ + public function useCategoryQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinCategory($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Category', '\CategoryQuery'); + } + + /** + * Filter the query by a related \Rank object + * + * @param \Rank|ObjectCollection $rank The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function filterByRank($rank, $comparison = null) + { + if ($rank instanceof \Rank) { + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_RANK_ID, $rank->getId(), $comparison); + } elseif ($rank instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(CategoryRankNutrientTableMap::COL_RANK_ID, $rank->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByRank() only accepts arguments of type \Rank or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Rank relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function joinRank($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Rank'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Rank'); + } + + return $this; + } + + /** + * Use the Rank relation Rank object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \RankQuery A secondary query class using the current class as primary query + */ + public function useRankQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinRank($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Rank', '\RankQuery'); + } + + /** + * Exclude object from result + * + * @param ChildCategoryRankNutrient $categoryRankNutrient Object to remove from the list of results + * + * @return $this|ChildCategoryRankNutrientQuery The current query, for fluid interface + */ + public function prune($categoryRankNutrient = null) + { + if ($categoryRankNutrient) { + $this->addUsingAlias(CategoryRankNutrientTableMap::COL_ID, $categoryRankNutrient->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Category_Rank_Nutrient table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + CategoryRankNutrientTableMap::clearInstancePool(); + CategoryRankNutrientTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(CategoryRankNutrientTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + CategoryRankNutrientTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + CategoryRankNutrientTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // CategoryRankNutrientQuery diff --git a/api/generated-classes/Base/Food.php b/api/generated-classes/Base/Food.php new file mode 100644 index 0000000..38bb5bc --- /dev/null +++ b/api/generated-classes/Base/Food.php @@ -0,0 +1,1530 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another Food instance. If + * obj is an instance of Food, delegates to + * equals(Food). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|Food The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [name] column value. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get the [barcode] column value. + * + * @return int + */ + public function getBarcode() + { + return $this->barcode; + } + + /** + * Get the [rank_id] column value. + * + * @return int + */ + public function getRankId() + { + return $this->rank_id; + } + + /** + * Get the [category_id] column value. + * + * @return int + */ + public function getCategoryId() + { + return $this->category_id; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\Food The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[FoodTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [name] column. + * + * @param string $v new value + * @return $this|\Food The current object (for fluent API support) + */ + public function setName($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[FoodTableMap::COL_NAME] = true; + } + + return $this; + } // setName() + + /** + * Set the value of [barcode] column. + * + * @param int $v new value + * @return $this|\Food The current object (for fluent API support) + */ + public function setBarcode($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->barcode !== $v) { + $this->barcode = $v; + $this->modifiedColumns[FoodTableMap::COL_BARCODE] = true; + } + + return $this; + } // setBarcode() + + /** + * Set the value of [rank_id] column. + * + * @param int $v new value + * @return $this|\Food The current object (for fluent API support) + */ + public function setRankId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->rank_id !== $v) { + $this->rank_id = $v; + $this->modifiedColumns[FoodTableMap::COL_RANK_ID] = true; + } + + if ($this->aRank !== null && $this->aRank->getId() !== $v) { + $this->aRank = null; + } + + return $this; + } // setRankId() + + /** + * Set the value of [category_id] column. + * + * @param int $v new value + * @return $this|\Food The current object (for fluent API support) + */ + public function setCategoryId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->category_id !== $v) { + $this->category_id = $v; + $this->modifiedColumns[FoodTableMap::COL_CATEGORY_ID] = true; + } + + if ($this->aCategory !== null && $this->aCategory->getId() !== $v) { + $this->aCategory = null; + } + + return $this; + } // setCategoryId() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : FoodTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : FoodTableMap::translateFieldName('Name', TableMap::TYPE_PHPNAME, $indexType)]; + $this->name = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : FoodTableMap::translateFieldName('Barcode', TableMap::TYPE_PHPNAME, $indexType)]; + $this->barcode = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : FoodTableMap::translateFieldName('RankId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->rank_id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : FoodTableMap::translateFieldName('CategoryId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->category_id = (null !== $col) ? (int) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 5; // 5 = FoodTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\Food'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + if ($this->aRank !== null && $this->rank_id !== $this->aRank->getId()) { + $this->aRank = null; + } + if ($this->aCategory !== null && $this->category_id !== $this->aCategory->getId()) { + $this->aCategory = null; + } + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(FoodTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildFoodQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->aCategory = null; + $this->aRank = null; + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see Food::setDeleted() + * @see Food::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildFoodQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + FoodTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + // We call the save method on the following object(s) if they + // were passed to this object by their corresponding set + // method. This object relates to these object(s) by a + // foreign key reference. + + if ($this->aCategory !== null) { + if ($this->aCategory->isModified() || $this->aCategory->isNew()) { + $affectedRows += $this->aCategory->save($con); + } + $this->setCategory($this->aCategory); + } + + if ($this->aRank !== null) { + if ($this->aRank->isModified() || $this->aRank->isNew()) { + $affectedRows += $this->aRank->save($con); + } + $this->setRank($this->aRank); + } + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[FoodTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . FoodTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(FoodTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(FoodTableMap::COL_NAME)) { + $modifiedColumns[':p' . $index++] = 'name'; + } + if ($this->isColumnModified(FoodTableMap::COL_BARCODE)) { + $modifiedColumns[':p' . $index++] = 'barcode'; + } + if ($this->isColumnModified(FoodTableMap::COL_RANK_ID)) { + $modifiedColumns[':p' . $index++] = 'rank_id'; + } + if ($this->isColumnModified(FoodTableMap::COL_CATEGORY_ID)) { + $modifiedColumns[':p' . $index++] = 'category_id'; + } + + $sql = sprintf( + 'INSERT INTO Food (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'name': + $stmt->bindValue($identifier, $this->name, PDO::PARAM_STR); + break; + case 'barcode': + $stmt->bindValue($identifier, $this->barcode, PDO::PARAM_INT); + break; + case 'rank_id': + $stmt->bindValue($identifier, $this->rank_id, PDO::PARAM_INT); + break; + case 'category_id': + $stmt->bindValue($identifier, $this->category_id, PDO::PARAM_INT); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = FoodTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + case 2: + return $this->getBarcode(); + break; + case 3: + return $this->getRankId(); + break; + case 4: + return $this->getCategoryId(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['Food'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['Food'][$this->hashCode()] = true; + $keys = FoodTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + $keys[2] => $this->getBarcode(), + $keys[3] => $this->getRankId(), + $keys[4] => $this->getCategoryId(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->aCategory) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'category'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category'; + break; + default: + $key = 'Category'; + } + + $result[$key] = $this->aCategory->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + if (null !== $this->aRank) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'rank'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Rank'; + break; + default: + $key = 'Rank'; + } + + $result[$key] = $this->aRank->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\Food + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = FoodTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\Food + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + case 2: + $this->setBarcode($value); + break; + case 3: + $this->setRankId($value); + break; + case 4: + $this->setCategoryId($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = FoodTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setName($arr[$keys[1]]); + } + if (array_key_exists($keys[2], $arr)) { + $this->setBarcode($arr[$keys[2]]); + } + if (array_key_exists($keys[3], $arr)) { + $this->setRankId($arr[$keys[3]]); + } + if (array_key_exists($keys[4], $arr)) { + $this->setCategoryId($arr[$keys[4]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\Food The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(FoodTableMap::DATABASE_NAME); + + if ($this->isColumnModified(FoodTableMap::COL_ID)) { + $criteria->add(FoodTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(FoodTableMap::COL_NAME)) { + $criteria->add(FoodTableMap::COL_NAME, $this->name); + } + if ($this->isColumnModified(FoodTableMap::COL_BARCODE)) { + $criteria->add(FoodTableMap::COL_BARCODE, $this->barcode); + } + if ($this->isColumnModified(FoodTableMap::COL_RANK_ID)) { + $criteria->add(FoodTableMap::COL_RANK_ID, $this->rank_id); + } + if ($this->isColumnModified(FoodTableMap::COL_CATEGORY_ID)) { + $criteria->add(FoodTableMap::COL_CATEGORY_ID, $this->category_id); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildFoodQuery::create(); + $criteria->add(FoodTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Food (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setName($this->getName()); + $copyObj->setBarcode($this->getBarcode()); + $copyObj->setRankId($this->getRankId()); + $copyObj->setCategoryId($this->getCategoryId()); + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Food Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + /** + * Declares an association between this object and a ChildCategory object. + * + * @param ChildCategory $v + * @return $this|\Food The current object (for fluent API support) + * @throws PropelException + */ + public function setCategory(ChildCategory $v = null) + { + if ($v === null) { + $this->setCategoryId(NULL); + } else { + $this->setCategoryId($v->getId()); + } + + $this->aCategory = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildCategory object, it will not be re-added. + if ($v !== null) { + $v->addFood($this); + } + + + return $this; + } + + + /** + * Get the associated ChildCategory object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildCategory The associated ChildCategory object. + * @throws PropelException + */ + public function getCategory(ConnectionInterface $con = null) + { + if ($this->aCategory === null && ($this->category_id !== null)) { + $this->aCategory = ChildCategoryQuery::create()->findPk($this->category_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aCategory->addFoods($this); + */ + } + + return $this->aCategory; + } + + /** + * Declares an association between this object and a ChildRank object. + * + * @param ChildRank $v + * @return $this|\Food The current object (for fluent API support) + * @throws PropelException + */ + public function setRank(ChildRank $v = null) + { + if ($v === null) { + $this->setRankId(NULL); + } else { + $this->setRankId($v->getId()); + } + + $this->aRank = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildRank object, it will not be re-added. + if ($v !== null) { + $v->addFood($this); + } + + + return $this; + } + + + /** + * Get the associated ChildRank object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildRank The associated ChildRank object. + * @throws PropelException + */ + public function getRank(ConnectionInterface $con = null) + { + if ($this->aRank === null && ($this->rank_id !== null)) { + $this->aRank = ChildRankQuery::create()->findPk($this->rank_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aRank->addFoods($this); + */ + } + + return $this->aRank; + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + if (null !== $this->aCategory) { + $this->aCategory->removeFood($this); + } + if (null !== $this->aRank) { + $this->aRank->removeFood($this); + } + $this->id = null; + $this->name = null; + $this->barcode = null; + $this->rank_id = null; + $this->category_id = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + } // if ($deep) + + $this->aCategory = null; + $this->aRank = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(FoodTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/FoodQuery.php b/api/generated-classes/Base/FoodQuery.php new file mode 100644 index 0000000..19211a4 --- /dev/null +++ b/api/generated-classes/Base/FoodQuery.php @@ -0,0 +1,701 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildFood|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(FoodTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = FoodTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildFood A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, name, barcode, rank_id, category_id FROM Food WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildFood $obj */ + $obj = new ChildFood(); + $obj->hydrate($row); + FoodTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildFood|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(FoodTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(FoodTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(FoodTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(FoodTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(FoodTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the name column + * + * Example usage: + * + * $query->filterByName('fooValue'); // WHERE name = 'fooValue' + * $query->filterByName('%fooValue%', Criteria::LIKE); // WHERE name LIKE '%fooValue%' + * + * + * @param string $name The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByName($name = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($name)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(FoodTableMap::COL_NAME, $name, $comparison); + } + + /** + * Filter the query on the barcode column + * + * Example usage: + * + * $query->filterByBarcode(1234); // WHERE barcode = 1234 + * $query->filterByBarcode(array(12, 34)); // WHERE barcode IN (12, 34) + * $query->filterByBarcode(array('min' => 12)); // WHERE barcode > 12 + * + * + * @param mixed $barcode The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByBarcode($barcode = null, $comparison = null) + { + if (is_array($barcode)) { + $useMinMax = false; + if (isset($barcode['min'])) { + $this->addUsingAlias(FoodTableMap::COL_BARCODE, $barcode['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($barcode['max'])) { + $this->addUsingAlias(FoodTableMap::COL_BARCODE, $barcode['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(FoodTableMap::COL_BARCODE, $barcode, $comparison); + } + + /** + * Filter the query on the rank_id column + * + * Example usage: + * + * $query->filterByRankId(1234); // WHERE rank_id = 1234 + * $query->filterByRankId(array(12, 34)); // WHERE rank_id IN (12, 34) + * $query->filterByRankId(array('min' => 12)); // WHERE rank_id > 12 + * + * + * @see filterByRank() + * + * @param mixed $rankId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByRankId($rankId = null, $comparison = null) + { + if (is_array($rankId)) { + $useMinMax = false; + if (isset($rankId['min'])) { + $this->addUsingAlias(FoodTableMap::COL_RANK_ID, $rankId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($rankId['max'])) { + $this->addUsingAlias(FoodTableMap::COL_RANK_ID, $rankId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(FoodTableMap::COL_RANK_ID, $rankId, $comparison); + } + + /** + * Filter the query on the category_id column + * + * Example usage: + * + * $query->filterByCategoryId(1234); // WHERE category_id = 1234 + * $query->filterByCategoryId(array(12, 34)); // WHERE category_id IN (12, 34) + * $query->filterByCategoryId(array('min' => 12)); // WHERE category_id > 12 + * + * + * @see filterByCategory() + * + * @param mixed $categoryId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function filterByCategoryId($categoryId = null, $comparison = null) + { + if (is_array($categoryId)) { + $useMinMax = false; + if (isset($categoryId['min'])) { + $this->addUsingAlias(FoodTableMap::COL_CATEGORY_ID, $categoryId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($categoryId['max'])) { + $this->addUsingAlias(FoodTableMap::COL_CATEGORY_ID, $categoryId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(FoodTableMap::COL_CATEGORY_ID, $categoryId, $comparison); + } + + /** + * Filter the query by a related \Category object + * + * @param \Category|ObjectCollection $category The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildFoodQuery The current query, for fluid interface + */ + public function filterByCategory($category, $comparison = null) + { + if ($category instanceof \Category) { + return $this + ->addUsingAlias(FoodTableMap::COL_CATEGORY_ID, $category->getId(), $comparison); + } elseif ($category instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(FoodTableMap::COL_CATEGORY_ID, $category->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByCategory() only accepts arguments of type \Category or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Category relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function joinCategory($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Category'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Category'); + } + + return $this; + } + + /** + * Use the Category relation Category object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryQuery A secondary query class using the current class as primary query + */ + public function useCategoryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinCategory($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Category', '\CategoryQuery'); + } + + /** + * Filter the query by a related \Rank object + * + * @param \Rank|ObjectCollection $rank The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildFoodQuery The current query, for fluid interface + */ + public function filterByRank($rank, $comparison = null) + { + if ($rank instanceof \Rank) { + return $this + ->addUsingAlias(FoodTableMap::COL_RANK_ID, $rank->getId(), $comparison); + } elseif ($rank instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(FoodTableMap::COL_RANK_ID, $rank->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByRank() only accepts arguments of type \Rank or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Rank relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function joinRank($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Rank'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Rank'); + } + + return $this; + } + + /** + * Use the Rank relation Rank object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \RankQuery A secondary query class using the current class as primary query + */ + public function useRankQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinRank($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Rank', '\RankQuery'); + } + + /** + * Exclude object from result + * + * @param ChildFood $food Object to remove from the list of results + * + * @return $this|ChildFoodQuery The current query, for fluid interface + */ + public function prune($food = null) + { + if ($food) { + $this->addUsingAlias(FoodTableMap::COL_ID, $food->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Food table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + FoodTableMap::clearInstancePool(); + FoodTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(FoodTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + FoodTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + FoodTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // FoodQuery diff --git a/api/generated-classes/Base/Nutrient.php b/api/generated-classes/Base/Nutrient.php new file mode 100644 index 0000000..581a3c1 --- /dev/null +++ b/api/generated-classes/Base/Nutrient.php @@ -0,0 +1,1520 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another Nutrient instance. If + * obj is an instance of Nutrient, delegates to + * equals(Nutrient). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|Nutrient The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [name] column value. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\Nutrient The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[NutrientTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [name] column. + * + * @param string $v new value + * @return $this|\Nutrient The current object (for fluent API support) + */ + public function setName($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[NutrientTableMap::COL_NAME] = true; + } + + return $this; + } // setName() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : NutrientTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : NutrientTableMap::translateFieldName('Name', TableMap::TYPE_PHPNAME, $indexType)]; + $this->name = (null !== $col) ? (string) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 2; // 2 = NutrientTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\Nutrient'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(NutrientTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildNutrientQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->collCategoryRankNutrients = null; + + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see Nutrient::setDeleted() + * @see Nutrient::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildNutrientQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + NutrientTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + if ($this->categoryRankNutrientsScheduledForDeletion !== null) { + if (!$this->categoryRankNutrientsScheduledForDeletion->isEmpty()) { + \CategoryRankNutrientQuery::create() + ->filterByPrimaryKeys($this->categoryRankNutrientsScheduledForDeletion->getPrimaryKeys(false)) + ->delete($con); + $this->categoryRankNutrientsScheduledForDeletion = null; + } + } + + if ($this->collCategoryRankNutrients !== null) { + foreach ($this->collCategoryRankNutrients as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[NutrientTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . NutrientTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(NutrientTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(NutrientTableMap::COL_NAME)) { + $modifiedColumns[':p' . $index++] = 'name'; + } + + $sql = sprintf( + 'INSERT INTO Nutrient (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'name': + $stmt->bindValue($identifier, $this->name, PDO::PARAM_STR); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = NutrientTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['Nutrient'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['Nutrient'][$this->hashCode()] = true; + $keys = NutrientTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->collCategoryRankNutrients) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'categoryRankNutrients'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category_Rank_Nutrients'; + break; + default: + $key = 'CategoryRankNutrients'; + } + + $result[$key] = $this->collCategoryRankNutrients->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\Nutrient + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = NutrientTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\Nutrient + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = NutrientTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setName($arr[$keys[1]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\Nutrient The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(NutrientTableMap::DATABASE_NAME); + + if ($this->isColumnModified(NutrientTableMap::COL_ID)) { + $criteria->add(NutrientTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(NutrientTableMap::COL_NAME)) { + $criteria->add(NutrientTableMap::COL_NAME, $this->name); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildNutrientQuery::create(); + $criteria->add(NutrientTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Nutrient (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setName($this->getName()); + + if ($deepCopy) { + // important: temporarily setNew(false) because this affects the behavior of + // the getter/setter methods for fkey referrer objects. + $copyObj->setNew(false); + + foreach ($this->getCategoryRankNutrients() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addCategoryRankNutrient($relObj->copy($deepCopy)); + } + } + + } // if ($deepCopy) + + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Nutrient Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + + /** + * Initializes a collection based on the name of a relation. + * Avoids crafting an 'init[$relationName]s' method name + * that wouldn't work when StandardEnglishPluralizer is used. + * + * @param string $relationName The name of the relation to initialize + * @return void + */ + public function initRelation($relationName) + { + if ('CategoryRankNutrient' == $relationName) { + return $this->initCategoryRankNutrients(); + } + } + + /** + * Clears out the collCategoryRankNutrients collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addCategoryRankNutrients() + */ + public function clearCategoryRankNutrients() + { + $this->collCategoryRankNutrients = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collCategoryRankNutrients collection loaded partially. + */ + public function resetPartialCategoryRankNutrients($v = true) + { + $this->collCategoryRankNutrientsPartial = $v; + } + + /** + * Initializes the collCategoryRankNutrients collection. + * + * By default this just sets the collCategoryRankNutrients collection to an empty array (like clearcollCategoryRankNutrients()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initCategoryRankNutrients($overrideExisting = true) + { + if (null !== $this->collCategoryRankNutrients && !$overrideExisting) { + return; + } + + $collectionClassName = CategoryRankNutrientTableMap::getTableMap()->getCollectionClassName(); + + $this->collCategoryRankNutrients = new $collectionClassName; + $this->collCategoryRankNutrients->setModel('\CategoryRankNutrient'); + } + + /** + * Gets an array of ChildCategoryRankNutrient objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildNutrient is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + * @throws PropelException + */ + public function getCategoryRankNutrients(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + // return empty collection + $this->initCategoryRankNutrients(); + } else { + $collCategoryRankNutrients = ChildCategoryRankNutrientQuery::create(null, $criteria) + ->filterByNutrient($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collCategoryRankNutrientsPartial && count($collCategoryRankNutrients)) { + $this->initCategoryRankNutrients(false); + + foreach ($collCategoryRankNutrients as $obj) { + if (false == $this->collCategoryRankNutrients->contains($obj)) { + $this->collCategoryRankNutrients->append($obj); + } + } + + $this->collCategoryRankNutrientsPartial = true; + } + + return $collCategoryRankNutrients; + } + + if ($partial && $this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $obj) { + if ($obj->isNew()) { + $collCategoryRankNutrients[] = $obj; + } + } + } + + $this->collCategoryRankNutrients = $collCategoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + } + } + + return $this->collCategoryRankNutrients; + } + + /** + * Sets a collection of ChildCategoryRankNutrient objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $categoryRankNutrients A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildNutrient The current object (for fluent API support) + */ + public function setCategoryRankNutrients(Collection $categoryRankNutrients, ConnectionInterface $con = null) + { + /** @var ChildCategoryRankNutrient[] $categoryRankNutrientsToDelete */ + $categoryRankNutrientsToDelete = $this->getCategoryRankNutrients(new Criteria(), $con)->diff($categoryRankNutrients); + + + $this->categoryRankNutrientsScheduledForDeletion = $categoryRankNutrientsToDelete; + + foreach ($categoryRankNutrientsToDelete as $categoryRankNutrientRemoved) { + $categoryRankNutrientRemoved->setNutrient(null); + } + + $this->collCategoryRankNutrients = null; + foreach ($categoryRankNutrients as $categoryRankNutrient) { + $this->addCategoryRankNutrient($categoryRankNutrient); + } + + $this->collCategoryRankNutrients = $categoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + + return $this; + } + + /** + * Returns the number of related CategoryRankNutrient objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related CategoryRankNutrient objects. + * @throws PropelException + */ + public function countCategoryRankNutrients(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getCategoryRankNutrients()); + } + + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByNutrient($this) + ->count($con); + } + + return count($this->collCategoryRankNutrients); + } + + /** + * Method called to associate a ChildCategoryRankNutrient object to this object + * through the ChildCategoryRankNutrient foreign key attribute. + * + * @param ChildCategoryRankNutrient $l ChildCategoryRankNutrient + * @return $this|\Nutrient The current object (for fluent API support) + */ + public function addCategoryRankNutrient(ChildCategoryRankNutrient $l) + { + if ($this->collCategoryRankNutrients === null) { + $this->initCategoryRankNutrients(); + $this->collCategoryRankNutrientsPartial = true; + } + + if (!$this->collCategoryRankNutrients->contains($l)) { + $this->doAddCategoryRankNutrient($l); + + if ($this->categoryRankNutrientsScheduledForDeletion and $this->categoryRankNutrientsScheduledForDeletion->contains($l)) { + $this->categoryRankNutrientsScheduledForDeletion->remove($this->categoryRankNutrientsScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to add. + */ + protected function doAddCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + $this->collCategoryRankNutrients[]= $categoryRankNutrient; + $categoryRankNutrient->setNutrient($this); + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to remove. + * @return $this|ChildNutrient The current object (for fluent API support) + */ + public function removeCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + if ($this->getCategoryRankNutrients()->contains($categoryRankNutrient)) { + $pos = $this->collCategoryRankNutrients->search($categoryRankNutrient); + $this->collCategoryRankNutrients->remove($pos); + if (null === $this->categoryRankNutrientsScheduledForDeletion) { + $this->categoryRankNutrientsScheduledForDeletion = clone $this->collCategoryRankNutrients; + $this->categoryRankNutrientsScheduledForDeletion->clear(); + } + $this->categoryRankNutrientsScheduledForDeletion[]= clone $categoryRankNutrient; + $categoryRankNutrient->setNutrient(null); + } + + return $this; + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Nutrient is new, it will return + * an empty collection; or if this Nutrient has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Nutrient. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinCategory(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Category', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Nutrient is new, it will return + * an empty collection; or if this Nutrient has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Nutrient. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinRank(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Rank', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + $this->id = null; + $this->name = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + if ($this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $o) { + $o->clearAllReferences($deep); + } + } + } // if ($deep) + + $this->collCategoryRankNutrients = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(NutrientTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/NutrientQuery.php b/api/generated-classes/Base/NutrientQuery.php new file mode 100644 index 0000000..a5b8c1e --- /dev/null +++ b/api/generated-classes/Base/NutrientQuery.php @@ -0,0 +1,468 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildNutrient|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(NutrientTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = NutrientTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildNutrient A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, name FROM Nutrient WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildNutrient $obj */ + $obj = new ChildNutrient(); + $obj->hydrate($row); + NutrientTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildNutrient|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(NutrientTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(NutrientTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(NutrientTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(NutrientTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(NutrientTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the name column + * + * Example usage: + * + * $query->filterByName('fooValue'); // WHERE name = 'fooValue' + * $query->filterByName('%fooValue%', Criteria::LIKE); // WHERE name LIKE '%fooValue%' + * + * + * @param string $name The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function filterByName($name = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($name)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(NutrientTableMap::COL_NAME, $name, $comparison); + } + + /** + * Filter the query by a related \CategoryRankNutrient object + * + * @param \CategoryRankNutrient|ObjectCollection $categoryRankNutrient the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildNutrientQuery The current query, for fluid interface + */ + public function filterByCategoryRankNutrient($categoryRankNutrient, $comparison = null) + { + if ($categoryRankNutrient instanceof \CategoryRankNutrient) { + return $this + ->addUsingAlias(NutrientTableMap::COL_ID, $categoryRankNutrient->getNutrientId(), $comparison); + } elseif ($categoryRankNutrient instanceof ObjectCollection) { + return $this + ->useCategoryRankNutrientQuery() + ->filterByPrimaryKeys($categoryRankNutrient->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByCategoryRankNutrient() only accepts arguments of type \CategoryRankNutrient or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the CategoryRankNutrient relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function joinCategoryRankNutrient($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('CategoryRankNutrient'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'CategoryRankNutrient'); + } + + return $this; + } + + /** + * Use the CategoryRankNutrient relation CategoryRankNutrient object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryRankNutrientQuery A secondary query class using the current class as primary query + */ + public function useCategoryRankNutrientQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinCategoryRankNutrient($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'CategoryRankNutrient', '\CategoryRankNutrientQuery'); + } + + /** + * Exclude object from result + * + * @param ChildNutrient $nutrient Object to remove from the list of results + * + * @return $this|ChildNutrientQuery The current query, for fluid interface + */ + public function prune($nutrient = null) + { + if ($nutrient) { + $this->addUsingAlias(NutrientTableMap::COL_ID, $nutrient->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Nutrient table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + NutrientTableMap::clearInstancePool(); + NutrientTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(NutrientTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + NutrientTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + NutrientTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // NutrientQuery diff --git a/api/generated-classes/Base/Rank.php b/api/generated-classes/Base/Rank.php new file mode 100644 index 0000000..164de22 --- /dev/null +++ b/api/generated-classes/Base/Rank.php @@ -0,0 +1,1835 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another Rank instance. If + * obj is an instance of Rank, delegates to + * equals(Rank). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|Rank The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [name] column value. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\Rank The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[RankTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [name] column. + * + * @param string $v new value + * @return $this|\Rank The current object (for fluent API support) + */ + public function setName($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[RankTableMap::COL_NAME] = true; + } + + return $this; + } // setName() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : RankTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : RankTableMap::translateFieldName('Name', TableMap::TYPE_PHPNAME, $indexType)]; + $this->name = (null !== $col) ? (string) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 2; // 2 = RankTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\Rank'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(RankTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildRankQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->collCategoryRankNutrients = null; + + $this->collFoods = null; + + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see Rank::setDeleted() + * @see Rank::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildRankQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + RankTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + if ($this->categoryRankNutrientsScheduledForDeletion !== null) { + if (!$this->categoryRankNutrientsScheduledForDeletion->isEmpty()) { + \CategoryRankNutrientQuery::create() + ->filterByPrimaryKeys($this->categoryRankNutrientsScheduledForDeletion->getPrimaryKeys(false)) + ->delete($con); + $this->categoryRankNutrientsScheduledForDeletion = null; + } + } + + if ($this->collCategoryRankNutrients !== null) { + foreach ($this->collCategoryRankNutrients as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->foodsScheduledForDeletion !== null) { + if (!$this->foodsScheduledForDeletion->isEmpty()) { + foreach ($this->foodsScheduledForDeletion as $food) { + // need to save related object because we set the relation to null + $food->save($con); + } + $this->foodsScheduledForDeletion = null; + } + } + + if ($this->collFoods !== null) { + foreach ($this->collFoods as $referrerFK) { + if (!$referrerFK->isDeleted() && ($referrerFK->isNew() || $referrerFK->isModified())) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[RankTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . RankTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(RankTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(RankTableMap::COL_NAME)) { + $modifiedColumns[':p' . $index++] = 'name'; + } + + $sql = sprintf( + 'INSERT INTO Rank (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'name': + $stmt->bindValue($identifier, $this->name, PDO::PARAM_STR); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = RankTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['Rank'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['Rank'][$this->hashCode()] = true; + $keys = RankTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->collCategoryRankNutrients) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'categoryRankNutrients'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category_Rank_Nutrients'; + break; + default: + $key = 'CategoryRankNutrients'; + } + + $result[$key] = $this->collCategoryRankNutrients->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + if (null !== $this->collFoods) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'foods'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Foods'; + break; + default: + $key = 'Foods'; + } + + $result[$key] = $this->collFoods->toArray(null, false, $keyType, $includeLazyLoadColumns, $alreadyDumpedObjects); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\Rank + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = RankTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\Rank + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = RankTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setName($arr[$keys[1]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\Rank The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(RankTableMap::DATABASE_NAME); + + if ($this->isColumnModified(RankTableMap::COL_ID)) { + $criteria->add(RankTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(RankTableMap::COL_NAME)) { + $criteria->add(RankTableMap::COL_NAME, $this->name); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildRankQuery::create(); + $criteria->add(RankTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Rank (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setName($this->getName()); + + if ($deepCopy) { + // important: temporarily setNew(false) because this affects the behavior of + // the getter/setter methods for fkey referrer objects. + $copyObj->setNew(false); + + foreach ($this->getCategoryRankNutrients() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addCategoryRankNutrient($relObj->copy($deepCopy)); + } + } + + foreach ($this->getFoods() as $relObj) { + if ($relObj !== $this) { // ensure that we don't try to copy a reference to ourselves + $copyObj->addFood($relObj->copy($deepCopy)); + } + } + + } // if ($deepCopy) + + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Rank Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + + /** + * Initializes a collection based on the name of a relation. + * Avoids crafting an 'init[$relationName]s' method name + * that wouldn't work when StandardEnglishPluralizer is used. + * + * @param string $relationName The name of the relation to initialize + * @return void + */ + public function initRelation($relationName) + { + if ('CategoryRankNutrient' == $relationName) { + return $this->initCategoryRankNutrients(); + } + if ('Food' == $relationName) { + return $this->initFoods(); + } + } + + /** + * Clears out the collCategoryRankNutrients collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addCategoryRankNutrients() + */ + public function clearCategoryRankNutrients() + { + $this->collCategoryRankNutrients = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collCategoryRankNutrients collection loaded partially. + */ + public function resetPartialCategoryRankNutrients($v = true) + { + $this->collCategoryRankNutrientsPartial = $v; + } + + /** + * Initializes the collCategoryRankNutrients collection. + * + * By default this just sets the collCategoryRankNutrients collection to an empty array (like clearcollCategoryRankNutrients()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initCategoryRankNutrients($overrideExisting = true) + { + if (null !== $this->collCategoryRankNutrients && !$overrideExisting) { + return; + } + + $collectionClassName = CategoryRankNutrientTableMap::getTableMap()->getCollectionClassName(); + + $this->collCategoryRankNutrients = new $collectionClassName; + $this->collCategoryRankNutrients->setModel('\CategoryRankNutrient'); + } + + /** + * Gets an array of ChildCategoryRankNutrient objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildRank is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + * @throws PropelException + */ + public function getCategoryRankNutrients(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + // return empty collection + $this->initCategoryRankNutrients(); + } else { + $collCategoryRankNutrients = ChildCategoryRankNutrientQuery::create(null, $criteria) + ->filterByRank($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collCategoryRankNutrientsPartial && count($collCategoryRankNutrients)) { + $this->initCategoryRankNutrients(false); + + foreach ($collCategoryRankNutrients as $obj) { + if (false == $this->collCategoryRankNutrients->contains($obj)) { + $this->collCategoryRankNutrients->append($obj); + } + } + + $this->collCategoryRankNutrientsPartial = true; + } + + return $collCategoryRankNutrients; + } + + if ($partial && $this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $obj) { + if ($obj->isNew()) { + $collCategoryRankNutrients[] = $obj; + } + } + } + + $this->collCategoryRankNutrients = $collCategoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + } + } + + return $this->collCategoryRankNutrients; + } + + /** + * Sets a collection of ChildCategoryRankNutrient objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $categoryRankNutrients A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildRank The current object (for fluent API support) + */ + public function setCategoryRankNutrients(Collection $categoryRankNutrients, ConnectionInterface $con = null) + { + /** @var ChildCategoryRankNutrient[] $categoryRankNutrientsToDelete */ + $categoryRankNutrientsToDelete = $this->getCategoryRankNutrients(new Criteria(), $con)->diff($categoryRankNutrients); + + + $this->categoryRankNutrientsScheduledForDeletion = $categoryRankNutrientsToDelete; + + foreach ($categoryRankNutrientsToDelete as $categoryRankNutrientRemoved) { + $categoryRankNutrientRemoved->setRank(null); + } + + $this->collCategoryRankNutrients = null; + foreach ($categoryRankNutrients as $categoryRankNutrient) { + $this->addCategoryRankNutrient($categoryRankNutrient); + } + + $this->collCategoryRankNutrients = $categoryRankNutrients; + $this->collCategoryRankNutrientsPartial = false; + + return $this; + } + + /** + * Returns the number of related CategoryRankNutrient objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related CategoryRankNutrient objects. + * @throws PropelException + */ + public function countCategoryRankNutrients(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collCategoryRankNutrientsPartial && !$this->isNew(); + if (null === $this->collCategoryRankNutrients || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collCategoryRankNutrients) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getCategoryRankNutrients()); + } + + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByRank($this) + ->count($con); + } + + return count($this->collCategoryRankNutrients); + } + + /** + * Method called to associate a ChildCategoryRankNutrient object to this object + * through the ChildCategoryRankNutrient foreign key attribute. + * + * @param ChildCategoryRankNutrient $l ChildCategoryRankNutrient + * @return $this|\Rank The current object (for fluent API support) + */ + public function addCategoryRankNutrient(ChildCategoryRankNutrient $l) + { + if ($this->collCategoryRankNutrients === null) { + $this->initCategoryRankNutrients(); + $this->collCategoryRankNutrientsPartial = true; + } + + if (!$this->collCategoryRankNutrients->contains($l)) { + $this->doAddCategoryRankNutrient($l); + + if ($this->categoryRankNutrientsScheduledForDeletion and $this->categoryRankNutrientsScheduledForDeletion->contains($l)) { + $this->categoryRankNutrientsScheduledForDeletion->remove($this->categoryRankNutrientsScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to add. + */ + protected function doAddCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + $this->collCategoryRankNutrients[]= $categoryRankNutrient; + $categoryRankNutrient->setRank($this); + } + + /** + * @param ChildCategoryRankNutrient $categoryRankNutrient The ChildCategoryRankNutrient object to remove. + * @return $this|ChildRank The current object (for fluent API support) + */ + public function removeCategoryRankNutrient(ChildCategoryRankNutrient $categoryRankNutrient) + { + if ($this->getCategoryRankNutrients()->contains($categoryRankNutrient)) { + $pos = $this->collCategoryRankNutrients->search($categoryRankNutrient); + $this->collCategoryRankNutrients->remove($pos); + if (null === $this->categoryRankNutrientsScheduledForDeletion) { + $this->categoryRankNutrientsScheduledForDeletion = clone $this->collCategoryRankNutrients; + $this->categoryRankNutrientsScheduledForDeletion->clear(); + } + $this->categoryRankNutrientsScheduledForDeletion[]= clone $categoryRankNutrient; + $categoryRankNutrient->setRank(null); + } + + return $this; + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Rank is new, it will return + * an empty collection; or if this Rank has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Rank. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinNutrient(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Nutrient', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Rank is new, it will return + * an empty collection; or if this Rank has previously + * been saved, it will retrieve related CategoryRankNutrients from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Rank. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildCategoryRankNutrient[] List of ChildCategoryRankNutrient objects + */ + public function getCategoryRankNutrientsJoinCategory(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildCategoryRankNutrientQuery::create(null, $criteria); + $query->joinWith('Category', $joinBehavior); + + return $this->getCategoryRankNutrients($query, $con); + } + + /** + * Clears out the collFoods collection + * + * This does not modify the database; however, it will remove any associated objects, causing + * them to be refetched by subsequent calls to accessor method. + * + * @return void + * @see addFoods() + */ + public function clearFoods() + { + $this->collFoods = null; // important to set this to NULL since that means it is uninitialized + } + + /** + * Reset is the collFoods collection loaded partially. + */ + public function resetPartialFoods($v = true) + { + $this->collFoodsPartial = $v; + } + + /** + * Initializes the collFoods collection. + * + * By default this just sets the collFoods collection to an empty array (like clearcollFoods()); + * however, you may wish to override this method in your stub class to provide setting appropriate + * to your application -- for example, setting the initial array to the values stored in database. + * + * @param boolean $overrideExisting If set to true, the method call initializes + * the collection even if it is not empty + * + * @return void + */ + public function initFoods($overrideExisting = true) + { + if (null !== $this->collFoods && !$overrideExisting) { + return; + } + + $collectionClassName = FoodTableMap::getTableMap()->getCollectionClassName(); + + $this->collFoods = new $collectionClassName; + $this->collFoods->setModel('\Food'); + } + + /** + * Gets an array of ChildFood objects which contain a foreign key that references this object. + * + * If the $criteria is not null, it is used to always fetch the results from the database. + * Otherwise the results are fetched from the database the first time, then cached. + * Next time the same method is called without $criteria, the cached collection is returned. + * If this ChildRank is new, it will return + * an empty collection or the current collection; the criteria is ignored on a new object. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @return ObjectCollection|ChildFood[] List of ChildFood objects + * @throws PropelException + */ + public function getFoods(Criteria $criteria = null, ConnectionInterface $con = null) + { + $partial = $this->collFoodsPartial && !$this->isNew(); + if (null === $this->collFoods || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collFoods) { + // return empty collection + $this->initFoods(); + } else { + $collFoods = ChildFoodQuery::create(null, $criteria) + ->filterByRank($this) + ->find($con); + + if (null !== $criteria) { + if (false !== $this->collFoodsPartial && count($collFoods)) { + $this->initFoods(false); + + foreach ($collFoods as $obj) { + if (false == $this->collFoods->contains($obj)) { + $this->collFoods->append($obj); + } + } + + $this->collFoodsPartial = true; + } + + return $collFoods; + } + + if ($partial && $this->collFoods) { + foreach ($this->collFoods as $obj) { + if ($obj->isNew()) { + $collFoods[] = $obj; + } + } + } + + $this->collFoods = $collFoods; + $this->collFoodsPartial = false; + } + } + + return $this->collFoods; + } + + /** + * Sets a collection of ChildFood objects related by a one-to-many relationship + * to the current object. + * It will also schedule objects for deletion based on a diff between old objects (aka persisted) + * and new objects from the given Propel collection. + * + * @param Collection $foods A Propel collection. + * @param ConnectionInterface $con Optional connection object + * @return $this|ChildRank The current object (for fluent API support) + */ + public function setFoods(Collection $foods, ConnectionInterface $con = null) + { + /** @var ChildFood[] $foodsToDelete */ + $foodsToDelete = $this->getFoods(new Criteria(), $con)->diff($foods); + + + $this->foodsScheduledForDeletion = $foodsToDelete; + + foreach ($foodsToDelete as $foodRemoved) { + $foodRemoved->setRank(null); + } + + $this->collFoods = null; + foreach ($foods as $food) { + $this->addFood($food); + } + + $this->collFoods = $foods; + $this->collFoodsPartial = false; + + return $this; + } + + /** + * Returns the number of related Food objects. + * + * @param Criteria $criteria + * @param boolean $distinct + * @param ConnectionInterface $con + * @return int Count of related Food objects. + * @throws PropelException + */ + public function countFoods(Criteria $criteria = null, $distinct = false, ConnectionInterface $con = null) + { + $partial = $this->collFoodsPartial && !$this->isNew(); + if (null === $this->collFoods || null !== $criteria || $partial) { + if ($this->isNew() && null === $this->collFoods) { + return 0; + } + + if ($partial && !$criteria) { + return count($this->getFoods()); + } + + $query = ChildFoodQuery::create(null, $criteria); + if ($distinct) { + $query->distinct(); + } + + return $query + ->filterByRank($this) + ->count($con); + } + + return count($this->collFoods); + } + + /** + * Method called to associate a ChildFood object to this object + * through the ChildFood foreign key attribute. + * + * @param ChildFood $l ChildFood + * @return $this|\Rank The current object (for fluent API support) + */ + public function addFood(ChildFood $l) + { + if ($this->collFoods === null) { + $this->initFoods(); + $this->collFoodsPartial = true; + } + + if (!$this->collFoods->contains($l)) { + $this->doAddFood($l); + + if ($this->foodsScheduledForDeletion and $this->foodsScheduledForDeletion->contains($l)) { + $this->foodsScheduledForDeletion->remove($this->foodsScheduledForDeletion->search($l)); + } + } + + return $this; + } + + /** + * @param ChildFood $food The ChildFood object to add. + */ + protected function doAddFood(ChildFood $food) + { + $this->collFoods[]= $food; + $food->setRank($this); + } + + /** + * @param ChildFood $food The ChildFood object to remove. + * @return $this|ChildRank The current object (for fluent API support) + */ + public function removeFood(ChildFood $food) + { + if ($this->getFoods()->contains($food)) { + $pos = $this->collFoods->search($food); + $this->collFoods->remove($pos); + if (null === $this->foodsScheduledForDeletion) { + $this->foodsScheduledForDeletion = clone $this->collFoods; + $this->foodsScheduledForDeletion->clear(); + } + $this->foodsScheduledForDeletion[]= $food; + $food->setRank(null); + } + + return $this; + } + + + /** + * If this collection has already been initialized with + * an identical criteria, it returns the collection. + * Otherwise if this Rank is new, it will return + * an empty collection; or if this Rank has previously + * been saved, it will retrieve related Foods from storage. + * + * This method is protected by default in order to keep the public + * api reasonable. You can provide public methods for those you + * actually need in Rank. + * + * @param Criteria $criteria optional Criteria object to narrow the query + * @param ConnectionInterface $con optional connection object + * @param string $joinBehavior optional join type to use (defaults to Criteria::LEFT_JOIN) + * @return ObjectCollection|ChildFood[] List of ChildFood objects + */ + public function getFoodsJoinCategory(Criteria $criteria = null, ConnectionInterface $con = null, $joinBehavior = Criteria::LEFT_JOIN) + { + $query = ChildFoodQuery::create(null, $criteria); + $query->joinWith('Category', $joinBehavior); + + return $this->getFoods($query, $con); + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + $this->id = null; + $this->name = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + if ($this->collCategoryRankNutrients) { + foreach ($this->collCategoryRankNutrients as $o) { + $o->clearAllReferences($deep); + } + } + if ($this->collFoods) { + foreach ($this->collFoods as $o) { + $o->clearAllReferences($deep); + } + } + } // if ($deep) + + $this->collCategoryRankNutrients = null; + $this->collFoods = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(RankTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/RankQuery.php b/api/generated-classes/Base/RankQuery.php new file mode 100644 index 0000000..9f3d376 --- /dev/null +++ b/api/generated-classes/Base/RankQuery.php @@ -0,0 +1,551 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildRank|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(RankTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = RankTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildRank A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, name FROM Rank WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildRank $obj */ + $obj = new ChildRank(); + $obj->hydrate($row); + RankTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildRank|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(RankTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(RankTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(RankTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(RankTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(RankTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the name column + * + * Example usage: + * + * $query->filterByName('fooValue'); // WHERE name = 'fooValue' + * $query->filterByName('%fooValue%', Criteria::LIKE); // WHERE name LIKE '%fooValue%' + * + * + * @param string $name The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function filterByName($name = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($name)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(RankTableMap::COL_NAME, $name, $comparison); + } + + /** + * Filter the query by a related \CategoryRankNutrient object + * + * @param \CategoryRankNutrient|ObjectCollection $categoryRankNutrient the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildRankQuery The current query, for fluid interface + */ + public function filterByCategoryRankNutrient($categoryRankNutrient, $comparison = null) + { + if ($categoryRankNutrient instanceof \CategoryRankNutrient) { + return $this + ->addUsingAlias(RankTableMap::COL_ID, $categoryRankNutrient->getRankId(), $comparison); + } elseif ($categoryRankNutrient instanceof ObjectCollection) { + return $this + ->useCategoryRankNutrientQuery() + ->filterByPrimaryKeys($categoryRankNutrient->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByCategoryRankNutrient() only accepts arguments of type \CategoryRankNutrient or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the CategoryRankNutrient relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function joinCategoryRankNutrient($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('CategoryRankNutrient'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'CategoryRankNutrient'); + } + + return $this; + } + + /** + * Use the CategoryRankNutrient relation CategoryRankNutrient object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryRankNutrientQuery A secondary query class using the current class as primary query + */ + public function useCategoryRankNutrientQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) + { + return $this + ->joinCategoryRankNutrient($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'CategoryRankNutrient', '\CategoryRankNutrientQuery'); + } + + /** + * Filter the query by a related \Food object + * + * @param \Food|ObjectCollection $food the related object to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildRankQuery The current query, for fluid interface + */ + public function filterByFood($food, $comparison = null) + { + if ($food instanceof \Food) { + return $this + ->addUsingAlias(RankTableMap::COL_ID, $food->getRankId(), $comparison); + } elseif ($food instanceof ObjectCollection) { + return $this + ->useFoodQuery() + ->filterByPrimaryKeys($food->getPrimaryKeys()) + ->endUse(); + } else { + throw new PropelException('filterByFood() only accepts arguments of type \Food or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Food relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function joinFood($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Food'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Food'); + } + + return $this; + } + + /** + * Use the Food relation Food object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \FoodQuery A secondary query class using the current class as primary query + */ + public function useFoodQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinFood($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Food', '\FoodQuery'); + } + + /** + * Exclude object from result + * + * @param ChildRank $rank Object to remove from the list of results + * + * @return $this|ChildRankQuery The current query, for fluid interface + */ + public function prune($rank = null) + { + if ($rank) { + $this->addUsingAlias(RankTableMap::COL_ID, $rank->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Rank table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + RankTableMap::clearInstancePool(); + RankTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(RankTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + RankTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + RankTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // RankQuery diff --git a/api/generated-classes/Base/Subcategory.php b/api/generated-classes/Base/Subcategory.php new file mode 100644 index 0000000..c6a7ba1 --- /dev/null +++ b/api/generated-classes/Base/Subcategory.php @@ -0,0 +1,1316 @@ +modifiedColumns; + } + + /** + * Has specified column been modified? + * + * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID + * @return boolean True if $col has been modified. + */ + public function isColumnModified($col) + { + return $this->modifiedColumns && isset($this->modifiedColumns[$col]); + } + + /** + * Get the columns that have been modified in this object. + * @return array A unique list of the modified column names for this object. + */ + public function getModifiedColumns() + { + return $this->modifiedColumns ? array_keys($this->modifiedColumns) : []; + } + + /** + * Returns whether the object has ever been saved. This will + * be false, if the object was retrieved from storage or was created + * and then saved. + * + * @return boolean true, if the object has never been persisted. + */ + public function isNew() + { + return $this->new; + } + + /** + * Setter for the isNew attribute. This method will be called + * by Propel-generated children and objects. + * + * @param boolean $b the state of the object. + */ + public function setNew($b) + { + $this->new = (boolean) $b; + } + + /** + * Whether this object has been deleted. + * @return boolean The deleted state of this object. + */ + public function isDeleted() + { + return $this->deleted; + } + + /** + * Specify whether this object has been deleted. + * @param boolean $b The deleted state of this object. + * @return void + */ + public function setDeleted($b) + { + $this->deleted = (boolean) $b; + } + + /** + * Sets the modified state for the object to be false. + * @param string $col If supplied, only the specified column is reset. + * @return void + */ + public function resetModified($col = null) + { + if (null !== $col) { + if (isset($this->modifiedColumns[$col])) { + unset($this->modifiedColumns[$col]); + } + } else { + $this->modifiedColumns = array(); + } + } + + /** + * Compares this with another Subcategory instance. If + * obj is an instance of Subcategory, delegates to + * equals(Subcategory). Otherwise, returns false. + * + * @param mixed $obj The object to compare to. + * @return boolean Whether equal to the object specified. + */ + public function equals($obj) + { + if (!$obj instanceof static) { + return false; + } + + if ($this === $obj) { + return true; + } + + if (null === $this->getPrimaryKey() || null === $obj->getPrimaryKey()) { + return false; + } + + return $this->getPrimaryKey() === $obj->getPrimaryKey(); + } + + /** + * Get the associative array of the virtual columns in this object + * + * @return array + */ + public function getVirtualColumns() + { + return $this->virtualColumns; + } + + /** + * Checks the existence of a virtual column in this object + * + * @param string $name The virtual column name + * @return boolean + */ + public function hasVirtualColumn($name) + { + return array_key_exists($name, $this->virtualColumns); + } + + /** + * Get the value of a virtual column in this object + * + * @param string $name The virtual column name + * @return mixed + * + * @throws PropelException + */ + public function getVirtualColumn($name) + { + if (!$this->hasVirtualColumn($name)) { + throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); + } + + return $this->virtualColumns[$name]; + } + + /** + * Set the value of a virtual column in this object + * + * @param string $name The virtual column name + * @param mixed $value The value to give to the virtual column + * + * @return $this|Subcategory The current object, for fluid interface + */ + public function setVirtualColumn($name, $value) + { + $this->virtualColumns[$name] = $value; + + return $this; + } + + /** + * Logs a message using Propel::log(). + * + * @param string $msg + * @param int $priority One of the Propel::LOG_* logging levels + * @return boolean + */ + protected function log($msg, $priority = Propel::LOG_INFO) + { + return Propel::log(get_class($this) . ': ' . $msg, $priority); + } + + /** + * Export the current object properties to a string, using a given parser format + * + * $book = BookQuery::create()->findPk(9012); + * echo $book->exportTo('JSON'); + * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. + * @return string The exported data + */ + public function exportTo($parser, $includeLazyLoadColumns = true) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); + } + + /** + * Clean up internal collections prior to serializing + * Avoids recursive loops that turn into segmentation faults when serializing + */ + public function __sleep() + { + $this->clearAllReferences(); + + $cls = new \ReflectionClass($this); + $propertyNames = []; + $serializableProperties = array_diff($cls->getProperties(), $cls->getProperties(\ReflectionProperty::IS_STATIC)); + + foreach($serializableProperties as $property) { + $propertyNames[] = $property->getName(); + } + + return $propertyNames; + } + + /** + * Get the [id] column value. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get the [name] column value. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get the [category_id] column value. + * + * @return int + */ + public function getCategoryId() + { + return $this->category_id; + } + + /** + * Set the value of [id] column. + * + * @param int $v new value + * @return $this|\Subcategory The current object (for fluent API support) + */ + public function setId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[SubcategoryTableMap::COL_ID] = true; + } + + return $this; + } // setId() + + /** + * Set the value of [name] column. + * + * @param string $v new value + * @return $this|\Subcategory The current object (for fluent API support) + */ + public function setName($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[SubcategoryTableMap::COL_NAME] = true; + } + + return $this; + } // setName() + + /** + * Set the value of [category_id] column. + * + * @param int $v new value + * @return $this|\Subcategory The current object (for fluent API support) + */ + public function setCategoryId($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->category_id !== $v) { + $this->category_id = $v; + $this->modifiedColumns[SubcategoryTableMap::COL_CATEGORY_ID] = true; + } + + if ($this->aCategory !== null && $this->aCategory->getId() !== $v) { + $this->aCategory = null; + } + + return $this; + } // setCategoryId() + + /** + * Indicates whether the columns in this object are only set to default values. + * + * This method can be used in conjunction with isModified() to indicate whether an object is both + * modified _and_ has some values set which are non-default. + * + * @return boolean Whether the columns in this object are only been set with default values. + */ + public function hasOnlyDefaultValues() + { + // otherwise, everything was equal, so return TRUE + return true; + } // hasOnlyDefaultValues() + + /** + * Hydrates (populates) the object variables with values from the database resultset. + * + * An offset (0-based "start column") is specified so that objects can be hydrated + * with a subset of the columns in the resultset rows. This is needed, for example, + * for results of JOIN queries where the resultset row includes columns from two or + * more tables. + * + * @param array $row The row returned by DataFetcher->fetch(). + * @param int $startcol 0-based offset column which indicates which restultset column to start with. + * @param boolean $rehydrate Whether this object is being re-hydrated from the database. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @return int next starting column + * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. + */ + public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) + { + try { + + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : SubcategoryTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + $this->id = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : SubcategoryTableMap::translateFieldName('Name', TableMap::TYPE_PHPNAME, $indexType)]; + $this->name = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : SubcategoryTableMap::translateFieldName('CategoryId', TableMap::TYPE_PHPNAME, $indexType)]; + $this->category_id = (null !== $col) ? (int) $col : null; + $this->resetModified(); + + $this->setNew(false); + + if ($rehydrate) { + $this->ensureConsistency(); + } + + return $startcol + 3; // 3 = SubcategoryTableMap::NUM_HYDRATE_COLUMNS. + + } catch (Exception $e) { + throw new PropelException(sprintf('Error populating %s object', '\\Subcategory'), 0, $e); + } + } + + /** + * Checks and repairs the internal consistency of the object. + * + * This method is executed after an already-instantiated object is re-hydrated + * from the database. It exists to check any foreign keys to make sure that + * the objects related to the current object are correct based on foreign key. + * + * You can override this method in the stub class, but you should always invoke + * the base method from the overridden method (i.e. parent::ensureConsistency()), + * in case your model changes. + * + * @throws PropelException + */ + public function ensureConsistency() + { + if ($this->aCategory !== null && $this->category_id !== $this->aCategory->getId()) { + $this->aCategory = null; + } + } // ensureConsistency + + /** + * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. + * + * This will only work if the object has been saved and has a valid primary key set. + * + * @param boolean $deep (optional) Whether to also de-associated any related objects. + * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. + * @return void + * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db + */ + public function reload($deep = false, ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("Cannot reload a deleted object."); + } + + if ($this->isNew()) { + throw new PropelException("Cannot reload an unsaved object."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(SubcategoryTableMap::DATABASE_NAME); + } + + // We don't need to alter the object instance pool; we're just modifying this instance + // already in the pool. + + $dataFetcher = ChildSubcategoryQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); + $row = $dataFetcher->fetch(); + $dataFetcher->close(); + if (!$row) { + throw new PropelException('Cannot find matching row in the database to reload object values.'); + } + $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate + + if ($deep) { // also de-associate any related objects? + + $this->aCategory = null; + } // if (deep) + } + + /** + * Removes this object from datastore and sets delete attribute. + * + * @param ConnectionInterface $con + * @return void + * @throws PropelException + * @see Subcategory::setDeleted() + * @see Subcategory::isDeleted() + */ + public function delete(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + $con->transaction(function () use ($con) { + $deleteQuery = ChildSubcategoryQuery::create() + ->filterByPrimaryKey($this->getPrimaryKey()); + $ret = $this->preDelete($con); + if ($ret) { + $deleteQuery->delete($con); + $this->postDelete($con); + $this->setDeleted(true); + } + }); + } + + /** + * Persists this object to the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All modified related objects will also be persisted in the doSave() + * method. This method wraps all precipitate database operations in a + * single transaction. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see doSave() + */ + public function save(ConnectionInterface $con = null) + { + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + return $con->transaction(function () use ($con) { + $ret = $this->preSave($con); + $isInsert = $this->isNew(); + if ($isInsert) { + $ret = $ret && $this->preInsert($con); + } else { + $ret = $ret && $this->preUpdate($con); + } + if ($ret) { + $affectedRows = $this->doSave($con); + if ($isInsert) { + $this->postInsert($con); + } else { + $this->postUpdate($con); + } + $this->postSave($con); + SubcategoryTableMap::addInstanceToPool($this); + } else { + $affectedRows = 0; + } + + return $affectedRows; + }); + } + + /** + * Performs the work of inserting or updating the row in the database. + * + * If the object is new, it inserts it; otherwise an update is performed. + * All related objects are also updated in this method. + * + * @param ConnectionInterface $con + * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. + * @throws PropelException + * @see save() + */ + protected function doSave(ConnectionInterface $con) + { + $affectedRows = 0; // initialize var to track total num of affected rows + if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + // We call the save method on the following object(s) if they + // were passed to this object by their corresponding set + // method. This object relates to these object(s) by a + // foreign key reference. + + if ($this->aCategory !== null) { + if ($this->aCategory->isModified() || $this->aCategory->isNew()) { + $affectedRows += $this->aCategory->save($con); + } + $this->setCategory($this->aCategory); + } + + if ($this->isNew() || $this->isModified()) { + // persist changes + if ($this->isNew()) { + $this->doInsert($con); + $affectedRows += 1; + } else { + $affectedRows += $this->doUpdate($con); + } + $this->resetModified(); + } + + $this->alreadyInSave = false; + + } + + return $affectedRows; + } // doSave() + + /** + * Insert the row in the database. + * + * @param ConnectionInterface $con + * + * @throws PropelException + * @see doSave() + */ + protected function doInsert(ConnectionInterface $con) + { + $modifiedColumns = array(); + $index = 0; + + $this->modifiedColumns[SubcategoryTableMap::COL_ID] = true; + if (null !== $this->id) { + throw new PropelException('Cannot insert a value for auto-increment primary key (' . SubcategoryTableMap::COL_ID . ')'); + } + + // check the columns in natural order for more readable SQL queries + if ($this->isColumnModified(SubcategoryTableMap::COL_ID)) { + $modifiedColumns[':p' . $index++] = 'id'; + } + if ($this->isColumnModified(SubcategoryTableMap::COL_NAME)) { + $modifiedColumns[':p' . $index++] = 'name'; + } + if ($this->isColumnModified(SubcategoryTableMap::COL_CATEGORY_ID)) { + $modifiedColumns[':p' . $index++] = 'category_id'; + } + + $sql = sprintf( + 'INSERT INTO Subcategory (%s) VALUES (%s)', + implode(', ', $modifiedColumns), + implode(', ', array_keys($modifiedColumns)) + ); + + try { + $stmt = $con->prepare($sql); + foreach ($modifiedColumns as $identifier => $columnName) { + switch ($columnName) { + case 'id': + $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); + break; + case 'name': + $stmt->bindValue($identifier, $this->name, PDO::PARAM_STR); + break; + case 'category_id': + $stmt->bindValue($identifier, $this->category_id, PDO::PARAM_INT); + break; + } + } + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); + } + + try { + $pk = $con->lastInsertId(); + } catch (Exception $e) { + throw new PropelException('Unable to get autoincrement id.', 0, $e); + } + $this->setId($pk); + + $this->setNew(false); + } + + /** + * Update the row in the database. + * + * @param ConnectionInterface $con + * + * @return Integer Number of updated rows + * @see doSave() + */ + protected function doUpdate(ConnectionInterface $con) + { + $selectCriteria = $this->buildPkeyCriteria(); + $valuesCriteria = $this->buildCriteria(); + + return $selectCriteria->doUpdate($valuesCriteria, $con); + } + + /** + * Retrieves a field from the object by name passed in as a string. + * + * @param string $name name + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return mixed Value of field. + */ + public function getByName($name, $type = TableMap::TYPE_PHPNAME) + { + $pos = SubcategoryTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + $field = $this->getByPosition($pos); + + return $field; + } + + /** + * Retrieves a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @return mixed Value of field at $pos + */ + public function getByPosition($pos) + { + switch ($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + case 2: + return $this->getCategoryId(); + break; + default: + return null; + break; + } // switch() + } + + /** + * Exports the object as an array. + * + * You can specify the key type of the array by passing one of the class + * type constants. + * + * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. + * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion + * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. + * + * @return array an associative array containing the field names (as keys) and field values + */ + public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) + { + + if (isset($alreadyDumpedObjects['Subcategory'][$this->hashCode()])) { + return '*RECURSION*'; + } + $alreadyDumpedObjects['Subcategory'][$this->hashCode()] = true; + $keys = SubcategoryTableMap::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + $keys[2] => $this->getCategoryId(), + ); + $virtualColumns = $this->virtualColumns; + foreach ($virtualColumns as $key => $virtualColumn) { + $result[$key] = $virtualColumn; + } + + if ($includeForeignObjects) { + if (null !== $this->aCategory) { + + switch ($keyType) { + case TableMap::TYPE_CAMELNAME: + $key = 'category'; + break; + case TableMap::TYPE_FIELDNAME: + $key = 'Category'; + break; + default: + $key = 'Category'; + } + + $result[$key] = $this->aCategory->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); + } + } + + return $result; + } + + /** + * Sets a field from the object by name passed in as a string. + * + * @param string $name + * @param mixed $value field value + * @param string $type The type of fieldname the $name is of: + * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * Defaults to TableMap::TYPE_PHPNAME. + * @return $this|\Subcategory + */ + public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) + { + $pos = SubcategoryTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); + + return $this->setByPosition($pos, $value); + } + + /** + * Sets a field from the object by Position as specified in the xml schema. + * Zero-based. + * + * @param int $pos position in xml schema + * @param mixed $value field value + * @return $this|\Subcategory + */ + public function setByPosition($pos, $value) + { + switch ($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + case 2: + $this->setCategoryId($value); + break; + } // switch() + + return $this; + } + + /** + * Populates the object using an array. + * + * This is particularly useful when populating an object from one of the + * request arrays (e.g. $_POST). This method goes through the column + * names, checking to see whether a matching key exists in populated + * array. If so the setByName() method is called for that column. + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param array $arr An array to populate the object from. + * @param string $keyType The type of keys the array uses. + * @return void + */ + public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) + { + $keys = SubcategoryTableMap::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) { + $this->setId($arr[$keys[0]]); + } + if (array_key_exists($keys[1], $arr)) { + $this->setName($arr[$keys[1]]); + } + if (array_key_exists($keys[2], $arr)) { + $this->setCategoryId($arr[$keys[2]]); + } + } + + /** + * Populate the current object from a string, using a given parser format + * + * $book = new Book(); + * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); + * + * + * You can specify the key type of the array by additionally passing one + * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME, + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * The default key type is the column's TableMap::TYPE_PHPNAME. + * + * @param mixed $parser A AbstractParser instance, + * or a format name ('XML', 'YAML', 'JSON', 'CSV') + * @param string $data The source data to import from + * @param string $keyType The type of keys the array uses. + * + * @return $this|\Subcategory The current object, for fluid interface + */ + public function importFrom($parser, $data, $keyType = TableMap::TYPE_PHPNAME) + { + if (!$parser instanceof AbstractParser) { + $parser = AbstractParser::getParser($parser); + } + + $this->fromArray($parser->toArray($data), $keyType); + + return $this; + } + + /** + * Build a Criteria object containing the values of all modified columns in this object. + * + * @return Criteria The Criteria object containing all modified values. + */ + public function buildCriteria() + { + $criteria = new Criteria(SubcategoryTableMap::DATABASE_NAME); + + if ($this->isColumnModified(SubcategoryTableMap::COL_ID)) { + $criteria->add(SubcategoryTableMap::COL_ID, $this->id); + } + if ($this->isColumnModified(SubcategoryTableMap::COL_NAME)) { + $criteria->add(SubcategoryTableMap::COL_NAME, $this->name); + } + if ($this->isColumnModified(SubcategoryTableMap::COL_CATEGORY_ID)) { + $criteria->add(SubcategoryTableMap::COL_CATEGORY_ID, $this->category_id); + } + + return $criteria; + } + + /** + * Builds a Criteria object containing the primary key for this object. + * + * Unlike buildCriteria() this method includes the primary key values regardless + * of whether or not they have been modified. + * + * @throws LogicException if no primary key is defined + * + * @return Criteria The Criteria object containing value(s) for primary key(s). + */ + public function buildPkeyCriteria() + { + $criteria = ChildSubcategoryQuery::create(); + $criteria->add(SubcategoryTableMap::COL_ID, $this->id); + + return $criteria; + } + + /** + * If the primary key is not null, return the hashcode of the + * primary key. Otherwise, return the hash code of the object. + * + * @return int Hashcode + */ + public function hashCode() + { + $validPk = null !== $this->getId(); + + $validPrimaryKeyFKs = 0; + $primaryKeyFKs = []; + + if ($validPk) { + return crc32(json_encode($this->getPrimaryKey(), JSON_UNESCAPED_UNICODE)); + } elseif ($validPrimaryKeyFKs) { + return crc32(json_encode($primaryKeyFKs, JSON_UNESCAPED_UNICODE)); + } + + return spl_object_hash($this); + } + + /** + * Returns the primary key for this object (row). + * @return int + */ + public function getPrimaryKey() + { + return $this->getId(); + } + + /** + * Generic method to set the primary key (id column). + * + * @param int $key Primary key. + * @return void + */ + public function setPrimaryKey($key) + { + $this->setId($key); + } + + /** + * Returns true if the primary key for this object is null. + * @return boolean + */ + public function isPrimaryKeyNull() + { + return null === $this->getId(); + } + + /** + * Sets contents of passed object to values from current object. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param object $copyObj An object of \Subcategory (or compatible) type. + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. + * @throws PropelException + */ + public function copyInto($copyObj, $deepCopy = false, $makeNew = true) + { + $copyObj->setName($this->getName()); + $copyObj->setCategoryId($this->getCategoryId()); + if ($makeNew) { + $copyObj->setNew(true); + $copyObj->setId(NULL); // this is a auto-increment column, so set to default value + } + } + + /** + * Makes a copy of this object that will be inserted as a new row in table when saved. + * It creates a new object filling in the simple attributes, but skipping any primary + * keys that are defined for the table. + * + * If desired, this method can also make copies of all associated (fkey referrers) + * objects. + * + * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. + * @return \Subcategory Clone of current object. + * @throws PropelException + */ + public function copy($deepCopy = false) + { + // we use get_class(), because this might be a subclass + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + + return $copyObj; + } + + /** + * Declares an association between this object and a ChildCategory object. + * + * @param ChildCategory $v + * @return $this|\Subcategory The current object (for fluent API support) + * @throws PropelException + */ + public function setCategory(ChildCategory $v = null) + { + if ($v === null) { + $this->setCategoryId(NULL); + } else { + $this->setCategoryId($v->getId()); + } + + $this->aCategory = $v; + + // Add binding for other direction of this n:n relationship. + // If this object has already been added to the ChildCategory object, it will not be re-added. + if ($v !== null) { + $v->addSubcategory($this); + } + + + return $this; + } + + + /** + * Get the associated ChildCategory object + * + * @param ConnectionInterface $con Optional Connection object. + * @return ChildCategory The associated ChildCategory object. + * @throws PropelException + */ + public function getCategory(ConnectionInterface $con = null) + { + if ($this->aCategory === null && ($this->category_id !== null)) { + $this->aCategory = ChildCategoryQuery::create()->findPk($this->category_id, $con); + /* The following can be used additionally to + guarantee the related object contains a reference + to this object. This level of coupling may, however, be + undesirable since it could result in an only partially populated collection + in the referenced object. + $this->aCategory->addSubcategories($this); + */ + } + + return $this->aCategory; + } + + /** + * Clears the current object, sets all attributes to their default values and removes + * outgoing references as well as back-references (from other objects to this one. Results probably in a database + * change of those foreign objects when you call `save` there). + */ + public function clear() + { + if (null !== $this->aCategory) { + $this->aCategory->removeSubcategory($this); + } + $this->id = null; + $this->name = null; + $this->category_id = null; + $this->alreadyInSave = false; + $this->clearAllReferences(); + $this->resetModified(); + $this->setNew(true); + $this->setDeleted(false); + } + + /** + * Resets all references and back-references to other model objects or collections of model objects. + * + * This method is used to reset all php object references (not the actual reference in the database). + * Necessary for object serialisation. + * + * @param boolean $deep Whether to also clear the references on all referrer objects. + */ + public function clearAllReferences($deep = false) + { + if ($deep) { + } // if ($deep) + + $this->aCategory = null; + } + + /** + * Return the string representation of this object + * + * @return string + */ + public function __toString() + { + return (string) $this->exportTo(SubcategoryTableMap::DEFAULT_STRING_FORMAT); + } + + /** + * Code to be run before persisting the object + * @param ConnectionInterface $con + * @return boolean + */ + public function preSave(ConnectionInterface $con = null) + { + if (is_callable('parent::preSave')) { + return parent::preSave($con); + } + return true; + } + + /** + * Code to be run after persisting the object + * @param ConnectionInterface $con + */ + public function postSave(ConnectionInterface $con = null) + { + if (is_callable('parent::postSave')) { + parent::postSave($con); + } + } + + /** + * Code to be run before inserting to database + * @param ConnectionInterface $con + * @return boolean + */ + public function preInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::preInsert')) { + return parent::preInsert($con); + } + return true; + } + + /** + * Code to be run after inserting to database + * @param ConnectionInterface $con + */ + public function postInsert(ConnectionInterface $con = null) + { + if (is_callable('parent::postInsert')) { + parent::postInsert($con); + } + } + + /** + * Code to be run before updating the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::preUpdate')) { + return parent::preUpdate($con); + } + return true; + } + + /** + * Code to be run after updating the object in database + * @param ConnectionInterface $con + */ + public function postUpdate(ConnectionInterface $con = null) + { + if (is_callable('parent::postUpdate')) { + parent::postUpdate($con); + } + } + + /** + * Code to be run before deleting the object in database + * @param ConnectionInterface $con + * @return boolean + */ + public function preDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::preDelete')) { + return parent::preDelete($con); + } + return true; + } + + /** + * Code to be run after deleting the object in database + * @param ConnectionInterface $con + */ + public function postDelete(ConnectionInterface $con = null) + { + if (is_callable('parent::postDelete')) { + parent::postDelete($con); + } + } + + + /** + * Derived method to catches calls to undefined methods. + * + * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). + * Allows to define default __call() behavior if you overwrite __call() + * + * @param string $name + * @param mixed $params + * + * @return array|string + */ + public function __call($name, $params) + { + if (0 === strpos($name, 'get')) { + $virtualColumn = substr($name, 3); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + + $virtualColumn = lcfirst($virtualColumn); + if ($this->hasVirtualColumn($virtualColumn)) { + return $this->getVirtualColumn($virtualColumn); + } + } + + if (0 === strpos($name, 'from')) { + $format = substr($name, 4); + + return $this->importFrom($format, reset($params)); + } + + if (0 === strpos($name, 'to')) { + $format = substr($name, 2); + $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; + + return $this->exportTo($format, $includeLazyLoadColumns); + } + + throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); + } + +} diff --git a/api/generated-classes/Base/SubcategoryQuery.php b/api/generated-classes/Base/SubcategoryQuery.php new file mode 100644 index 0000000..e5ff830 --- /dev/null +++ b/api/generated-classes/Base/SubcategoryQuery.php @@ -0,0 +1,520 @@ +setModelAlias($modelAlias); + } + if ($criteria instanceof Criteria) { + $query->mergeWith($criteria); + } + + return $query; + } + + /** + * Find object by primary key. + * Propel uses the instance pool to skip the database if the object exists. + * Go fast if the query is untouched. + * + * + * $obj = $c->findPk(12, $con); + * + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ChildSubcategory|array|mixed the result, formatted by the current formatter + */ + public function findPk($key, ConnectionInterface $con = null) + { + if ($key === null) { + return null; + } + + if ($con === null) { + $con = Propel::getServiceContainer()->getReadConnection(SubcategoryTableMap::DATABASE_NAME); + } + + $this->basePreSelect($con); + + if ( + $this->formatter || $this->modelAlias || $this->with || $this->select + || $this->selectColumns || $this->asColumns || $this->selectModifiers + || $this->map || $this->having || $this->joins + ) { + return $this->findPkComplex($key, $con); + } + + if ((null !== ($obj = SubcategoryTableMap::getInstanceFromPool(null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key)))) { + // the object is already in the instance pool + return $obj; + } + + return $this->findPkSimple($key, $con); + } + + /** + * Find object by primary key using raw SQL to go fast. + * Bypass doSelect() and the object formatter by using generated code. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildSubcategory A model object, or null if the key is not found + */ + protected function findPkSimple($key, ConnectionInterface $con) + { + $sql = 'SELECT id, name, category_id FROM Subcategory WHERE id = :p0'; + try { + $stmt = $con->prepare($sql); + $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->execute(); + } catch (Exception $e) { + Propel::log($e->getMessage(), Propel::LOG_ERR); + throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); + } + $obj = null; + if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + /** @var ChildSubcategory $obj */ + $obj = new ChildSubcategory(); + $obj->hydrate($row); + SubcategoryTableMap::addInstanceToPool($obj, null === $key || is_scalar($key) || is_callable([$key, '__toString']) ? (string) $key : $key); + } + $stmt->closeCursor(); + + return $obj; + } + + /** + * Find object by primary key. + * + * @param mixed $key Primary key to use for the query + * @param ConnectionInterface $con A connection object + * + * @return ChildSubcategory|array|mixed the result, formatted by the current formatter + */ + protected function findPkComplex($key, ConnectionInterface $con) + { + // As the query uses a PK condition, no limit(1) is necessary. + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKey($key) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); + } + + /** + * Find objects by primary key + * + * $objs = $c->findPks(array(12, 56, 832), $con); + * + * @param array $keys Primary keys to use for the query + * @param ConnectionInterface $con an optional connection object + * + * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter + */ + public function findPks($keys, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); + } + $this->basePreSelect($con); + $criteria = $this->isKeepQuery() ? clone $this : $this; + $dataFetcher = $criteria + ->filterByPrimaryKeys($keys) + ->doSelect($con); + + return $criteria->getFormatter()->init($criteria)->format($dataFetcher); + } + + /** + * Filter the query by primary key + * + * @param mixed $key Primary key to use for the query + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterByPrimaryKey($key) + { + + return $this->addUsingAlias(SubcategoryTableMap::COL_ID, $key, Criteria::EQUAL); + } + + /** + * Filter the query by a list of primary keys + * + * @param array $keys The list of primary key to use for the query + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterByPrimaryKeys($keys) + { + + return $this->addUsingAlias(SubcategoryTableMap::COL_ID, $keys, Criteria::IN); + } + + /** + * Filter the query on the id column + * + * Example usage: + * + * $query->filterById(1234); // WHERE id = 1234 + * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) + * $query->filterById(array('min' => 12)); // WHERE id > 12 + * + * + * @param mixed $id The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterById($id = null, $comparison = null) + { + if (is_array($id)) { + $useMinMax = false; + if (isset($id['min'])) { + $this->addUsingAlias(SubcategoryTableMap::COL_ID, $id['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($id['max'])) { + $this->addUsingAlias(SubcategoryTableMap::COL_ID, $id['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(SubcategoryTableMap::COL_ID, $id, $comparison); + } + + /** + * Filter the query on the name column + * + * Example usage: + * + * $query->filterByName('fooValue'); // WHERE name = 'fooValue' + * $query->filterByName('%fooValue%', Criteria::LIKE); // WHERE name LIKE '%fooValue%' + * + * + * @param string $name The value to use as filter. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterByName($name = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($name)) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(SubcategoryTableMap::COL_NAME, $name, $comparison); + } + + /** + * Filter the query on the category_id column + * + * Example usage: + * + * $query->filterByCategoryId(1234); // WHERE category_id = 1234 + * $query->filterByCategoryId(array(12, 34)); // WHERE category_id IN (12, 34) + * $query->filterByCategoryId(array('min' => 12)); // WHERE category_id > 12 + * + * + * @see filterByCategory() + * + * @param mixed $categoryId The value to use as filter. + * Use scalar values for equality. + * Use array values for in_array() equivalent. + * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterByCategoryId($categoryId = null, $comparison = null) + { + if (is_array($categoryId)) { + $useMinMax = false; + if (isset($categoryId['min'])) { + $this->addUsingAlias(SubcategoryTableMap::COL_CATEGORY_ID, $categoryId['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($categoryId['max'])) { + $this->addUsingAlias(SubcategoryTableMap::COL_CATEGORY_ID, $categoryId['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(SubcategoryTableMap::COL_CATEGORY_ID, $categoryId, $comparison); + } + + /** + * Filter the query by a related \Category object + * + * @param \Category|ObjectCollection $category The related object(s) to use as filter + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @throws \Propel\Runtime\Exception\PropelException + * + * @return ChildSubcategoryQuery The current query, for fluid interface + */ + public function filterByCategory($category, $comparison = null) + { + if ($category instanceof \Category) { + return $this + ->addUsingAlias(SubcategoryTableMap::COL_CATEGORY_ID, $category->getId(), $comparison); + } elseif ($category instanceof ObjectCollection) { + if (null === $comparison) { + $comparison = Criteria::IN; + } + + return $this + ->addUsingAlias(SubcategoryTableMap::COL_CATEGORY_ID, $category->toKeyValue('PrimaryKey', 'Id'), $comparison); + } else { + throw new PropelException('filterByCategory() only accepts arguments of type \Category or Collection'); + } + } + + /** + * Adds a JOIN clause to the query using the Category relation + * + * @param string $relationAlias optional alias for the relation + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function joinCategory($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + $tableMap = $this->getTableMap(); + $relationMap = $tableMap->getRelation('Category'); + + // create a ModelJoin object for this join + $join = new ModelJoin(); + $join->setJoinType($joinType); + $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); + if ($previousJoin = $this->getPreviousJoin()) { + $join->setPreviousJoin($previousJoin); + } + + // add the ModelJoin to the current object + if ($relationAlias) { + $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); + $this->addJoinObject($join, $relationAlias); + } else { + $this->addJoinObject($join, 'Category'); + } + + return $this; + } + + /** + * Use the Category relation Category object + * + * @see useQuery() + * + * @param string $relationAlias optional alias for the relation, + * to be used as main alias in the secondary query + * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' + * + * @return \CategoryQuery A secondary query class using the current class as primary query + */ + public function useCategoryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + { + return $this + ->joinCategory($relationAlias, $joinType) + ->useQuery($relationAlias ? $relationAlias : 'Category', '\CategoryQuery'); + } + + /** + * Exclude object from result + * + * @param ChildSubcategory $subcategory Object to remove from the list of results + * + * @return $this|ChildSubcategoryQuery The current query, for fluid interface + */ + public function prune($subcategory = null) + { + if ($subcategory) { + $this->addUsingAlias(SubcategoryTableMap::COL_ID, $subcategory->getId(), Criteria::NOT_EQUAL); + } + + return $this; + } + + /** + * Deletes all rows from the Subcategory table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public function doDeleteAll(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con) { + $affectedRows = 0; // initialize var to track total num of affected rows + $affectedRows += parent::doDeleteAll($con); + // Because this db requires some delete cascade/set null emulation, we have to + // clear the cached instance *after* the emulation has happened (since + // instances get re-added by the select statement contained therein). + SubcategoryTableMap::clearInstancePool(); + SubcategoryTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + + /** + * Performs a DELETE on the database based on the current ModelCriteria + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public function delete(ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + $criteria = $this; + + // Set the correct dbName + $criteria->setDbName(SubcategoryTableMap::DATABASE_NAME); + + // use transaction because $criteria could contain info + // for more than one table or we could emulating ON DELETE CASCADE, etc. + return $con->transaction(function () use ($con, $criteria) { + $affectedRows = 0; // initialize var to track total num of affected rows + + SubcategoryTableMap::removeInstanceFromPool($criteria); + + $affectedRows += ModelCriteria::delete($con); + SubcategoryTableMap::clearRelatedInstancePool(); + + return $affectedRows; + }); + } + +} // SubcategoryQuery diff --git a/api/generated-classes/Category.php b/api/generated-classes/Category.php new file mode 100644 index 0000000..90c4ffb --- /dev/null +++ b/api/generated-classes/Category.php @@ -0,0 +1,18 @@ + array('Id', 'Units', 'Threshold', 'Operator', 'CategoryId', 'RankId', 'NutrientId', ), + self::TYPE_CAMELNAME => array('id', 'units', 'threshold', 'operator', 'categoryId', 'rankId', 'nutrientId', ), + self::TYPE_COLNAME => array(CategoryRankNutrientTableMap::COL_ID, CategoryRankNutrientTableMap::COL_UNITS, CategoryRankNutrientTableMap::COL_THRESHOLD, CategoryRankNutrientTableMap::COL_OPERATOR, CategoryRankNutrientTableMap::COL_CATEGORY_ID, CategoryRankNutrientTableMap::COL_RANK_ID, CategoryRankNutrientTableMap::COL_NUTRIENT_ID, ), + self::TYPE_FIELDNAME => array('id', 'units', 'threshold', 'operator', 'category_id', 'rank_id', 'nutrient_id', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Units' => 1, 'Threshold' => 2, 'Operator' => 3, 'CategoryId' => 4, 'RankId' => 5, 'NutrientId' => 6, ), + self::TYPE_CAMELNAME => array('id' => 0, 'units' => 1, 'threshold' => 2, 'operator' => 3, 'categoryId' => 4, 'rankId' => 5, 'nutrientId' => 6, ), + self::TYPE_COLNAME => array(CategoryRankNutrientTableMap::COL_ID => 0, CategoryRankNutrientTableMap::COL_UNITS => 1, CategoryRankNutrientTableMap::COL_THRESHOLD => 2, CategoryRankNutrientTableMap::COL_OPERATOR => 3, CategoryRankNutrientTableMap::COL_CATEGORY_ID => 4, CategoryRankNutrientTableMap::COL_RANK_ID => 5, CategoryRankNutrientTableMap::COL_NUTRIENT_ID => 6, ), + self::TYPE_FIELDNAME => array('id' => 0, 'units' => 1, 'threshold' => 2, 'operator' => 3, 'category_id' => 4, 'rank_id' => 5, 'nutrient_id' => 6, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Category_Rank_Nutrient'); + $this->setPhpName('CategoryRankNutrient'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\CategoryRankNutrient'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('units', 'Units', 'VARCHAR', false, 128, null); + $this->addColumn('threshold', 'Threshold', 'FLOAT', true, null, null); + $this->addColumn('operator', 'Operator', 'VARCHAR', true, 10, null); + $this->addForeignKey('category_id', 'CategoryId', 'INTEGER', 'Category', 'id', true, null, null); + $this->addForeignKey('rank_id', 'RankId', 'INTEGER', 'Rank', 'id', true, null, null); + $this->addForeignKey('nutrient_id', 'NutrientId', 'INTEGER', 'Nutrient', 'id', true, null, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('Nutrient', '\\Nutrient', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':nutrient_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', null, false); + $this->addRelation('Category', '\\Category', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', null, false); + $this->addRelation('Rank', '\\Rank', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':rank_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', null, false); + } // buildRelations() + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? CategoryRankNutrientTableMap::CLASS_DEFAULT : CategoryRankNutrientTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (CategoryRankNutrient object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = CategoryRankNutrientTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = CategoryRankNutrientTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + CategoryRankNutrientTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = CategoryRankNutrientTableMap::OM_CLASS; + /** @var CategoryRankNutrient $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + CategoryRankNutrientTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = CategoryRankNutrientTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = CategoryRankNutrientTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var CategoryRankNutrient $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + CategoryRankNutrientTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_ID); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_UNITS); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_THRESHOLD); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_OPERATOR); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_CATEGORY_ID); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_RANK_ID); + $criteria->addSelectColumn(CategoryRankNutrientTableMap::COL_NUTRIENT_ID); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.units'); + $criteria->addSelectColumn($alias . '.threshold'); + $criteria->addSelectColumn($alias . '.operator'); + $criteria->addSelectColumn($alias . '.category_id'); + $criteria->addSelectColumn($alias . '.rank_id'); + $criteria->addSelectColumn($alias . '.nutrient_id'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(CategoryRankNutrientTableMap::DATABASE_NAME)->getTable(CategoryRankNutrientTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(CategoryRankNutrientTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(CategoryRankNutrientTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new CategoryRankNutrientTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a CategoryRankNutrient or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or CategoryRankNutrient object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \CategoryRankNutrient) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(CategoryRankNutrientTableMap::DATABASE_NAME); + $criteria->add(CategoryRankNutrientTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = CategoryRankNutrientQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + CategoryRankNutrientTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + CategoryRankNutrientTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Category_Rank_Nutrient table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return CategoryRankNutrientQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a CategoryRankNutrient or Criteria object. + * + * @param mixed $criteria Criteria or CategoryRankNutrient object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryRankNutrientTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from CategoryRankNutrient object + } + + if ($criteria->containsKey(CategoryRankNutrientTableMap::COL_ID) && $criteria->keyContainsValue(CategoryRankNutrientTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.CategoryRankNutrientTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = CategoryRankNutrientQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // CategoryRankNutrientTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +CategoryRankNutrientTableMap::buildTableMap(); diff --git a/api/generated-classes/Map/CategoryTableMap.php b/api/generated-classes/Map/CategoryTableMap.php new file mode 100644 index 0000000..70d22ba --- /dev/null +++ b/api/generated-classes/Map/CategoryTableMap.php @@ -0,0 +1,440 @@ + array('Id', 'Name', ), + self::TYPE_CAMELNAME => array('id', 'name', ), + self::TYPE_COLNAME => array(CategoryTableMap::COL_ID, CategoryTableMap::COL_NAME, ), + self::TYPE_FIELDNAME => array('id', 'name', ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Name' => 1, ), + self::TYPE_CAMELNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_COLNAME => array(CategoryTableMap::COL_ID => 0, CategoryTableMap::COL_NAME => 1, ), + self::TYPE_FIELDNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Category'); + $this->setPhpName('Category'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\Category'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('name', 'Name', 'VARCHAR', true, 128, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('CategoryRankNutrient', '\\CategoryRankNutrient', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', 'CategoryRankNutrients', false); + $this->addRelation('Food', '\\Food', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', 'Foods', false); + $this->addRelation('Subcategory', '\\Subcategory', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', 'Subcategories', false); + } // buildRelations() + /** + * Method to invalidate the instance pool of all tables related to Category * by a foreign key with ON DELETE CASCADE + */ + public static function clearRelatedInstancePool() + { + // Invalidate objects in related instance pools, + // since one or more of them may be deleted by ON DELETE CASCADE/SETNULL rule. + CategoryRankNutrientTableMap::clearInstancePool(); + FoodTableMap::clearInstancePool(); + SubcategoryTableMap::clearInstancePool(); + } + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? CategoryTableMap::CLASS_DEFAULT : CategoryTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (Category object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = CategoryTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = CategoryTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + CategoryTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = CategoryTableMap::OM_CLASS; + /** @var Category $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + CategoryTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = CategoryTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = CategoryTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var Category $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + CategoryTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(CategoryTableMap::COL_ID); + $criteria->addSelectColumn(CategoryTableMap::COL_NAME); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.name'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(CategoryTableMap::DATABASE_NAME)->getTable(CategoryTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(CategoryTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(CategoryTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new CategoryTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a Category or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or Category object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Category) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(CategoryTableMap::DATABASE_NAME); + $criteria->add(CategoryTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = CategoryQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + CategoryTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + CategoryTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Category table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return CategoryQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a Category or Criteria object. + * + * @param mixed $criteria Criteria or Category object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(CategoryTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from Category object + } + + if ($criteria->containsKey(CategoryTableMap::COL_ID) && $criteria->keyContainsValue(CategoryTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.CategoryTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = CategoryQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // CategoryTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +CategoryTableMap::buildTableMap(); diff --git a/api/generated-classes/Map/FoodTableMap.php b/api/generated-classes/Map/FoodTableMap.php new file mode 100644 index 0000000..cb0c787 --- /dev/null +++ b/api/generated-classes/Map/FoodTableMap.php @@ -0,0 +1,446 @@ + array('Id', 'Name', 'Barcode', 'RankId', 'CategoryId', ), + self::TYPE_CAMELNAME => array('id', 'name', 'barcode', 'rankId', 'categoryId', ), + self::TYPE_COLNAME => array(FoodTableMap::COL_ID, FoodTableMap::COL_NAME, FoodTableMap::COL_BARCODE, FoodTableMap::COL_RANK_ID, FoodTableMap::COL_CATEGORY_ID, ), + self::TYPE_FIELDNAME => array('id', 'name', 'barcode', 'rank_id', 'category_id', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Name' => 1, 'Barcode' => 2, 'RankId' => 3, 'CategoryId' => 4, ), + self::TYPE_CAMELNAME => array('id' => 0, 'name' => 1, 'barcode' => 2, 'rankId' => 3, 'categoryId' => 4, ), + self::TYPE_COLNAME => array(FoodTableMap::COL_ID => 0, FoodTableMap::COL_NAME => 1, FoodTableMap::COL_BARCODE => 2, FoodTableMap::COL_RANK_ID => 3, FoodTableMap::COL_CATEGORY_ID => 4, ), + self::TYPE_FIELDNAME => array('id' => 0, 'name' => 1, 'barcode' => 2, 'rank_id' => 3, 'category_id' => 4, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Food'); + $this->setPhpName('Food'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\Food'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('name', 'Name', 'VARCHAR', true, 255, null); + $this->addColumn('barcode', 'Barcode', 'INTEGER', true, null, null); + $this->addForeignKey('rank_id', 'RankId', 'INTEGER', 'Rank', 'id', false, null, null); + $this->addForeignKey('category_id', 'CategoryId', 'INTEGER', 'Category', 'id', false, null, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('Category', '\\Category', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', null, false); + $this->addRelation('Rank', '\\Rank', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':rank_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', null, false); + } // buildRelations() + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? FoodTableMap::CLASS_DEFAULT : FoodTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (Food object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = FoodTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = FoodTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + FoodTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = FoodTableMap::OM_CLASS; + /** @var Food $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + FoodTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = FoodTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = FoodTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var Food $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + FoodTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(FoodTableMap::COL_ID); + $criteria->addSelectColumn(FoodTableMap::COL_NAME); + $criteria->addSelectColumn(FoodTableMap::COL_BARCODE); + $criteria->addSelectColumn(FoodTableMap::COL_RANK_ID); + $criteria->addSelectColumn(FoodTableMap::COL_CATEGORY_ID); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.name'); + $criteria->addSelectColumn($alias . '.barcode'); + $criteria->addSelectColumn($alias . '.rank_id'); + $criteria->addSelectColumn($alias . '.category_id'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(FoodTableMap::DATABASE_NAME)->getTable(FoodTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(FoodTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(FoodTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new FoodTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a Food or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or Food object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Food) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(FoodTableMap::DATABASE_NAME); + $criteria->add(FoodTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = FoodQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + FoodTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + FoodTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Food table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return FoodQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a Food or Criteria object. + * + * @param mixed $criteria Criteria or Food object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(FoodTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from Food object + } + + if ($criteria->containsKey(FoodTableMap::COL_ID) && $criteria->keyContainsValue(FoodTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.FoodTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = FoodQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // FoodTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +FoodTableMap::buildTableMap(); diff --git a/api/generated-classes/Map/NutrientTableMap.php b/api/generated-classes/Map/NutrientTableMap.php new file mode 100644 index 0000000..25adea2 --- /dev/null +++ b/api/generated-classes/Map/NutrientTableMap.php @@ -0,0 +1,424 @@ + array('Id', 'Name', ), + self::TYPE_CAMELNAME => array('id', 'name', ), + self::TYPE_COLNAME => array(NutrientTableMap::COL_ID, NutrientTableMap::COL_NAME, ), + self::TYPE_FIELDNAME => array('id', 'name', ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Name' => 1, ), + self::TYPE_CAMELNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_COLNAME => array(NutrientTableMap::COL_ID => 0, NutrientTableMap::COL_NAME => 1, ), + self::TYPE_FIELDNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Nutrient'); + $this->setPhpName('Nutrient'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\Nutrient'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('name', 'Name', 'VARCHAR', true, 255, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('CategoryRankNutrient', '\\CategoryRankNutrient', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':nutrient_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', 'CategoryRankNutrients', false); + } // buildRelations() + /** + * Method to invalidate the instance pool of all tables related to Nutrient * by a foreign key with ON DELETE CASCADE + */ + public static function clearRelatedInstancePool() + { + // Invalidate objects in related instance pools, + // since one or more of them may be deleted by ON DELETE CASCADE/SETNULL rule. + CategoryRankNutrientTableMap::clearInstancePool(); + } + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? NutrientTableMap::CLASS_DEFAULT : NutrientTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (Nutrient object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = NutrientTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = NutrientTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + NutrientTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = NutrientTableMap::OM_CLASS; + /** @var Nutrient $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + NutrientTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = NutrientTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = NutrientTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var Nutrient $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + NutrientTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(NutrientTableMap::COL_ID); + $criteria->addSelectColumn(NutrientTableMap::COL_NAME); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.name'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(NutrientTableMap::DATABASE_NAME)->getTable(NutrientTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(NutrientTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(NutrientTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new NutrientTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a Nutrient or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or Nutrient object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Nutrient) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(NutrientTableMap::DATABASE_NAME); + $criteria->add(NutrientTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = NutrientQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + NutrientTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + NutrientTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Nutrient table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return NutrientQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a Nutrient or Criteria object. + * + * @param mixed $criteria Criteria or Nutrient object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(NutrientTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from Nutrient object + } + + if ($criteria->containsKey(NutrientTableMap::COL_ID) && $criteria->keyContainsValue(NutrientTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.NutrientTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = NutrientQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // NutrientTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +NutrientTableMap::buildTableMap(); diff --git a/api/generated-classes/Map/RankTableMap.php b/api/generated-classes/Map/RankTableMap.php new file mode 100644 index 0000000..e5a8cea --- /dev/null +++ b/api/generated-classes/Map/RankTableMap.php @@ -0,0 +1,432 @@ + array('Id', 'Name', ), + self::TYPE_CAMELNAME => array('id', 'name', ), + self::TYPE_COLNAME => array(RankTableMap::COL_ID, RankTableMap::COL_NAME, ), + self::TYPE_FIELDNAME => array('id', 'name', ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Name' => 1, ), + self::TYPE_CAMELNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_COLNAME => array(RankTableMap::COL_ID => 0, RankTableMap::COL_NAME => 1, ), + self::TYPE_FIELDNAME => array('id' => 0, 'name' => 1, ), + self::TYPE_NUM => array(0, 1, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Rank'); + $this->setPhpName('Rank'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\Rank'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('name', 'Name', 'VARCHAR', true, 128, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('CategoryRankNutrient', '\\CategoryRankNutrient', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':rank_id', + 1 => ':id', + ), +), 'CASCADE', 'CASCADE', 'CategoryRankNutrients', false); + $this->addRelation('Food', '\\Food', RelationMap::ONE_TO_MANY, array ( + 0 => + array ( + 0 => ':rank_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', 'Foods', false); + } // buildRelations() + /** + * Method to invalidate the instance pool of all tables related to Rank * by a foreign key with ON DELETE CASCADE + */ + public static function clearRelatedInstancePool() + { + // Invalidate objects in related instance pools, + // since one or more of them may be deleted by ON DELETE CASCADE/SETNULL rule. + CategoryRankNutrientTableMap::clearInstancePool(); + FoodTableMap::clearInstancePool(); + } + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? RankTableMap::CLASS_DEFAULT : RankTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (Rank object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = RankTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = RankTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + RankTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = RankTableMap::OM_CLASS; + /** @var Rank $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + RankTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = RankTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = RankTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var Rank $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + RankTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(RankTableMap::COL_ID); + $criteria->addSelectColumn(RankTableMap::COL_NAME); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.name'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(RankTableMap::DATABASE_NAME)->getTable(RankTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(RankTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(RankTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new RankTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a Rank or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or Rank object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Rank) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(RankTableMap::DATABASE_NAME); + $criteria->add(RankTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = RankQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + RankTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + RankTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Rank table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return RankQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a Rank or Criteria object. + * + * @param mixed $criteria Criteria or Rank object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(RankTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from Rank object + } + + if ($criteria->containsKey(RankTableMap::COL_ID) && $criteria->keyContainsValue(RankTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.RankTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = RankQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // RankTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +RankTableMap::buildTableMap(); diff --git a/api/generated-classes/Map/SubcategoryTableMap.php b/api/generated-classes/Map/SubcategoryTableMap.php new file mode 100644 index 0000000..d4b8c2e --- /dev/null +++ b/api/generated-classes/Map/SubcategoryTableMap.php @@ -0,0 +1,423 @@ + array('Id', 'Name', 'CategoryId', ), + self::TYPE_CAMELNAME => array('id', 'name', 'categoryId', ), + self::TYPE_COLNAME => array(SubcategoryTableMap::COL_ID, SubcategoryTableMap::COL_NAME, SubcategoryTableMap::COL_CATEGORY_ID, ), + self::TYPE_FIELDNAME => array('id', 'name', 'category_id', ), + self::TYPE_NUM => array(0, 1, 2, ) + ); + + /** + * holds an array of keys for quick access to the fieldnames array + * + * first dimension keys are the type constants + * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 + */ + protected static $fieldKeys = array ( + self::TYPE_PHPNAME => array('Id' => 0, 'Name' => 1, 'CategoryId' => 2, ), + self::TYPE_CAMELNAME => array('id' => 0, 'name' => 1, 'categoryId' => 2, ), + self::TYPE_COLNAME => array(SubcategoryTableMap::COL_ID => 0, SubcategoryTableMap::COL_NAME => 1, SubcategoryTableMap::COL_CATEGORY_ID => 2, ), + self::TYPE_FIELDNAME => array('id' => 0, 'name' => 1, 'category_id' => 2, ), + self::TYPE_NUM => array(0, 1, 2, ) + ); + + /** + * Initialize the table attributes and columns + * Relations are not initialized by this method since they are lazy loaded + * + * @return void + * @throws PropelException + */ + public function initialize() + { + // attributes + $this->setName('Subcategory'); + $this->setPhpName('Subcategory'); + $this->setIdentifierQuoting(false); + $this->setClassName('\\Subcategory'); + $this->setPackage(''); + $this->setUseIdGenerator(true); + // columns + $this->addPrimaryKey('id', 'Id', 'INTEGER', true, null, null); + $this->addColumn('name', 'Name', 'VARCHAR', true, 255, null); + $this->addForeignKey('category_id', 'CategoryId', 'INTEGER', 'Category', 'id', false, null, null); + } // initialize() + + /** + * Build the RelationMap objects for this table relationships + */ + public function buildRelations() + { + $this->addRelation('Category', '\\Category', RelationMap::MANY_TO_ONE, array ( + 0 => + array ( + 0 => ':category_id', + 1 => ':id', + ), +), 'SET NULL', 'CASCADE', null, false); + } // buildRelations() + + /** + * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. + * + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, a serialize()d version of the primary key will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return string The primary key hash of the row + */ + public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + // If the PK cannot be derived from the row, return NULL. + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + return null; + } + + return null === $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] || is_scalar($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]) || is_callable([$row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)], '__toString']) ? (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] : $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + } + + /** + * Retrieves the primary key from the DB resultset row + * For tables with a single-column primary key, that simple pkey value will be returned. For tables with + * a multi-column primary key, an array of the primary key columns will be returned. + * + * @param array $row resultset row. + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM + * + * @return mixed The primary key of the row + */ + public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + return (int) $row[ + $indexType == TableMap::TYPE_NUM + ? 0 + $offset + : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) + ]; + } + + /** + * The class that the tableMap will make instances of. + * + * If $withPrefix is true, the returned path + * uses a dot-path notation which is translated into a path + * relative to a location on the PHP include_path. + * (e.g. path.to.MyClass -> 'path/to/MyClass.php') + * + * @param boolean $withPrefix Whether or not to return the path with the class name + * @return string path.to.ClassName + */ + public static function getOMClass($withPrefix = true) + { + return $withPrefix ? SubcategoryTableMap::CLASS_DEFAULT : SubcategoryTableMap::OM_CLASS; + } + + /** + * Populates an object of the default type or an object that inherit from the default. + * + * @param array $row row returned by DataFetcher->fetch(). + * @param int $offset The 0-based offset for reading from the resultset row. + * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). + One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_CAMELNAME + * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. + * + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + * @return array (Subcategory object, last column rank) + */ + public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) + { + $key = SubcategoryTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); + if (null !== ($obj = SubcategoryTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, $offset, true); // rehydrate + $col = $offset + SubcategoryTableMap::NUM_HYDRATE_COLUMNS; + } else { + $cls = SubcategoryTableMap::OM_CLASS; + /** @var Subcategory $obj */ + $obj = new $cls(); + $col = $obj->hydrate($row, $offset, false, $indexType); + SubcategoryTableMap::addInstanceToPool($obj, $key); + } + + return array($obj, $col); + } + + /** + * The returned array will contain objects of the default type or + * objects that inherit from the default. + * + * @param DataFetcherInterface $dataFetcher + * @return array + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function populateObjects(DataFetcherInterface $dataFetcher) + { + $results = array(); + + // set the class once to avoid overhead in the loop + $cls = static::getOMClass(false); + // populate the object(s) + while ($row = $dataFetcher->fetch()) { + $key = SubcategoryTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); + if (null !== ($obj = SubcategoryTableMap::getInstanceFromPool($key))) { + // We no longer rehydrate the object, since this can cause data loss. + // See http://www.propelorm.org/ticket/509 + // $obj->hydrate($row, 0, true); // rehydrate + $results[] = $obj; + } else { + /** @var Subcategory $obj */ + $obj = new $cls(); + $obj->hydrate($row); + $results[] = $obj; + SubcategoryTableMap::addInstanceToPool($obj, $key); + } // if key exists + } + + return $results; + } + /** + * Add all the columns needed to create a new object. + * + * Note: any columns that were marked with lazyLoad="true" in the + * XML schema will not be added to the select list and only loaded + * on demand. + * + * @param Criteria $criteria object containing the columns to add. + * @param string $alias optional table alias + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function addSelectColumns(Criteria $criteria, $alias = null) + { + if (null === $alias) { + $criteria->addSelectColumn(SubcategoryTableMap::COL_ID); + $criteria->addSelectColumn(SubcategoryTableMap::COL_NAME); + $criteria->addSelectColumn(SubcategoryTableMap::COL_CATEGORY_ID); + } else { + $criteria->addSelectColumn($alias . '.id'); + $criteria->addSelectColumn($alias . '.name'); + $criteria->addSelectColumn($alias . '.category_id'); + } + } + + /** + * Returns the TableMap related to this object. + * This method is not needed for general use but a specific application could have a need. + * @return TableMap + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function getTableMap() + { + return Propel::getServiceContainer()->getDatabaseMap(SubcategoryTableMap::DATABASE_NAME)->getTable(SubcategoryTableMap::TABLE_NAME); + } + + /** + * Add a TableMap instance to the database for this tableMap class. + */ + public static function buildTableMap() + { + $dbMap = Propel::getServiceContainer()->getDatabaseMap(SubcategoryTableMap::DATABASE_NAME); + if (!$dbMap->hasTable(SubcategoryTableMap::TABLE_NAME)) { + $dbMap->addTableObject(new SubcategoryTableMap()); + } + } + + /** + * Performs a DELETE on the database, given a Subcategory or Criteria object OR a primary key value. + * + * @param mixed $values Criteria or Subcategory object or primary key or array of primary keys + * which is used to create the DELETE statement + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows + * if supported by native driver or if emulated using Propel. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doDelete($values, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + // rename for clarity + $criteria = $values; + } elseif ($values instanceof \Subcategory) { // it's a model object + // create criteria based on pk values + $criteria = $values->buildPkeyCriteria(); + } else { // it's a primary key, or an array of pks + $criteria = new Criteria(SubcategoryTableMap::DATABASE_NAME); + $criteria->add(SubcategoryTableMap::COL_ID, (array) $values, Criteria::IN); + } + + $query = SubcategoryQuery::create()->mergeWith($criteria); + + if ($values instanceof Criteria) { + SubcategoryTableMap::clearInstancePool(); + } elseif (!is_object($values)) { // it's a primary key, or an array of pks + foreach ((array) $values as $singleval) { + SubcategoryTableMap::removeInstanceFromPool($singleval); + } + } + + return $query->delete($con); + } + + /** + * Deletes all rows from the Subcategory table. + * + * @param ConnectionInterface $con the connection to use + * @return int The number of affected rows (if supported by underlying database driver). + */ + public static function doDeleteAll(ConnectionInterface $con = null) + { + return SubcategoryQuery::create()->doDeleteAll($con); + } + + /** + * Performs an INSERT on the database, given a Subcategory or Criteria object. + * + * @param mixed $criteria Criteria or Subcategory object containing data that is used to create the INSERT statement. + * @param ConnectionInterface $con the ConnectionInterface connection to use + * @return mixed The new primary key. + * @throws PropelException Any exceptions caught during processing will be + * rethrown wrapped into a PropelException. + */ + public static function doInsert($criteria, ConnectionInterface $con = null) + { + if (null === $con) { + $con = Propel::getServiceContainer()->getWriteConnection(SubcategoryTableMap::DATABASE_NAME); + } + + if ($criteria instanceof Criteria) { + $criteria = clone $criteria; // rename for clarity + } else { + $criteria = $criteria->buildCriteria(); // build Criteria from Subcategory object + } + + if ($criteria->containsKey(SubcategoryTableMap::COL_ID) && $criteria->keyContainsValue(SubcategoryTableMap::COL_ID) ) { + throw new PropelException('Cannot insert a value for auto-increment primary key ('.SubcategoryTableMap::COL_ID.')'); + } + + + // Set the correct dbName + $query = SubcategoryQuery::create()->mergeWith($criteria); + + // use transaction because $criteria could contain info + // for more than one table (I guess, conceivably) + return $con->transaction(function () use ($con, $query) { + return $query->doInsert($con); + }); + } + +} // SubcategoryTableMap +// This is the static code needed to register the TableMap for this table with the main Propel class. +// +SubcategoryTableMap::buildTableMap(); diff --git a/api/generated-classes/Nutrient.php b/api/generated-classes/Nutrient.php new file mode 100644 index 0000000..c893930 --- /dev/null +++ b/api/generated-classes/Nutrient.php @@ -0,0 +1,18 @@ +checkVersion('2.0.0-dev'); +$serviceContainer->setAdapterClass('default', 'mysql'); +$manager = new \Propel\Runtime\Connection\ConnectionManagerSingle(); +$manager->setConfiguration(array ( + 'dsn' => 'mysql:host=develop.digitalmediauconn.org;port=3306;dbname=foodbank', + 'user' => 'foodbank', + 'password' => 'foodbank123', + 'settings' => + array ( + 'charset' => 'utf8', + 'queries' => + array ( + ), + ), + 'classname' => '\\Propel\\Runtime\\Connection\\ConnectionWrapper', + 'model_paths' => + array ( + 0 => 'src', + 1 => 'vendor', + ), +)); +$manager->setName('default'); +$serviceContainer->setConnectionManager('default', $manager); +$serviceContainer->setDefaultDatasource('default'); \ No newline at end of file diff --git a/api/generated-sql/default.sql b/api/generated-sql/default.sql new file mode 100644 index 0000000..1dd54e8 --- /dev/null +++ b/api/generated-sql/default.sql @@ -0,0 +1,131 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +-- --------------------------------------------------------------------- +-- Category +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Category`; + +CREATE TABLE `Category` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(128) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- Category_Rank_Nutrient +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Category_Rank_Nutrient`; + +CREATE TABLE `Category_Rank_Nutrient` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `units` VARCHAR(128), + `threshold` FLOAT NOT NULL, + `operator` VARCHAR(10) NOT NULL, + `category_id` INTEGER NOT NULL, + `rank_id` INTEGER NOT NULL, + `nutrient_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `category_id` (`category_id`), + INDEX `rank_id` (`rank_id`), + INDEX `nutrient_id` (`nutrient_id`), + CONSTRAINT `Category_Rank_Nutrient_ibfk_3` + FOREIGN KEY (`nutrient_id`) + REFERENCES `Nutrient` (`id`) + ON UPDATE CASCADE + ON DELETE CASCADE, + CONSTRAINT `Category_Rank_Nutrient_ibfk_1` + FOREIGN KEY (`category_id`) + REFERENCES `Category` (`id`) + ON UPDATE CASCADE + ON DELETE CASCADE, + CONSTRAINT `Category_Rank_Nutrient_ibfk_2` + FOREIGN KEY (`rank_id`) + REFERENCES `Rank` (`id`) + ON UPDATE CASCADE + ON DELETE CASCADE +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- Food +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Food`; + +CREATE TABLE `Food` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `barcode` INTEGER NOT NULL, + `rank_id` INTEGER, + `category_id` INTEGER, + PRIMARY KEY (`id`), + UNIQUE INDEX `barcode` (`barcode`), + INDEX `rank_id` (`rank_id`, `category_id`), + INDEX `category_id` (`category_id`), + CONSTRAINT `Food_ibfk_1` + FOREIGN KEY (`category_id`) + REFERENCES `Category` (`id`) + ON UPDATE CASCADE + ON DELETE SET NULL, + CONSTRAINT `Parent Rank ID` + FOREIGN KEY (`rank_id`) + REFERENCES `Rank` (`id`) + ON UPDATE CASCADE + ON DELETE SET NULL +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- Nutrient +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Nutrient`; + +CREATE TABLE `Nutrient` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- Rank +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Rank`; + +CREATE TABLE `Rank` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(128) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- --------------------------------------------------------------------- +-- Subcategory +-- --------------------------------------------------------------------- + +DROP TABLE IF EXISTS `Subcategory`; + +CREATE TABLE `Subcategory` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `category_id` INTEGER, + PRIMARY KEY (`id`), + INDEX `category_id` (`category_id`), + CONSTRAINT `Parent Category ID` + FOREIGN KEY (`category_id`) + REFERENCES `Category` (`id`) + ON UPDATE CASCADE + ON DELETE SET NULL +) ENGINE=InnoDB; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/api/generated-sql/sqldb.map b/api/generated-sql/sqldb.map new file mode 100644 index 0000000..67bc4d4 --- /dev/null +++ b/api/generated-sql/sqldb.map @@ -0,0 +1,2 @@ +# Sqlfile -> Database map +default.sql=default diff --git a/api/index.php b/api/index.php new file mode 100644 index 0000000..ee8530e --- /dev/null +++ b/api/index.php @@ -0,0 +1,17 @@ +add('', __DIR__ . '/generated-classes/'); // Propel ORM Classes +require './generated-conf/config.php'; // Propel Config +require './config.php'; // Slim Config + +// Init Slim +$app = new \Slim\App($config); + +/** + * Routes + */ +require './routes/category.php'; + +// Run App +$app->run(); \ No newline at end of file diff --git a/api/propel.yml b/api/propel.yml new file mode 100644 index 0000000..c305b3e --- /dev/null +++ b/api/propel.yml @@ -0,0 +1,10 @@ +propel: + database: + connections: + default: + adapter: mysql + dsn: mysql:host=develop.digitalmediauconn.org;port=3306;dbname=foodbank + user: foodbank + password: foodbank123 + settings: + charset: utf8mb4_unicode_ci diff --git a/api/propel.yml.dist b/api/propel.yml.dist new file mode 100644 index 0000000..1a6809d --- /dev/null +++ b/api/propel.yml.dist @@ -0,0 +1,25 @@ +# When you're part of a team, you could want to define a common configuration file and commit it into your VCS. But, of +# course, there can be some properties you don't want to share, e.g. database passwords. Propel helps you and looks for +# a propel.yml.dist file too, merging its properties with propel.yml ones. So you can define shared configuration +# properties in propel.yml.dist, committing it in your VCS, and keep propel.yml as private. The properties loaded from +# propel.yml overwrite the ones with the same name, loaded from propel.yml.dist. +# +# For a complete references see: http://propelorm.org/documentation/reference/configuration-file.html + +propel: + paths: + # The directory where Propel expects to find your `schema.xml` file. + schemaDir: /Users/brian/Documents/Sites/foodbank/api + + # The directory where Propel should output generated object model classes. + phpDir: /Users/brian/Documents/Sites/foodbank/api + +# database: +# connections: +# default: +# adapter: mysql +# dsn: mysql:host=develop.digitalmediauconn.org;port=3306;dbname=foodbank +# user: foodbank +# password: +# settings: +# charset: utf8mb4_unicode_ci diff --git a/api/routes/category.php b/api/routes/category.php new file mode 100644 index 0000000..6a344a0 --- /dev/null +++ b/api/routes/category.php @@ -0,0 +1,25 @@ +get('/category/all', function( $request, $response ) { + $q = new CategoryQuery; + $cats = $q::create()->find(); + $response_json = [ + "status" => [ + "code" => $response->getStatusCode(), + "message" => "OK" + ], + "data" => [] + ]; + foreach( $cats as $cat ) { + $response_json["data"][] = [ + "id" => $cat->getId(), + "name" => $cat->getName() + ]; + } + $response = $response->withJSON($response_json); + return $response; +}); \ No newline at end of file diff --git a/api/schema.xml b/api/schema.xml new file mode 100644 index 0000000..099723a --- /dev/null +++ b/api/schema.xml @@ -0,0 +1,94 @@ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/app.js b/app/app.js new file mode 100644 index 0000000..f176306 --- /dev/null +++ b/app/app.js @@ -0,0 +1,4 @@ +var app = angular.module('app', ['ngRoute']); + +// Root controllers in /root/ folder +// Page controllers in /pages/[your-page] folder diff --git a/app/app.route.js b/app/app.route.js new file mode 100644 index 0000000..2dbcd17 --- /dev/null +++ b/app/app.route.js @@ -0,0 +1,48 @@ +app.config( function ($routeProvider, $locationProvider) { + $routeProvider + .when('/', { + templateUrl: 'app/pages/food/view.html', + controller: 'FoodCtrl' + }) + + .when('/login', { + templateUrl: 'app/pages/login/view.html', + controller: 'LoginCtrl' + }) + + .when('/categories', { + templateUrl: 'app/pages/categories/view.html', + controller: 'CategoryCtrl' + }) + + .when('/food', { + templateUrl: 'app/pages/food/view.html', + controller: 'FoodCtrl' + }) + + // Sandbox Demo + .when('/news', { + templateUrl: 'app/sandbox/news.html', + controller: 'NewsCtrl' + }) + + // Sandbox Demo + .when('/competitions', { + templateUrl: 'app/sandbox/competition.html', + controller: 'CompetitionCtrl' + }) + + // Sandbox Demo + .when('/todo', { + templateUrl: 'app/sandbox/todo.html', + controller: 'TodoCtrl' + }) + + // 404 Not Found + .otherwise({ + templateUrl: 'app/pages/404/view.html', + controller: '404Ctrl' + }); + + // $locationProvider.html5Mode(true); +}); diff --git a/app/pages/404/ctrl.js b/app/pages/404/ctrl.js new file mode 100644 index 0000000..ced7d2d --- /dev/null +++ b/app/pages/404/ctrl.js @@ -0,0 +1,7 @@ +app.controller('404Ctrl', ['$scope', function ($scope) { + $scope.page.title = '404'; + $scope.page.id = '404'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); diff --git a/app/pages/404/style.styl b/app/pages/404/style.styl new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/404/view.html b/app/pages/404/view.html new file mode 100644 index 0000000..640e8c2 --- /dev/null +++ b/app/pages/404/view.html @@ -0,0 +1,2 @@ +
+

You've reached pages/404/view.html by going to an invalid link.

diff --git a/app/pages/categories/anotherCtrl.js b/app/pages/categories/anotherCtrl.js new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/categories/ctrl.js b/app/pages/categories/ctrl.js new file mode 100644 index 0000000..38bbe26 --- /dev/null +++ b/app/pages/categories/ctrl.js @@ -0,0 +1,7 @@ +app.controller('CategoryCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Categories'; + $scope.page.id = 'cat'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); diff --git a/app/pages/categories/style.styl b/app/pages/categories/style.styl new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/categories/view.html b/app/pages/categories/view.html new file mode 100644 index 0000000..0481886 --- /dev/null +++ b/app/pages/categories/view.html @@ -0,0 +1,2 @@ +
+

You've reached pages/categories/view.html.

diff --git a/app/pages/food/anotherCtrl.js b/app/pages/food/anotherCtrl.js new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/food/ctrl.js b/app/pages/food/ctrl.js new file mode 100644 index 0000000..199a701 --- /dev/null +++ b/app/pages/food/ctrl.js @@ -0,0 +1,7 @@ +app.controller('FoodCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Food'; + $scope.page.id = 'food'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); diff --git a/app/pages/food/style.styl b/app/pages/food/style.styl new file mode 100644 index 0000000..a07d8f3 --- /dev/null +++ b/app/pages/food/style.styl @@ -0,0 +1,141 @@ +.food-search + padding-top: .5em + i + cursor: pointer + top: 6px + right: 0 + &:hover + color: #888 + transform: scale(.9) + transition: all .2s + .input-field label.active + transform: translateY(-120%) + .input-field.col label + left: 0 + +.food-filter + display: flex + flex-flow: row wrap + width: 100% + padding: 0 1em + .block + flex: 1 500px + padding: 0 1em + &:last-child + flex: 0 130px + nav + box-shadow: none + display: flex + align-items: center + justify-content: center + nav + background-color: lightergray + a + color: black + +.green[type="checkbox"].filled-in:checked+label:after + border-color: green + background-color: green +.yellow[type="checkbox"].filled-in:checked+label:after + border-color: yellow + background-color: yellow +.red[type="checkbox"].filled-in:checked+label:after + border-color: red + background-color: red +[type="checkbox"]+label + padding-left: 26px + +.foods + display: flex + padding: 3em + flex-wrap: wrap + + .card-panel + flex-grow: 1 + display: flex + padding: 0 + margin: .5em + align-items: center + cursor: pointer + transition: all .2s + &:hover + transform: scale(.95) + .health + background-color: green + width: 3em + min-width: @width + min-height: @width + height: 100% + display: flex + align-items: center + justify-content: center + i + color: white + h5 + font-size: 1.4em + margin: .3em .7em + + // "Add new food" button + &.add + background-color: blue + color: white + +above(500px) + max-width: 17em + i + font-size: 2.5em + .health + background-color: alpha(black, .27) + + + +.food-crud + font-size: 1.1em + padding: 1em + border: 1px solid lightgray + my-box-shadow() + background: white + [type="radio"]:not(:checked)+label, [type="radio"]:checked+label + padding-left: 1.7em + padding-right: 1em + .grade + margin-bottom: 2em + h4 + margin: 5px 0 25px 0 + p + font-size: 1.1em + font-weight: 500 + color: #BBB + margin-bottom: 5px + a.btn + width: 48% + .orange + float: right + + .nutrition + margin-bottom: 1.5em + td + padding: .5em 5px + td:first-child + font-weight: 500 + width: 50% + + + +.modal_ .editContent + display: none +.modal_.editMode .editContent + display: inline + +.modal_ + align-items: center + justify-content: center + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ diff --git a/app/pages/food/view.html b/app/pages/food/view.html new file mode 100644 index 0000000..b81a390 --- /dev/null +++ b/app/pages/food/view.html @@ -0,0 +1,185 @@ + + + + +
+ +
+
By Category
+ +
+ + +
+
By Nutrient
+ +
+ +
+
By Grade
+ +
+ +
+ + + +
+ +
+
+ add +
+
Add new food
+
+ +
+
+ favorite +
+
{{n}}
+
+ +
+ + + + + + + + diff --git a/app/pages/login/anotherCtrl.js b/app/pages/login/anotherCtrl.js new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/login/ctrl.js b/app/pages/login/ctrl.js new file mode 100644 index 0000000..c8daf8f --- /dev/null +++ b/app/pages/login/ctrl.js @@ -0,0 +1,40 @@ +app.controller('LoginCtrl', ['$scope', 'loginService', function ($scope, loginService) { + $scope.page.title = 'Login'; + $scope.page.id = 'login'; + $scope.page.yourVar = "globalStuff"; + + $scope.selected = { + username: "", + password: "" + }; + + $scope.loginAttempt = { + username: "", + password: "", + attempt: false, + login: false + }; + + $scope.loginService = loginService; + + $scope.login = function( username, password ) { + $scope.loginAttempt.username = username; + $scope.loginAttempt.password = password; + $scope.loginAttempt.attempt = true; + // Sanitize? Pre-check? + console.log($scope.loginService); + $scope.loginService.login( username, password ).then(function(response) { + console.log(response); + // Mock the fact that this takes longer + setTimeout(function() { + $scope.$apply(function() { + $scope.loginAttempt.login = response.login; + $scope.loginAttempt.attempt = false; + }); + }, 1000); + }, function(error) { + console.error(error); + }); + }; + +}]); diff --git a/app/pages/login/example.json b/app/pages/login/example.json new file mode 100644 index 0000000..79fcf88 --- /dev/null +++ b/app/pages/login/example.json @@ -0,0 +1,4 @@ +{ + "message": "ok", + "login": true +} \ No newline at end of file diff --git a/app/pages/login/loginService.js b/app/pages/login/loginService.js new file mode 100644 index 0000000..a415c3e --- /dev/null +++ b/app/pages/login/loginService.js @@ -0,0 +1,11 @@ +app.factory('loginService', ['$http', function($http) { + return { + login: function( username, password ) { + return $http.get('/app/pages/login/example.json').then(function(response) { + return response.data; + }, function(error) { + return error; + }); + } + }; +}]); \ No newline at end of file diff --git a/app/pages/login/style.styl b/app/pages/login/style.styl new file mode 100644 index 0000000..e69de29 diff --git a/app/pages/login/view.html b/app/pages/login/view.html new file mode 100644 index 0000000..4bcccae --- /dev/null +++ b/app/pages/login/view.html @@ -0,0 +1,60 @@ +
+
+
+
+
+
+
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ done +
+
+ + +
{{ selected | json }}
+
{{ loginAttempt | json }}
+
+
+
\ No newline at end of file diff --git a/app/root/_footer.kit b/app/root/_footer.kit new file mode 100644 index 0000000..84777ec --- /dev/null +++ b/app/root/_footer.kit @@ -0,0 +1,6 @@ + + diff --git a/app/root/_header.kit b/app/root/_header.kit new file mode 100644 index 0000000..2ed1062 --- /dev/null +++ b/app/root/_header.kit @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/root/_nav.kit b/app/root/_nav.kit new file mode 100644 index 0000000..5d5f290 --- /dev/null +++ b/app/root/_nav.kit @@ -0,0 +1,72 @@ + + + + + + + + + + + diff --git a/app/root/index.kit b/app/root/index.kit new file mode 100644 index 0000000..55ae8e6 --- /dev/null +++ b/app/root/index.kit @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/root/root-ctrl.js b/app/root/root-ctrl.js new file mode 100644 index 0000000..c3beffd --- /dev/null +++ b/app/root/root-ctrl.js @@ -0,0 +1,18 @@ +app.controller('root', ['$scope', '$location', function ($scope, $location) { + + $scope.$watch('page', function () { + $scope.title = $scope.page.title + ' | F2E'; + }, true); + + $scope.page = { + 'title' : 'Root', + 'id' : 'root', + 'blackNav' : false + }; + + $scope.loop = ['Apple Pie','Bananas','Peas','Newman\'s Own Oil and Vinegar Dressing','Cucumber Salad','Kraft Macaroni and Cheese','Some food','Some more food','Some junk food','Some healthy food']; + + $scope.go = function ( path ) { + $location.path( path ); + }; +}]); diff --git a/app/root/root.styl b/app/root/root.styl new file mode 100644 index 0000000..e16f515 --- /dev/null +++ b/app/root/root.styl @@ -0,0 +1,67 @@ +/* +Table of Contents: + Spacer + Main Nav + Footer +*/ + + +.spacer + height: 80px + +// Main Nav +.nav-main + display: flex + justify-content: space-between + color: white + // position: fixed + top: 0 + height: navh = 4.5em + width: 100% + z-index: 10 + // &.scroll, &.scrollStuck + background-color: rgba(0,0,0,.8) + + .left-nav + display: flex + height: navh + align-items: center + * {display: inline} + i + font-size: 3.5rem + margin: 0 .15em 0 .1em + h4 + font-size: 2.6rem + font-weight: 500 + margin: 0 + + .right-nav + display: flex + align-items: center + + a.btn + padding: 0 + min-width: 7em + width: 10em + margin-right: 1em + &.blue {margin-left: 1em} + + .tabs + height: auto + min-width: 27em // adjust this to make the white bar work + .tab + height: navh + line-height: navh + .indicator + background-color: white + top: 0 + height: 5px + +// Footer +footer + display: flex + align-items: center + justify-content: center + padding: 2em + * + margin: 0 1em diff --git a/app/sandbox/competition.html b/app/sandbox/competition.html new file mode 100644 index 0000000..db77b32 --- /dev/null +++ b/app/sandbox/competition.html @@ -0,0 +1,29 @@ +
+
+
+
+ Card Title +
+
+ +
+
+
+ Card Title +
+
+ +
+
+
+ Card Title +
+
+ +
+
+
+ Card Title +
+
+
diff --git a/app/sandbox/ctrl.js b/app/sandbox/ctrl.js new file mode 100644 index 0000000..b5aad9c --- /dev/null +++ b/app/sandbox/ctrl.js @@ -0,0 +1,27 @@ +app.controller('NewsCtrl', ['$scope', function ($scope) { + $scope.page.title = 'News'; + $scope.page.id = 'news'; + $scope.page.blackNav = false; +}]); + +app.controller('CompetitionCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Competitions'; + $scope.page.id = 'comps'; + $scope.page.blackNav = true; +}]); + +app.controller('TodoCtrl', ['$scope', function ($scope) { + $scope.todos = [ + { name: 'Master HTML/CSS/Javascript', completed: true }, + { name: 'Learn AngularJS', completed: false }, + { name: 'Build NodeJS backend', completed: false }, + { name: 'Get started with ExpressJS', completed: false }, + { name: 'Setup MongoDB database', completed: false }, + { name: 'Be awesome!', completed: false }, + ]; +}]); + +app.controller('EmailController', ['$scope', function ($scope) { + $scope.name = "Gabe"; + $scope.email = "rogangabe@gmail.com"; +}]); diff --git a/app/sandbox/email.html b/app/sandbox/email.html new file mode 100644 index 0000000..57fdd99 --- /dev/null +++ b/app/sandbox/email.html @@ -0,0 +1,17 @@ + +
+
+
+
+ account_circle + + +
+
+ phone + + +
+
+
+
diff --git a/app/sandbox/news.html b/app/sandbox/news.html new file mode 100644 index 0000000..89a9b69 --- /dev/null +++ b/app/sandbox/news.html @@ -0,0 +1,38 @@ + +
+ + + +
+ +
+

The "How it works" section is a work in progress.

+
+ +
+
+ account_circle + Featured User +
+
+
+
+

Firstname Lastname

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Make sure this is the right length!

+ +
+
+
+ +
+
+
+ library_books + News +
+
+
Topic here
+

Title here

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+
+
diff --git a/app/sandbox/scrap.html b/app/sandbox/scrap.html new file mode 100644 index 0000000..0f5f52a --- /dev/null +++ b/app/sandbox/scrap.html @@ -0,0 +1,3 @@ + diff --git a/app/sandbox/todo.html b/app/sandbox/todo.html new file mode 100644 index 0000000..ff59f18 --- /dev/null +++ b/app/sandbox/todo.html @@ -0,0 +1,7 @@ + + diff --git a/app/sandbox/whatever.styl b/app/sandbox/whatever.styl new file mode 100644 index 0000000..ce8e37a --- /dev/null +++ b/app/sandbox/whatever.styl @@ -0,0 +1,119 @@ +/* +Table of Contents: + Hero + How it works + Header buttons + News + Featured User + --Competition page +*/ + + +// Hero +.hero + height: 70vh + background-size: cover + + +// How it works +.howItWorks + background-color: #eee + margin: 0 + padding: 1em + + +// Header buttons +header.label + cursor: auto + color: white + font-size: 1.5em + position: absolute + left: -.3em + background-color: #bbb + &:hover // materialize fix + my-box-shadow() + background-color: #bbb + i + font-size: 1em + display: inline-flex + vertical-align: -5% + +// News +.newsFeed article + display: flex + flex-direction: column + align-items: center + padding-bottom: 5em + h4, h5 + text-align: center + * + width: 65% + + +// Featured User +.featuredUser + // Desktop + +above(700px) + margin-bottom: 2em + article + align-items: center + display: flex + flex-wrap: wrap + justify-content: center + margin: 1.5em 1em + +above(1200px) + margin: 3em auto + max-width: 1200px + .left + flex: 1 35% + padding: 0 25px + text-align: center + img + width: 100% + max-width: 30em + min-width: 15em + border-radius: 800px + .right + flex: 1 60% + padding: 0 2vw + h1 + font-size: 5vw + margin: 0 0 1rem 0 + +above(1200px) + .right h1 {font-size: 60px} + + // Mobile + +below(700px) + margin-bottom: .8em + article + display: flex + align-items: center + justify-content: center + margin: 1em 1em 1.5em 1em + .left + img + width: 10em + border-radius: 800px + .right + margin-left: 5vw + h1 + font-size: 2em + margin: 0 0 1rem 0 + p + display: none + + + + +.competition-cards + display: flex + flex-flow: row wrap + justify-content: space-around + padding: 6em 2em + .card.small + flex: 0 400px + height: auto + margin: 1.5em .5em + .img + height: 200px + background-size: cover diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..6af37ad --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,389 @@ +a { + cursor: pointer; +} +.show { + display: block !important; +} +::-webkit-scrollbar { + display: none; +} +[ng:cloak], +[ng-cloak], +[data-ng-cloak], +[x-ng-cloak], +.ng-cloak, +.x-ng-cloak { + display: none !important; +} +.input-field .prefix ~ input, +.input-field .prefix ~ textarea, +.input-field .prefix ~ label, +.input-field .prefix ~ .validate ~ label, +.input-field .prefix ~ .autocomplete-content { + margin-left: 0; + width: 100%; + position: absolute; +} +ul.tabs { + background: none; +} +ul.tabs .tab a { + color: inherit; +} +ul.tabs .tab a:hover { + color: inherit; +} +.food-search { + padding-top: 0.5em; +} +.food-search i { + cursor: pointer; + top: 6px; + right: 0; +} +.food-search i:hover { + color: #888; + transform: scale(0.9); + transition: all 0.2s; +} +.food-search .input-field label.active { + transform: translateY(-120%); +} +.food-search .input-field.col label { + left: 0; +} +.food-filter { + display: flex; + flex-flow: row wrap; + width: 100%; + padding: 0 1em; +} +.food-filter .block { + flex: 1 500px; + padding: 0 1em; +} +.food-filter .block:last-child { + flex: 0 130px; +} +.food-filter .block:last-child nav { + box-shadow: none; + display: flex; + align-items: center; + justify-content: center; +} +.food-filter nav { + background-color: #f5f5f5; +} +.food-filter nav a { + color: #000; +} +.green[type="checkbox"].filled-in:checked+label:after { + border-color: #7ae076; + background-color: #7ae076; +} +.yellow[type="checkbox"].filled-in:checked+label:after { + border-color: #fddf7b; + background-color: #fddf7b; +} +.red[type="checkbox"].filled-in:checked+label:after { + border-color: #fd7b7b; + background-color: #fd7b7b; +} +[type="checkbox"]+label { + padding-left: 26px; +} +.foods { + display: flex; + padding: 3em; + flex-wrap: wrap; +} +.foods .card-panel { + flex-grow: 1; + display: flex; + padding: 0; + margin: 0.5em; + align-items: center; + cursor: pointer; + transition: all 0.2s; +} +.foods .card-panel:hover { + transform: scale(0.95); +} +.foods .card-panel .health { + background-color: #7ae076; + width: 3em; + min-width: 3em; + min-height: 3em; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} +.foods .card-panel .health i { + color: #fff; +} +.foods .card-panel h5 { + font-size: 1.4em; + margin: 0.3em 0.7em; +} +.foods .card-panel.add { + background-color: #4ba8f8; + color: #fff; +} +@media all and (min-width: 500px) { + .foods .card-panel.add { + max-width: 17em; + } +} +.foods .card-panel.add i { + font-size: 2.5em; +} +.foods .card-panel.add .health { + background-color: rgba(0,0,0,0.27); +} +.food-crud { + font-size: 1.1em; + padding: 1em; + border: 1px solid #f0f0f0; + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); + background: #fff; +} +.food-crud [type="radio"]:not(:checked)+label, +.food-crud [type="radio"]:checked+label { + padding-left: 1.7em; + padding-right: 1em; +} +.food-crud .grade { + margin-bottom: 2em; +} +.food-crud h4 { + margin: 5px 0 25px 0; +} +.food-crud p { + font-size: 1.1em; + font-weight: 500; + color: #bbb; + margin-bottom: 5px; +} +.food-crud a.btn { + width: 48%; +} +.food-crud .orange { + float: right; +} +.food-crud .nutrition { + margin-bottom: 1.5em; +} +.food-crud .nutrition td { + padding: 0.5em 5px; +} +.food-crud .nutrition td:first-child { + font-weight: 500; + width: 50%; +} +.modal_ .editContent { + display: none; +} +.modal_.editMode .editContent { + display: inline; +} +.modal_ { + align-items: center; + justify-content: center; + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: #000; /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} +.spacer { + height: 80px; +} +.nav-main { + display: flex; + justify-content: space-between; + color: #fff; + top: 0; + height: 4.5em; + width: 100%; + z-index: 10; + background-color: rgba(0,0,0,0.8); +} +.nav-main .left-nav { + display: flex; + height: 4.5em; + align-items: center; +} +.nav-main .left-nav * { + display: inline; +} +.nav-main .left-nav i { + font-size: 3.5rem; + margin: 0 0.15em 0 0.1em; +} +.nav-main .left-nav h4 { + font-size: 2.6rem; + font-weight: 500; + margin: 0; +} +.nav-main .right-nav { + display: flex; + align-items: center; +} +.nav-main a.btn { + padding: 0; + min-width: 7em; + width: 10em; + margin-right: 1em; +} +.nav-main a.btn.blue { + margin-left: 1em; +} +.nav-main .tabs { + height: auto; + min-width: 27em; +} +.nav-main .tabs .tab { + height: 4.5em; + line-height: 4.5em; +} +.nav-main .tabs .indicator { + background-color: #fff; + top: 0; + height: 5px; +} +footer { + display: flex; + align-items: center; + justify-content: center; + padding: 2em; +} +footer * { + margin: 0 1em; +} +.hero { + height: 70vh; + background-size: cover; +} +.howItWorks { + background-color: #eee; + margin: 0; + padding: 1em; +} +header.label { + cursor: auto; + color: #fff; + font-size: 1.5em; + position: absolute; + left: -0.3em; + background-color: #bbb; +} +header.label:hover { + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12); + background-color: #bbb; +} +header.label i { + font-size: 1em; + display: inline-flex; + vertical-align: -5%; +} +.newsFeed article { + display: flex; + flex-direction: column; + align-items: center; + padding-bottom: 5em; +} +.newsFeed article h4, +.newsFeed article h5 { + text-align: center; +} +.newsFeed article * { + width: 65%; +} +@media all and (min-width: 700px) { + .featuredUser { + margin-bottom: 2em; + } + .featuredUser article { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: 1.5em 1em; + } + .featuredUser .left { + flex: 1 35%; + padding: 0 25px; + text-align: center; + } + .featuredUser .left img { + width: 100%; + max-width: 30em; + min-width: 15em; + border-radius: 800px; + } + .featuredUser .right { + flex: 1 60%; + padding: 0 2vw; + } + .featuredUser .right h1 { + font-size: 5vw; + margin: 0 0 1rem 0; + } +} +@media all and (max-width: 699px) { + .featuredUser { + margin-bottom: 0.8em; + } + .featuredUser article { + display: flex; + align-items: center; + justify-content: center; + margin: 1em 1em 1.5em 1em; + } + .featuredUser article .left img { + width: 10em; + border-radius: 800px; + } + .featuredUser article .right { + margin-left: 5vw; + } + .featuredUser article .right h1 { + font-size: 2em; + margin: 0 0 1rem 0; + } + .featuredUser article .right p { + display: none; + } +} +@media all and (min-width: 700px) and (min-width: 1200px) { + .featuredUser article { + margin: 3em auto; + max-width: 1200px; + } +} +@media all and (min-width: 700px) and (min-width: 1200px) { + .featuredUser .right h1 { + font-size: 60px; + } +} +.competition-cards { + display: flex; + flex-flow: row wrap; + justify-content: space-around; + padding: 6em 2em; +} +.competition-cards .card.small { + flex: 0 400px; + height: auto; + margin: 1.5em 0.5em; +} +.competition-cards .card.small .img { + height: 200px; + background-size: cover; +} diff --git a/assets/img/gabe.jpg b/assets/img/gabe.jpg new file mode 100644 index 0000000..ad29f7b Binary files /dev/null and b/assets/img/gabe.jpg differ diff --git a/assets/img/landscape.jpg b/assets/img/landscape.jpg new file mode 100644 index 0000000..6fe2c96 Binary files /dev/null and b/assets/img/landscape.jpg differ diff --git a/assets/img/office.jpg b/assets/img/office.jpg new file mode 100644 index 0000000..67e78fc Binary files /dev/null and b/assets/img/office.jpg differ diff --git a/assets/js/bundle.js b/assets/js/bundle.js new file mode 100644 index 0000000..632e994 --- /dev/null +++ b/assets/js/bundle.js @@ -0,0 +1,180 @@ +var app = angular.module('app', ['ngRoute']); + +// Root controllers in /root/ folder +// Page controllers in /pages/[your-page] folder + +app.config( function ($routeProvider, $locationProvider) { + $routeProvider + .when('/', { + templateUrl: 'app/pages/food/view.html', + controller: 'FoodCtrl' + }) + + .when('/login', { + templateUrl: 'app/pages/login/view.html', + controller: 'LoginCtrl' + }) + + .when('/categories', { + templateUrl: 'app/pages/categories/view.html', + controller: 'CategoryCtrl' + }) + + .when('/food', { + templateUrl: 'app/pages/food/view.html', + controller: 'FoodCtrl' + }) + + // Sandbox Demo + .when('/news', { + templateUrl: 'app/sandbox/news.html', + controller: 'NewsCtrl' + }) + + // Sandbox Demo + .when('/competitions', { + templateUrl: 'app/sandbox/competition.html', + controller: 'CompetitionCtrl' + }) + + // Sandbox Demo + .when('/todo', { + templateUrl: 'app/sandbox/todo.html', + controller: 'TodoCtrl' + }) + + // 404 Not Found + .otherwise({ + templateUrl: 'app/pages/404/view.html', + controller: '404Ctrl' + }); + + // $locationProvider.html5Mode(true); +}); + +app.controller('root', ['$scope', '$location', function ($scope, $location) { + + $scope.$watch('page', function () { + $scope.title = $scope.page.title + ' | F2E'; + }, true); + + $scope.page = { + 'title' : 'Root', + 'id' : 'root', + 'blackNav' : false + }; + + $scope.loop = ['Apple Pie','Bananas','Peas','Newman\'s Own Oil and Vinegar Dressing','Cucumber Salad','Kraft Macaroni and Cheese','Some food','Some more food','Some junk food','Some healthy food']; + + $scope.go = function ( path ) { + $location.path( path ); + }; +}]); + +app.controller('NewsCtrl', ['$scope', function ($scope) { + $scope.page.title = 'News'; + $scope.page.id = 'news'; + $scope.page.blackNav = false; +}]); + +app.controller('CompetitionCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Competitions'; + $scope.page.id = 'comps'; + $scope.page.blackNav = true; +}]); + +app.controller('TodoCtrl', ['$scope', function ($scope) { + $scope.todos = [ + { name: 'Master HTML/CSS/Javascript', completed: true }, + { name: 'Learn AngularJS', completed: false }, + { name: 'Build NodeJS backend', completed: false }, + { name: 'Get started with ExpressJS', completed: false }, + { name: 'Setup MongoDB database', completed: false }, + { name: 'Be awesome!', completed: false }, + ]; +}]); + +app.controller('EmailController', ['$scope', function ($scope) { + $scope.name = "Gabe"; + $scope.email = "rogangabe@gmail.com"; +}]); + +app.controller('404Ctrl', ['$scope', function ($scope) { + $scope.page.title = '404'; + $scope.page.id = '404'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); + + +app.controller('CategoryCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Categories'; + $scope.page.id = 'cat'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); + + +app.controller('FoodCtrl', ['$scope', function ($scope) { + $scope.page.title = 'Food'; + $scope.page.id = 'food'; + $scope.page.yourVar = "globalStuff"; + + $scope.var2 = "localStuff"; +}]); + + +app.controller('LoginCtrl', ['$scope', 'loginService', function ($scope, loginService) { + $scope.page.title = 'Login'; + $scope.page.id = 'login'; + $scope.page.yourVar = "globalStuff"; + + $scope.selected = { + username: "", + password: "" + }; + + $scope.loginAttempt = { + username: "", + password: "", + attempt: false, + login: false + }; + + $scope.loginService = loginService; + + $scope.login = function( username, password ) { + $scope.loginAttempt.username = username; + $scope.loginAttempt.password = password; + $scope.loginAttempt.attempt = true; + // Sanitize? Pre-check? + console.log($scope.loginService); + $scope.loginService.login( username, password ).then(function(response) { + console.log(response); + // Mock the fact that this takes longer + setTimeout(function() { + $scope.$apply(function() { + $scope.loginAttempt.login = response.login; + $scope.loginAttempt.attempt = false; + }); + }, 1000); + }, function(error) { + console.error(error); + }); + }; + +}]); + +app.factory('loginService', ['$http', function($http) { + return { + login: function( username, password ) { + return $http.get('/app/pages/login/example.json').then(function(response) { + return response.data; + }, function(error) { + return error; + }); + } + }; +}]); \ No newline at end of file diff --git a/assets/js/flowtype.js b/assets/js/flowtype.js new file mode 100644 index 0000000..687b033 --- /dev/null +++ b/assets/js/flowtype.js @@ -0,0 +1,49 @@ + +/* +* FlowType.JS v1.1 +* Copyright 2013-2014, Simple Focus http://simplefocus.com/ +* +* FlowType.JS by Simple Focus (http://simplefocus.com/) +* is licensed under the MIT License. Read a copy of the +* license in the LICENSE.txt file or at +* http://choosealicense.com/licenses/mit +* +* Thanks to Giovanni Difeterici (http://www.gdifeterici.com/) +*/ + +(function($) { + $.fn.flowtype = function(options) { + +// Establish default settings/variables +// ==================================== + var settings = $.extend({ + maximum : 9999, + minimum : 1, + maxFont : 9999, + minFont : 1, + fontRatio : 35 + }, options), + +// Do the magic math +// ================= + changes = function(el) { + var $el = $(el), + elw = $el.width(), + width = elw > settings.maximum ? settings.maximum : elw < settings.minimum ? settings.minimum : elw, + fontBase = width / settings.fontRatio, + fontSize = fontBase > settings.maxFont ? settings.maxFont : fontBase < settings.minFont ? settings.minFont : fontBase; + $el.css('font-size', fontSize + 'px'); + }; + +// Make the magic visible +// ====================== + return this.each(function() { + // Context for resize callback + var that = this; + // Make changes upon resize + $(window).resize(function(){changes(that);}); + // Set changes on load + changes(this); + }); + }; +}(jQuery)); diff --git a/assets/js/materialize.js b/assets/js/materialize.js new file mode 100644 index 0000000..7a3313d --- /dev/null +++ b/assets/js/materialize.js @@ -0,0 +1,7614 @@ +/*! + * Materialize v0.97.8 (http://materializecss.com) + * Copyright 2014-2015 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +// Check for jQuery. +if (typeof(jQuery) === 'undefined') { + var jQuery; + // Check if require is a defined function. + if (typeof(require) === 'function') { + jQuery = $ = require('jquery'); + // Else use the dollar sign alias. + } else { + jQuery = $; + } +} +;/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright © 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +jQuery.easing['jswing'] = jQuery.easing['swing']; + +jQuery.extend( jQuery.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert(jQuery.easing.default); + return jQuery.easing[jQuery.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright © 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */; // Custom Easing + jQuery.extend( jQuery.easing, + { + easeInOutMaterial: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return c/4*((t-=2)*t*t + 2) + b; + } + }); + +;/*! VelocityJS.org (1.2.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ +/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ +/*! Note that this has been modified by Materialize to confirm that Velocity is not already being imported. */ +jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(e){function t(e){var t=e.length,a=r.type(e);return"function"===a||r.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===a||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;ln;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;cO;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)})); +;!function(a,b,c,d){"use strict";function k(a,b,c){return setTimeout(q(a,c),b)}function l(a,b,c){return Array.isArray(a)?(m(a,c[b],c),!0):!1}function m(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e-1}function x(a){return a.trim().split(/\s+/g)}function y(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function B(a,b){for(var c,f,g=b[0].toUpperCase()+b.slice(1),h=0;h1&&!c.firstMultiple?c.firstMultiple=gb(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=hb(d);b.timeStamp=j(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=lb(h,i),b.distance=kb(h,i),eb(c,b),b.offsetDirection=jb(b.deltaX,b.deltaY),b.scale=g?nb(g.pointers,d):1,b.rotation=g?mb(g.pointers,d):0,fb(c,b);var k=a.element;v(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function eb(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===O||f.eventType===Q)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function fb(a,b){var f,g,h,j,c=a.lastInterval||b,e=b.timeStamp-c.timeStamp;if(b.eventType!=R&&(e>N||c.velocity===d)){var k=c.deltaX-b.deltaX,l=c.deltaY-b.deltaY,m=ib(e,k,l);g=m.x,h=m.y,f=i(m.x)>i(m.y)?m.x:m.y,j=jb(k,l),a.lastInterval=b}else f=c.velocity,g=c.velocityX,h=c.velocityY,j=c.direction;b.velocity=f,b.velocityX=g,b.velocityY=h,b.direction=j}function gb(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:h(c/b),y:h(d/b)}}function ib(a,b,c){return{x:b/a||0,y:c/a||0}}function jb(a,b){return a===b?S:i(a)>=i(b)?a>0?T:U:b>0?V:W}function kb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function lb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function mb(a,b){return lb(b[1],b[0],_)-lb(a[1],a[0],_)}function nb(a,b){return kb(b[0],b[1],_)/kb(a[0],a[1],_)}function rb(){this.evEl=pb,this.evWin=qb,this.allow=!0,this.pressed=!1,ab.apply(this,arguments)}function wb(){this.evEl=ub,this.evWin=vb,ab.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function Ab(){this.evTarget=yb,this.evWin=zb,this.started=!1,ab.apply(this,arguments)}function Bb(a,b){var c=z(a.touches),d=z(a.changedTouches);return b&(Q|R)&&(c=A(c.concat(d),"identifier",!0)),[c,d]}function Eb(){this.evTarget=Db,this.targetIds={},ab.apply(this,arguments)}function Fb(a,b){var c=z(a.touches),d=this.targetIds;if(b&(O|P)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=z(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return v(a.target,i)}),b===O)for(e=0;eh&&(b.push(a),h=b.length-1):e&(Q|R)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var xb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},yb="touchstart",zb="touchstart touchmove touchend touchcancel";p(Ab,ab,{handler:function(a){var b=xb[a.type];if(b===O&&(this.started=!0),this.started){var c=Bb.call(this,a,b);b&(Q|R)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}});var Cb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},Db="touchstart touchmove touchend touchcancel";p(Eb,ab,{handler:function(a){var b=Cb[a.type],c=Fb.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}),p(Gb,ab,{handler:function(a,b,c){var d=c.pointerType==J,e=c.pointerType==L;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Q|R)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Hb=B(f.style,"touchAction"),Ib=Hb!==d,Jb="compute",Kb="auto",Lb="manipulation",Mb="none",Nb="pan-x",Ob="pan-y";Pb.prototype={set:function(a){a==Jb&&(a=this.compute()),Ib&&(this.manager.element.style[Hb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return m(this.manager.recognizers,function(b){r(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),Qb(a.join(" "))},preventDefaults:function(a){if(!Ib){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return b.preventDefault(),void 0;var d=this.actions,e=w(d,Mb),f=w(d,Ob),g=w(d,Nb);return e||f&&c&X||g&&c&Y?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var Rb=1,Sb=2,Tb=4,Ub=8,Vb=Ub,Wb=16,Xb=32;Yb.prototype={defaults:{},set:function(a){return n(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(l(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_b(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return l(a,"dropRecognizeWith",this)?this:(a=_b(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(l(a,"requireFailure",this))return this;var b=this.requireFail;return a=_b(a,this),-1===y(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(l(a,"dropRequireFailure",this))return this;a=_b(a,this);var b=y(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function d(d){b.manager.emit(b.options.event+(d?Zb(c):""),a)}var b=this,c=this.state;Ub>c&&d(!0),d(),c>=Ub&&d(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):(this.state=Xb,void 0)},canEmit:function(){for(var a=0;af?T:U,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?S:0>g?V:W,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return ac.prototype.attrTest.call(this,a)&&(this.state&Sb||!(this.state&Sb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),p(cc,ac,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&Sb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),p(dc,Yb,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[Kb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Q|R)&&!e)this.reset();else if(a.eventType&O)this.reset(),this._timer=k(function(){this.state=Vb,this.tryEmit()},b.time,this);else if(a.eventType&Q)return Vb;return Xb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===Vb&&(a&&a.eventType&Q?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=j(),this.manager.emit(this.options.event,this._input)))}}),p(ec,ac,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&Sb)}}),p(fc,ac,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:X|Y,pointers:1},getTouchAction:function(){return bc.prototype.getTouchAction.call(this)},attrTest:function(a){var c,b=this.options.direction;return b&(X|Y)?c=a.velocity:b&X?c=a.velocityX:b&Y&&(c=a.velocityY),this._super.attrTest.call(this,a)&&b&a.direction&&a.distance>this.options.threshold&&i(c)>this.options.velocity&&a.eventType&Q},emit:function(a){var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),p(gc,Yb,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[Lb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance= 0 && !requestAnimationFrame) { + requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; + cancelAnimationFrame = window[vendors[i] + 'CancelRequestAnimationFrame']; + } + + // polyfill with setTimeout fallback + // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945 + if (!requestAnimationFrame || !cancelAnimationFrame) { + requestAnimationFrame = function(callback) { + var now = +Date.now(), + nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { + callback(lastTime = nextTime); + }, nextTime - now); + }; + + cancelAnimationFrame = clearTimeout; + } + + // export to window + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; +}(window)); + + +// Unique ID +Materialize.guid = (function() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + + s4() + '-' + s4() + s4() + s4(); + }; +})(); + +/** + * Escapes hash from special characters + * @param {string} hash String returned from this.hash + * @returns {string} + */ +Materialize.escapeHash = function(hash) { + return hash.replace( /(:|\.|\[|\]|,|=)/g, "\\$1" ); +}; + +Materialize.elementOrParentIsFixed = function(element) { + var $element = $(element); + var $checkElements = $element.add($element.parents()); + var isFixed = false; + $checkElements.each(function(){ + if ($(this).css("position") === "fixed") { + isFixed = true; + return false; + } + }); + return isFixed; +}; + +// Velocity has conflicts when loaded with jQuery, this will check for it +// First, check if in noConflict mode +var Vel; +if (jQuery) { + Vel = jQuery.Velocity; +} else if ($) { + Vel = $.Velocity; +} else { + Vel = Velocity; +} +;(function ($) { + $.fn.collapsible = function(options) { + var defaults = { + accordion: undefined, + onOpen: undefined, + onClose: undefined + }; + + options = $.extend(defaults, options); + + + return this.each(function() { + + var $this = $(this); + + var $panel_headers = $(this).find('> li > .collapsible-header'); + + var collapsible_type = $this.data("collapsible"); + + // Turn off any existing event handlers + $this.off('click.collapse', '> li > .collapsible-header'); + $panel_headers.off('click.collapse'); + + + /**************** + Helper Functions + ****************/ + + // Accordion Open + function accordionOpen(object) { + $panel_headers = $this.find('> li > .collapsible-header'); + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else{ + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + + $panel_headers.not(object).removeClass('active').parent().removeClass('active'); + + // Close previously open accordion elements. + $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() { + if ($(this).is(':visible')) { + $(this).slideUp({ + duration: 350, + easing: "easeOutQuart", + queue: false, + complete: + function() { + $(this).css('height', ''); + execCallbacks($(this).siblings('.collapsible-header')); + } + }); + } + }); + } + + // Expandable Open + function expandableOpen(object) { + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else { + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + } + + // Open collapsible. object: .collapsible-header + function collapsibleOpen(object) { + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + accordionOpen(object); + } else { // Handle Expandables + expandableOpen(object); + } + + execCallbacks(object); + } + + // Handle callbacks + function execCallbacks(object) { + if (object.hasClass('active')) { + if (typeof(options.onOpen) === "function") { + options.onOpen.call(this, object.parent()); + } + } else { + if (typeof(options.onClose) === "function") { + options.onClose.call(this, object.parent()); + } + } + } + + /** + * Check if object is children of panel header + * @param {Object} object Jquery object + * @return {Boolean} true if it is children + */ + function isChildrenOfPanelHeader(object) { + + var panelHeader = getPanelHeader(object); + + return panelHeader.length > 0; + } + + /** + * Get panel header from a children element + * @param {Object} object Jquery object + * @return {Object} panel header object + */ + function getPanelHeader(object) { + + return object.closest('li > .collapsible-header'); + } + + /***** End Helper Functions *****/ + + + + // Add click handler to only direct collapsible header children + $this.on('click.collapse', '> li > .collapsible-header', function(e) { + var element = $(e.target); + + if (isChildrenOfPanelHeader(element)) { + element = getPanelHeader(element); + } + + element.toggleClass('active'); + + collapsibleOpen(element); + }); + + + // Open first active + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + collapsibleOpen($panel_headers.filter('.active').first()); + + } else { // Handle Expandables + $panel_headers.filter('.active').each(function() { + collapsibleOpen($(this)); + }); + } + + }); + }; + + $(document).ready(function(){ + $('.collapsible').collapsible(); + }); +}( jQuery ));;(function ($) { + + // Add posibility to scroll to selected option + // usefull for select for example + $.fn.scrollTo = function(elem) { + $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); + return this; + }; + + $.fn.dropdown = function (options) { + var defaults = { + inDuration: 300, + outDuration: 225, + constrain_width: true, // Constrains width of dropdown to the activator + hover: false, + gutter: 0, // Spacing from edge + belowOrigin: false, + alignment: 'left', + stopPropagation: false + }; + + // Open dropdown. + if (options === "open") { + this.each(function() { + $(this).trigger('open'); + }); + return false; + } + + // Close dropdown. + if (options === "close") { + this.each(function() { + $(this).trigger('close'); + }); + return false; + } + + this.each(function(){ + var origin = $(this); + var curr_options = $.extend({}, defaults, options); + var isFocused = false; + + // Dropdown menu + var activates = $("#"+ origin.attr('data-activates')); + + function updateOptions() { + if (origin.data('induration') !== undefined) + curr_options.inDuration = origin.data('induration'); + if (origin.data('outduration') !== undefined) + curr_options.outDuration = origin.data('outduration'); + if (origin.data('constrainwidth') !== undefined) + curr_options.constrain_width = origin.data('constrainwidth'); + if (origin.data('hover') !== undefined) + curr_options.hover = origin.data('hover'); + if (origin.data('gutter') !== undefined) + curr_options.gutter = origin.data('gutter'); + if (origin.data('beloworigin') !== undefined) + curr_options.belowOrigin = origin.data('beloworigin'); + if (origin.data('alignment') !== undefined) + curr_options.alignment = origin.data('alignment'); + if (origin.data('stoppropagation') !== undefined) + curr_options.stopPropagation = origin.data('stoppropagation'); + } + + updateOptions(); + + // Attach dropdown to its activator + origin.after(activates); + + /* + Helper function to position and resize dropdown. + Used in hover and click handler. + */ + function placeDropdown(eventType) { + // Check for simultaneous focus and click events. + if (eventType === 'focus') { + isFocused = true; + } + + // Check html data attributes + updateOptions(); + + // Set Dropdown state + activates.addClass('active'); + origin.addClass('active'); + + // Constrain width + if (curr_options.constrain_width === true) { + activates.css('width', origin.outerWidth()); + + } else { + activates.css('white-space', 'nowrap'); + } + + // Offscreen detection + var windowHeight = window.innerHeight; + var originHeight = origin.innerHeight(); + var offsetLeft = origin.offset().left; + var offsetTop = origin.offset().top - $(window).scrollTop(); + var currAlignment = curr_options.alignment; + var gutterSpacing = 0; + var leftPosition = 0; + + // Below Origin + var verticalOffset = 0; + if (curr_options.belowOrigin === true) { + verticalOffset = originHeight; + } + + // Check for scrolling positioned container. + var scrollYOffset = 0; + var scrollXOffset = 0; + var wrapper = origin.parent(); + if (!wrapper.is('body')) { + if (wrapper[0].scrollHeight > wrapper[0].clientHeight) { + scrollYOffset = wrapper[0].scrollTop; + } + if (wrapper[0].scrollWidth > wrapper[0].clientWidth) { + scrollXOffset = wrapper[0].scrollLeft; + } + } + + + if (offsetLeft + activates.innerWidth() > $(window).width()) { + // Dropdown goes past screen on right, force right alignment + currAlignment = 'right'; + + } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { + // Dropdown goes past screen on left, force left alignment + currAlignment = 'left'; + } + // Vertical bottom offscreen detection + if (offsetTop + activates.innerHeight() > windowHeight) { + // If going upwards still goes offscreen, just crop height of dropdown. + if (offsetTop + originHeight - activates.innerHeight() < 0) { + var adjustedHeight = windowHeight - offsetTop - verticalOffset; + activates.css('max-height', adjustedHeight); + } else { + // Flow upwards. + if (!verticalOffset) { + verticalOffset += originHeight; + } + verticalOffset -= activates.innerHeight(); + } + } + + // Handle edge alignment + if (currAlignment === 'left') { + gutterSpacing = curr_options.gutter; + leftPosition = origin.position().left + gutterSpacing; + } + else if (currAlignment === 'right') { + var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); + gutterSpacing = -curr_options.gutter; + leftPosition = offsetRight + gutterSpacing; + } + + // Position dropdown + activates.css({ + position: 'absolute', + top: origin.position().top + verticalOffset + scrollYOffset, + left: leftPosition + scrollXOffset + }); + + + // Show dropdown + activates.stop(true, true).css('opacity', 0) + .slideDown({ + queue: false, + duration: curr_options.inDuration, + easing: 'easeOutCubic', + complete: function() { + $(this).css('height', ''); + } + }) + .animate( {opacity: 1}, {queue: false, duration: curr_options.inDuration, easing: 'easeOutSine'}); + } + + function hideDropdown() { + // Check for simultaneous focus and click events. + isFocused = false; + activates.fadeOut(curr_options.outDuration); + activates.removeClass('active'); + origin.removeClass('active'); + setTimeout(function() { activates.css('max-height', ''); }, curr_options.outDuration); + } + + // Hover + if (curr_options.hover) { + var open = false; + origin.unbind('click.' + origin.attr('id')); + // Hover handler to show dropdown + origin.on('mouseenter', function(e){ // Mouse over + if (open === false) { + placeDropdown(); + open = true; + } + }); + origin.on('mouseleave', function(e){ + // If hover on origin then to something other than dropdown content, then close + var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element + if(!$(toEl).closest('.dropdown-content').is(activates)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + activates.on('mouseleave', function(e){ // Mouse out + var toEl = e.toElement || e.relatedTarget; + if(!$(toEl).closest('.dropdown-button').is(origin)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + // Click + } else { + // Click handler to show dropdown + origin.unbind('click.' + origin.attr('id')); + origin.bind('click.'+origin.attr('id'), function(e){ + if (!isFocused) { + if ( origin[0] == e.currentTarget && + !origin.hasClass('active') && + ($(e.target).closest('.dropdown-content').length === 0)) { + e.preventDefault(); // Prevents button click from moving window + if (curr_options.stopPropagation) { + e.stopPropagation(); + } + placeDropdown('click'); + } + // If origin is clicked and menu is open, close menu + else if (origin.hasClass('active')) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + // If menu open, add click close handler to document + if (activates.hasClass('active')) { + $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) { + if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + }); + } + } + }); + + } // End else + + // Listen to open and close event - useful for select component + origin.on('open', function(e, eventType) { + placeDropdown(eventType); + }); + origin.on('close', hideDropdown); + + + }); + }; // End dropdown plugin + + $(document).ready(function(){ + $('.dropdown-button').dropdown(); + }); +}( jQuery )); +;(function($) { + var _stack = 0, + _lastID = 0, + _generateID = function() { + _lastID++; + return 'materialize-modal-overlay-' + _lastID; + }; + + var methods = { + init : function(options) { + var defaults = { + opacity: 0.5, + in_duration: 350, + out_duration: 250, + ready: undefined, + complete: undefined, + dismissible: true, + starting_top: '4%', + ending_top: '10%' + }; + + // Override defaults + options = $.extend(defaults, options); + + return this.each(function() { + var $modal = $(this); + var modal_id = $(this).attr("id") || '#' + $(this).data('target'); + + var closeModal = function() { + var overlayID = $modal.data('overlay-id'); + var $overlay = $('#' + overlayID); + $modal.removeClass('open'); + + // Enable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $modal.find('.modal-close').off('click.close'); + $(document).off('keyup.modal' + overlayID); + + $overlay.velocity( { opacity: 0}, {duration: options.out_duration, queue: false, ease: "easeOutQuart"}); + + + // Define Bottom Sheet animation + var exitVelocityOptions = { + duration: options.out_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + $(this).css({display:"none"}); + + // Call complete callback + if (typeof(options.complete) === "function") { + options.complete.call(this, $modal); + } + $overlay.remove(); + _stack--; + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "-100%", opacity: 0}, exitVelocityOptions); + } + else { + $modal.velocity( + { top: options.starting_top, opacity: 0, scaleX: 0.7}, + exitVelocityOptions + ); + } + }; + + var openModal = function($trigger) { + var $body = $('body'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + if ($modal.hasClass('open')) { + return; + } + + var overlayID = _generateID(); + var $overlay = $(''); + lStack = (++_stack); + + // Store a reference of the overlay + $overlay.attr('id', overlayID).css('z-index', 1000 + lStack * 2); + $modal.data('overlay-id', overlayID).css('z-index', 1000 + lStack * 2 + 1); + $modal.addClass('open'); + + $("body").append($overlay); + + if (options.dismissible) { + $overlay.click(function() { + closeModal(); + }); + // Return on ESC + $(document).on('keyup.modal' + overlayID, function(e) { + if (e.keyCode === 27) { // ESC key + closeModal(); + } + }); + } + + $modal.find(".modal-close").on('click.close', function(e) { + closeModal(); + }); + + $overlay.css({ display : "block", opacity : 0 }); + + $modal.css({ + display : "block", + opacity: 0 + }); + + $overlay.velocity({opacity: options.opacity}, {duration: options.in_duration, queue: false, ease: "easeOutCubic"}); + $modal.data('associated-overlay', $overlay[0]); + + // Define Bottom Sheet animation + var enterVelocityOptions = { + duration: options.in_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + if (typeof(options.ready) === "function") { + options.ready.call(this, $modal, $trigger); + } + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "0", opacity: 1}, enterVelocityOptions); + } + else { + $.Velocity.hook($modal, "scaleX", 0.7); + $modal.css({ top: options.starting_top }); + $modal.velocity({top: options.ending_top, opacity: 1, scaleX: '1'}, enterVelocityOptions); + } + + }; + + // Reset handlers + $(document).off('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]'); + $(this).off('openModal'); + $(this).off('closeModal'); + + // Close Handlers + $(document).on('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]', function(e) { + options.starting_top = ($(this).offset().top - $(window).scrollTop()) /1.15; + openModal($(this)); + e.preventDefault(); + }); // done set on click + + $(this).on('openModal', function() { + var modal_id = $(this).attr("href") || '#' + $(this).data('target'); + openModal(); + }); + + $(this).on('closeModal', function() { + closeModal(); + }); + }); // done return + }, + open : function() { + $(this).trigger('openModal'); + }, + close : function() { + $(this).trigger('closeModal'); + } + }; + + $.fn.modal = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.modal' ); + } + }; +})(jQuery); +;(function ($) { + + $.fn.materialbox = function () { + + return this.each(function() { + + if ($(this).hasClass('initialized')) { + return; + } + + $(this).addClass('initialized'); + + var overlayActive = false; + var doneAnimating = true; + var inDuration = 275; + var outDuration = 200; + var origin = $(this); + var placeholder = $('
').addClass('material-placeholder'); + var originalWidth = 0; + var originalHeight = 0; + var ancestorsChanged; + var ancestor; + origin.wrap(placeholder); + + + origin.on('click', function(){ + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.width(); + var originalHeight = origin.height(); + + + // If already modal, return to original + if (doneAnimating === false) { + returnToOriginal(); + return false; + } + else if (overlayActive && doneAnimating===true) { + returnToOriginal(); + return false; + } + + + // Set states + doneAnimating = false; + origin.addClass('active'); + overlayActive = true; + + // Set positioning for placeholder + placeholder.css({ + width: placeholder[0].getBoundingClientRect().width, + height: placeholder[0].getBoundingClientRect().height, + position: 'relative', + top: 0, + left: 0 + }); + + // Find ancestor with overflow: hidden; and remove it + ancestorsChanged = undefined; + ancestor = placeholder[0].parentNode; + var count = 0; + while (ancestor !== null && !$(ancestor).is(document)) { + var curr = $(ancestor); + if (curr.css('overflow') !== 'visible') { + curr.css('overflow', 'visible'); + if (ancestorsChanged === undefined) { + ancestorsChanged = curr; + } + else { + ancestorsChanged = ancestorsChanged.add(curr); + } + } + ancestor = ancestor.parentNode; + } + + // Set css on origin + origin.css({position: 'absolute', 'z-index': 1000}) + .data('width', originalWidth) + .data('height', originalHeight); + + // Add overlay + var overlay = $('
') + .css({ + opacity: 0 + }) + .click(function(){ + if (doneAnimating === true) + returnToOriginal(); + }); + // Animate Overlay + // Put before in origin image to preserve z-index layering. + origin.before(overlay); + overlay.velocity({opacity: 1}, + {duration: inDuration, queue: false, easing: 'easeOutQuad'} ); + + // Add and animate caption if it exists + if (origin.data('caption') !== "") { + var $photo_caption = $('
'); + $photo_caption.text(origin.data('caption')); + $('body').append($photo_caption); + $photo_caption.css({ "display": "inline" }); + $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'}); + } + + // Resize Image + var ratio = 0; + var widthPercent = originalWidth / windowWidth; + var heightPercent = originalHeight / windowHeight; + var newWidth = 0; + var newHeight = 0; + + if (widthPercent > heightPercent) { + ratio = originalHeight / originalWidth; + newWidth = windowWidth * 0.9; + newHeight = windowWidth * 0.9 * ratio; + } + else { + ratio = originalWidth / originalHeight; + newWidth = (windowHeight * 0.9) * ratio; + newHeight = windowHeight * 0.9; + } + + // Animate image + set z-index + if(origin.hasClass('responsive-img')) { + origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false, + complete: function(){ + origin.css({left: 0, top: 0}) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); + } // End Complete + }); // End Velocity + } + else { + origin.css('left', 0) + .css('top', 0) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); // End Velocity + } + + }); // End origin on click + + + // Return on scroll + $(window).scroll(function() { + if (overlayActive) { + returnToOriginal(); + } + }); + + // Return on ESC + $(document).keyup(function(e) { + + if (e.keyCode === 27 && doneAnimating === true) { // ESC key + if (overlayActive) { + returnToOriginal(); + } + } + }); + + + // This function returns the modaled image to the original spot + function returnToOriginal() { + + doneAnimating = false; + + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.data('width'); + var originalHeight = origin.data('height'); + + origin.velocity("stop", true); + $('#materialbox-overlay').velocity("stop", true); + $('.materialbox-caption').velocity("stop", true); + + + $('#materialbox-overlay').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + // Remove Overlay + overlayActive = false; + $(this).remove(); + } + }); + + // Resize Image + origin.velocity( + { + width: originalWidth, + height: originalHeight, + left: 0, + top: 0 + }, + { + duration: outDuration, + queue: false, easing: 'easeOutQuad' + } + ); + + // Remove Caption + reset css settings on image + $('.materialbox-caption').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + placeholder.css({ + height: '', + width: '', + position: '', + top: '', + left: '' + }); + + origin.css({ + height: '', + top: '', + left: '', + width: '', + 'max-width': '', + position: '', + 'z-index': '' + }); + + // Remove class + origin.removeClass('active'); + doneAnimating = true; + $(this).remove(); + + // Remove overflow overrides on ancestors + if (ancestorsChanged) { + ancestorsChanged.css('overflow', ''); + } + } + }); + + } + }); +}; + +$(document).ready(function(){ + $('.materialboxed').materialbox(); +}); + +}( jQuery )); +;(function ($) { + + $.fn.parallax = function () { + var window_width = $(window).width(); + // Parallax Scripts + return this.each(function(i) { + var $this = $(this); + $this.addClass('parallax'); + + function updateParallax(initial) { + var container_height; + if (window_width < 601) { + container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height(); + } + else { + container_height = ($this.height() > 0) ? $this.height() : 500; + } + var $img = $this.children("img").first(); + var img_height = $img.height(); + var parallax_dist = img_height - container_height; + var bottom = $this.offset().top + container_height; + var top = $this.offset().top; + var scrollTop = $(window).scrollTop(); + var windowHeight = window.innerHeight; + var windowBottom = scrollTop + windowHeight; + var percentScrolled = (windowBottom - top) / (container_height + windowHeight); + var parallax = Math.round((parallax_dist * percentScrolled)); + + if (initial) { + $img.css('display', 'block'); + } + if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) { + $img.css('transform', "translate3D(-50%," + parallax + "px, 0)"); + } + + } + + // Wait for image load + $this.children("img").one("load", function() { + updateParallax(true); + }).each(function() { + if (this.complete) $(this).trigger("load"); + }); + + $(window).scroll(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + $(window).resize(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + }); + + }; +}( jQuery )); +;(function ($) { + $.fn.tooltip = function (options) { + var timeout = null, + margin = 5; + + // Defaults + var defaults = { + delay: 350, + tooltip: '', + position: 'bottom', + html: false + }; + + // Remove tooltip from the activator + if (options === "remove") { + this.each(function() { + $('#' + $(this).attr('data-tooltip-id')).remove(); + $(this).off('mouseenter.tooltip mouseleave.tooltip'); + }); + return false; + } + + options = $.extend(defaults, options); + + return this.each(function() { + var tooltipId = Materialize.guid(); + var origin = $(this); + + // Destroy old tooltip + if (origin.attr('data-tooltip-id')) { + $('#' + origin.attr('data-tooltip-id')).remove(); + } + + origin.attr('data-tooltip-id', tooltipId); + + // Get attributes. + var allowHtml, + tooltipDelay, + tooltipPosition, + tooltipText, + tooltipEl, + backdrop; + var setAttributes = function() { + allowHtml = origin.attr('data-html') ? origin.attr('data-html') === 'true' : options.html; + tooltipDelay = origin.attr('data-delay'); + tooltipDelay = (tooltipDelay === undefined || tooltipDelay === '') ? + options.delay : tooltipDelay; + tooltipPosition = origin.attr('data-position'); + tooltipPosition = (tooltipPosition === undefined || tooltipPosition === '') ? + options.position : tooltipPosition; + tooltipText = origin.attr('data-tooltip'); + tooltipText = (tooltipText === undefined || tooltipText === '') ? + options.tooltip : tooltipText; + }; + setAttributes(); + + var renderTooltipEl = function() { + var tooltip = $('
'); + + // Create Text span + if (allowHtml) { + tooltipText = $('').html(tooltipText); + } else{ + tooltipText = $('').text(tooltipText); + } + + // Create tooltip + tooltip.append(tooltipText) + .appendTo($('body')) + .attr('id', tooltipId); + + // Create backdrop + backdrop = $('
'); + backdrop.appendTo(tooltip); + return tooltip; + }; + tooltipEl = renderTooltipEl(); + + // Destroy previously binded events + origin.off('mouseenter.tooltip mouseleave.tooltip'); + // Mouse In + var started = false, timeoutRef; + origin.on({'mouseenter.tooltip': function(e) { + var showTooltip = function() { + setAttributes(); + started = true; + tooltipEl.velocity('stop'); + backdrop.velocity('stop'); + tooltipEl.css({ display: 'block', left: '0px', top: '0px' }); + + // Tooltip positioning + var originWidth = origin.outerWidth(); + var originHeight = origin.outerHeight(); + + var tooltipHeight = tooltipEl.outerHeight(); + var tooltipWidth = tooltipEl.outerWidth(); + var tooltipVerticalMovement = '0px'; + var tooltipHorizontalMovement = '0px'; + var scaleXFactor = 8; + var scaleYFactor = 8; + var targetTop, targetLeft, newCoordinates; + + if (tooltipPosition === "top") { + // Top Position + targetTop = origin.offset().top - tooltipHeight - margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipVerticalMovement = '-10px'; + backdrop.css({ + bottom: 0, + left: 0, + borderRadius: '14px 14px 0 0', + transformOrigin: '50% 100%', + marginTop: tooltipHeight, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + // Left Position + else if (tooltipPosition === "left") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left - tooltipWidth - margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '-10px'; + backdrop.css({ + top: '-7px', + right: 0, + width: '14px', + height: '14px', + borderRadius: '14px 0 0 14px', + transformOrigin: '95% 50%', + marginTop: tooltipHeight/2, + marginLeft: tooltipWidth + }); + } + // Right Position + else if (tooltipPosition === "right") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left + originWidth + margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '+10px'; + backdrop.css({ + top: '-7px', + left: 0, + width: '14px', + height: '14px', + borderRadius: '0 14px 14px 0', + transformOrigin: '5% 50%', + marginTop: tooltipHeight/2, + marginLeft: '0px' + }); + } + else { + // Bottom Position + targetTop = origin.offset().top + origin.outerHeight() + margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + tooltipVerticalMovement = '+10px'; + backdrop.css({ + top: 0, + left: 0, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + + // Set tooptip css placement + tooltipEl.css({ + top: newCoordinates.y, + left: newCoordinates.x + }); + + // Calculate Scale to fill + scaleXFactor = Math.SQRT2 * tooltipWidth / parseInt(backdrop.css('width')); + scaleYFactor = Math.SQRT2 * tooltipHeight / parseInt(backdrop.css('height')); + + tooltipEl.velocity({ marginTop: tooltipVerticalMovement, marginLeft: tooltipHorizontalMovement}, { duration: 350, queue: false }) + .velocity({opacity: 1}, {duration: 300, delay: 50, queue: false}); + backdrop.css({ display: 'block' }) + .velocity({opacity:1},{duration: 55, delay: 0, queue: false}) + .velocity({scaleX: scaleXFactor, scaleY: scaleYFactor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'}); + }; + + timeoutRef = setTimeout(showTooltip, tooltipDelay); // End Interval + + // Mouse Out + }, + 'mouseleave.tooltip': function(){ + // Reset State + started = false; + clearTimeout(timeoutRef); + + // Animate back + setTimeout(function() { + if (started !== true) { + tooltipEl.velocity({ + opacity: 0, marginTop: 0, marginLeft: 0}, { duration: 225, queue: false}); + backdrop.velocity({opacity: 0, scaleX: 1, scaleY: 1}, { + duration:225, + queue: false, + complete: function(){ + backdrop.css('display', 'none'); + tooltipEl.css('display', 'none'); + started = false;} + }); + } + },225); + } + }); + }); + }; + + var repositionWithinScreen = function(x, y, width, height) { + var newX = x; + var newY = y; + + if (newX < 0) { + newX = 4; + } else if (newX + width > window.innerWidth) { + newX -= newX + width - window.innerWidth; + } + + if (newY < 0) { + newY = 4; + } else if (newY + height > window.innerHeight + $(window).scrollTop) { + newY -= newY + height - window.innerHeight; + } + + return {x: newX, y: newY}; + }; + + $(document).ready(function(){ + $('.tooltipped').tooltip(); + }); +}( jQuery )); +;/*! + * Waves v0.6.4 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */ + +;(function(window) { + 'use strict'; + + var Waves = Waves || {}; + var $$ = document.querySelectorAll.bind(document); + + // Find exact position of element + function isWindow(obj) { + return obj !== null && obj === obj.window; + } + + function getWindow(elem) { + return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; + } + + function offset(elem) { + var docElem, win, + box = {top: 0, left: 0}, + doc = elem && elem.ownerDocument; + + docElem = doc.documentElement; + + if (typeof elem.getBoundingClientRect !== typeof undefined) { + box = elem.getBoundingClientRect(); + } + win = getWindow(doc); + return { + top: box.top + win.pageYOffset - docElem.clientTop, + left: box.left + win.pageXOffset - docElem.clientLeft + }; + } + + function convertStyle(obj) { + var style = ''; + + for (var a in obj) { + if (obj.hasOwnProperty(a)) { + style += (a + ':' + obj[a] + ';'); + } + } + + return style; + } + + var Effect = { + + // Effect delay + duration: 750, + + show: function(e, element) { + + // Disable right click + if (e.button === 2) { + return false; + } + + var el = element || this; + + // Create ripple + var ripple = document.createElement('div'); + ripple.className = 'waves-ripple'; + el.appendChild(ripple); + + // Get click coordinate and element witdh + var pos = offset(el); + var relativeY = (e.pageY - pos.top); + var relativeX = (e.pageX - pos.left); + var scale = 'scale('+((el.clientWidth / 100) * 10)+')'; + + // Support for touch devices + if ('touches' in e) { + relativeY = (e.touches[0].pageY - pos.top); + relativeX = (e.touches[0].pageX - pos.left); + } + + // Attach data to element + ripple.setAttribute('data-hold', Date.now()); + ripple.setAttribute('data-scale', scale); + ripple.setAttribute('data-x', relativeX); + ripple.setAttribute('data-y', relativeY); + + // Set ripple position + var rippleStyle = { + 'top': relativeY+'px', + 'left': relativeX+'px' + }; + + ripple.className = ripple.className + ' waves-notransition'; + ripple.setAttribute('style', convertStyle(rippleStyle)); + ripple.className = ripple.className.replace('waves-notransition', ''); + + // Scale the ripple + rippleStyle['-webkit-transform'] = scale; + rippleStyle['-moz-transform'] = scale; + rippleStyle['-ms-transform'] = scale; + rippleStyle['-o-transform'] = scale; + rippleStyle.transform = scale; + rippleStyle.opacity = '1'; + + rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-o-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['transition-duration'] = Effect.duration + 'ms'; + + rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + + ripple.setAttribute('style', convertStyle(rippleStyle)); + }, + + hide: function(e) { + TouchHandler.touchup(e); + + var el = this; + var width = el.clientWidth * 1.4; + + // Get first ripple + var ripple = null; + var ripples = el.getElementsByClassName('waves-ripple'); + if (ripples.length > 0) { + ripple = ripples[ripples.length - 1]; + } else { + return false; + } + + var relativeX = ripple.getAttribute('data-x'); + var relativeY = ripple.getAttribute('data-y'); + var scale = ripple.getAttribute('data-scale'); + + // Get delay beetween mousedown and mouse leave + var diff = Date.now() - Number(ripple.getAttribute('data-hold')); + var delay = 350 - diff; + + if (delay < 0) { + delay = 0; + } + + // Fade out ripple after delay + setTimeout(function() { + var style = { + 'top': relativeY+'px', + 'left': relativeX+'px', + 'opacity': '0', + + // Duration + '-webkit-transition-duration': Effect.duration + 'ms', + '-moz-transition-duration': Effect.duration + 'ms', + '-o-transition-duration': Effect.duration + 'ms', + 'transition-duration': Effect.duration + 'ms', + '-webkit-transform': scale, + '-moz-transform': scale, + '-ms-transform': scale, + '-o-transform': scale, + 'transform': scale, + }; + + ripple.setAttribute('style', convertStyle(style)); + + setTimeout(function() { + try { + el.removeChild(ripple); + } catch(e) { + return false; + } + }, Effect.duration); + }, delay); + }, + + // Little hack to make can perform waves effect + wrapInput: function(elements) { + for (var a = 0; a < elements.length; a++) { + var el = elements[a]; + + if (el.tagName.toLowerCase() === 'input') { + var parent = el.parentNode; + + // If input already have parent just pass through + if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) { + continue; + } + + // Put element class and style to the specified parent + var wrapper = document.createElement('i'); + wrapper.className = el.className + ' waves-input-wrapper'; + + var elementStyle = el.getAttribute('style'); + + if (!elementStyle) { + elementStyle = ''; + } + + wrapper.setAttribute('style', elementStyle); + + el.className = 'waves-button-input'; + el.removeAttribute('style'); + + // Put element as child + parent.replaceChild(wrapper, el); + wrapper.appendChild(el); + } + } + } + }; + + + /** + * Disable mousedown event for 500ms during and after touch + */ + var TouchHandler = { + /* uses an integer rather than bool so there's no issues with + * needing to clear timeouts if another touch event occurred + * within the 500ms. Cannot mouseup between touchstart and + * touchend, nor in the 500ms after touchend. */ + touches: 0, + allowEvent: function(e) { + var allow = true; + + if (e.type === 'touchstart') { + TouchHandler.touches += 1; //push + } else if (e.type === 'touchend' || e.type === 'touchcancel') { + setTimeout(function() { + if (TouchHandler.touches > 0) { + TouchHandler.touches -= 1; //pop after 500ms + } + }, 500); + } else if (e.type === 'mousedown' && TouchHandler.touches > 0) { + allow = false; + } + + return allow; + }, + touchup: function(e) { + TouchHandler.allowEvent(e); + } + }; + + + /** + * Delegated click handler for .waves-effect element. + * returns null when .waves-effect element not in "click tree" + */ + function getWavesEffectElement(e) { + if (TouchHandler.allowEvent(e) === false) { + return null; + } + + var element = null; + var target = e.target || e.srcElement; + + while (target.parentElement !== null) { + if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) { + element = target; + break; + } else if (target.classList.contains('waves-effect')) { + element = target; + break; + } + target = target.parentElement; + } + + return element; + } + + /** + * Bubble the click and show effect if .waves-effect elem was found + */ + function showEffect(e) { + var element = getWavesEffectElement(e); + + if (element !== null) { + Effect.show(e, element); + + if ('ontouchstart' in window) { + element.addEventListener('touchend', Effect.hide, false); + element.addEventListener('touchcancel', Effect.hide, false); + } + + element.addEventListener('mouseup', Effect.hide, false); + element.addEventListener('mouseleave', Effect.hide, false); + } + } + + Waves.displayEffect = function(options) { + options = options || {}; + + if ('duration' in options) { + Effect.duration = options.duration; + } + + //Wrap input inside tag + Effect.wrapInput($$('.waves-effect')); + + if ('ontouchstart' in window) { + document.body.addEventListener('touchstart', showEffect, false); + } + + document.body.addEventListener('mousedown', showEffect, false); + }; + + /** + * Attach Waves to an input element (or any element which doesn't + * bubble mouseup/mousedown events). + * Intended to be used with dynamically loaded forms/inputs, or + * where the user doesn't want a delegated click handler. + */ + Waves.attach = function(element) { + //FUTURE: automatically add waves classes and allow users + // to specify them with an options param? Eg. light/classic/button + if (element.tagName.toLowerCase() === 'input') { + Effect.wrapInput([element]); + element = element.parentElement; + } + + if ('ontouchstart' in window) { + element.addEventListener('touchstart', showEffect, false); + } + + element.addEventListener('mousedown', showEffect, false); + }; + + window.Waves = Waves; + + document.addEventListener('DOMContentLoaded', function() { + Waves.displayEffect(); + }, false); + +})(window); +;Materialize.toast = function (message, displayLength, className, completeCallback) { + className = className || ""; + + var container = document.getElementById('toast-container'); + + // Create toast container if it does not exist + if (container === null) { + // create notification container + container = document.createElement('div'); + container.id = 'toast-container'; + document.body.appendChild(container); + } + + // Select and append toast + var newToast = createToast(message); + + // only append toast if message is not undefined + if(message){ + container.appendChild(newToast); + } + + newToast.style.top = '35px'; + newToast.style.opacity = 0; + + // Animate toast in + Vel(newToast, { "top" : "0px", opacity: 1 }, {duration: 300, + easing: 'easeOutCubic', + queue: false}); + + // Allows timer to be pause while being panned + var timeLeft = displayLength; + var counterInterval; + if (timeLeft != null) { + counterInterval = setInterval (function(){ + if (newToast.parentNode === null) + window.clearInterval(counterInterval); + + // If toast is not being dragged, decrease its time remaining + if (!newToast.classList.contains('panning')) { + timeLeft -= 20; + } + + if (timeLeft <= 0) { + // Animate toast out + Vel(newToast, {"opacity": 0, marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + // Call the optional callback + if(typeof(completeCallback) === "function") + completeCallback(); + // Remove toast after it times out + this[0].parentNode.removeChild(this[0]); + } + }); + window.clearInterval(counterInterval); + } + }, 20); + } + + + + function createToast(html) { + + // Create toast + var toast = document.createElement('div'); + toast.classList.add('toast'); + if (className) { + var classes = className.split(' '); + + for (var i = 0, count = classes.length; i < count; i++) { + toast.classList.add(classes[i]); + } + } + // If type of parameter is HTML Element + if ( typeof HTMLElement === "object" ? html instanceof HTMLElement : html && typeof html === "object" && html !== null && html.nodeType === 1 && typeof html.nodeName==="string" +) { + toast.appendChild(html); + } + else if (html instanceof jQuery) { + // Check if it is jQuery object + toast.appendChild(html[0]); + } + else { + // Insert as text; + toast.innerHTML = html; + } + // Bind hammer + var hammerHandler = new Hammer(toast, {prevent_default: false}); + hammerHandler.on('pan', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // Change toast state + if (!toast.classList.contains('panning')){ + toast.classList.add('panning'); + } + + var opacityPercent = 1-Math.abs(deltaX / activationDistance); + if (opacityPercent < 0) + opacityPercent = 0; + + Vel(toast, {left: deltaX, opacity: opacityPercent }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + }); + + hammerHandler.on('panend', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // If toast dragged past activation point + if (Math.abs(deltaX) > activationDistance) { + Vel(toast, {marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + if(typeof(completeCallback) === "function") { + completeCallback(); + } + toast.parentNode.removeChild(toast); + } + }); + + } else { + toast.classList.remove('panning'); + // Put toast back into original position + Vel(toast, { left: 0, opacity: 1 }, { duration: 300, + easing: 'easeOutExpo', + queue: false + }); + + } + }); + + return toast; + } +}; +;(function ($) { + + var methods = { + init : function(options) { + var defaults = { + menuWidth: 300, + edge: 'left', + closeOnClick: false, + draggable: true + }; + options = $.extend(defaults, options); + + $(this).each(function(){ + var $this = $(this); + var menu_id = $("#"+ $this.attr('data-activates')); + + // Set to width + if (options.menuWidth != 300) { + menu_id.css('width', options.menuWidth); + } + + // Add Touch Area + var $dragTarget; + if (options.draggable) { + $dragTarget = $('
').attr('data-sidenav', $this.attr('data-activates')); + $('body').append($dragTarget); + } else { + $dragTarget = $(); + } + + if (options.edge == 'left') { + menu_id.css('transform', 'translateX(-100%)'); + $dragTarget.css({'left': 0}); // Add Touch Area + } + else { + menu_id.addClass('right-aligned') // Change text-alignment to right + .css('transform', 'translateX(100%)'); + $dragTarget.css({'right': 0}); // Add Touch Area + } + + // If fixed sidenav, bring menu out + if (menu_id.hasClass('fixed')) { + if (window.innerWidth > 992) { + menu_id.css('transform', 'translateX(0)'); + } + } + + // Window resize to reset on large screens fixed + if (menu_id.hasClass('fixed')) { + $(window).resize( function() { + if (window.innerWidth > 992) { + // Close menu if window is resized bigger than 992 and user has fixed sidenav + if ($('#sidenav-overlay').length !== 0 && menuOut) { + removeMenu(true); + } + else { + // menu_id.removeAttr('style'); + menu_id.css('transform', 'translateX(0%)'); + // menu_id.css('width', options.menuWidth); + } + } + else if (menuOut === false){ + if (options.edge === 'left') { + menu_id.css('transform', 'translateX(-100%)'); + } else { + menu_id.css('transform', 'translateX(100%)'); + } + + } + + }); + } + + // if closeOnClick, then add close event for all a tags in side sideNav + if (options.closeOnClick === true) { + menu_id.on("click.itemclick", "a:not(.collapsible-header)", function(){ + removeMenu(); + }); + } + + var removeMenu = function(restoreNav) { + panning = false; + menuOut = false; + // Reenable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $('#sidenav-overlay').velocity({opacity: 0}, {duration: 200, + queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + if (options.edge === 'left') { + // Reset phantom div + $dragTarget.css({width: '', right: '', left: '0'}); + menu_id.velocity( + {'translateX': '-100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + + }); + } + else { + // Reset phantom div + $dragTarget.css({width: '', right: '0', left: ''}); + menu_id.velocity( + {'translateX': '100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + }); + } + }; + + + + // Touch Event + var panning = false; + var menuOut = false; + + if (options.draggable) { + $dragTarget.on('click', function(){ + if (menuOut) { + removeMenu(); + } + }); + + $dragTarget.hammer({ + prevent_default: false + }).bind('pan', function(e) { + + if (e.gesture.pointerType == "touch") { + + var direction = e.gesture.direction; + var x = e.gesture.center.x; + var y = e.gesture.center.y; + var velocityX = e.gesture.velocityX; + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('#sidenav-overlay'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // If overlay does not exist, create one and if it is clicked, close menu + if ($overlay.length === 0) { + $overlay = $('
'); + $overlay.css('opacity', 0).click( function(){ + removeMenu(); + }); + $('body').append($overlay); + } + + // Keep within boundaries + if (options.edge === 'left') { + if (x > options.menuWidth) { x = options.menuWidth; } + else if (x < 0) { x = 0; } + } + + if (options.edge === 'left') { + // Left Direction + if (x < (options.menuWidth / 2)) { menuOut = false; } + // Right Direction + else if (x >= (options.menuWidth / 2)) { menuOut = true; } + menu_id.css('transform', 'translateX(' + (x - options.menuWidth) + 'px)'); + } + else { + // Left Direction + if (x < (window.innerWidth - options.menuWidth / 2)) { + menuOut = true; + } + // Right Direction + else if (x >= (window.innerWidth - options.menuWidth / 2)) { + menuOut = false; + } + var rightPos = (x - options.menuWidth / 2); + if (rightPos < 0) { + rightPos = 0; + } + + menu_id.css('transform', 'translateX(' + rightPos + 'px)'); + } + + + // Percentage overlay + var overlayPerc; + if (options.edge === 'left') { + overlayPerc = x / options.menuWidth; + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + else { + overlayPerc = Math.abs((x - window.innerWidth) / options.menuWidth); + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + } + + }).bind('panend', function(e) { + + if (e.gesture.pointerType == "touch") { + var $overlay = $('
'); + var velocityX = e.gesture.velocityX; + var x = e.gesture.center.x; + var leftPos = x - options.menuWidth; + var rightPos = x - options.menuWidth / 2; + if (leftPos > 0 ) { + leftPos = 0; + } + if (rightPos < 0) { + rightPos = 0; + } + panning = false; + + if (options.edge === 'left') { + // If velocityX <= 0.3 then the user is flinging the menu closed so ignore menuOut + if ((menuOut && velocityX <= 0.3) || velocityX < -0.5) { + // Return menu to open + if (leftPos !== 0) { + menu_id.velocity({'translateX': [0, leftPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: 0, left: ''}); + menuOut = true; + } + else if (!menuOut || velocityX > 0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + // Slide menu closed + menu_id.velocity({'translateX': [-1 * options.menuWidth - 10, leftPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: '', left: 0}); + } + } + else { + if ((menuOut && velocityX >= -0.3) || velocityX > 0.5) { + // Return menu to open + if (rightPos !== 0) { + menu_id.velocity({'translateX': [0, rightPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: '', left: 0}); + menuOut = true; + } + else if (!menuOut || velocityX < -0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + + // Slide menu closed + menu_id.velocity({'translateX': [options.menuWidth + 10, rightPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: 0, left: ''}); + } + } + + } + }); + } + + $this.click(function() { + if (menuOut === true) { + menuOut = false; + panning = false; + removeMenu(); + } + else { + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('
'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // Push current drag target on top of DOM tree + $('body').append($dragTarget); + + if (options.edge === 'left') { + $dragTarget.css({width: '50%', right: 0, left: ''}); + menu_id.velocity({'translateX': [0, -1 * options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else { + $dragTarget.css({width: '50%', right: '', left: 0}); + menu_id.velocity({'translateX': [0, options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.css('opacity', 0) + .click(function(){ + menuOut = false; + panning = false; + removeMenu(); + $overlay.velocity({opacity: 0}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + + }); + $('body').append($overlay); + $overlay.velocity({opacity: 1}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function () { + menuOut = true; + panning = false; + } + }); + } + + return false; + }); + }); + + + }, + destroy: function () { + var $overlay = $('#sidenav-overlay'); + var $dragTarget = $('.drag-target[data-sidenav="' + $(this).attr('data-activates') + '"]'); + $overlay.trigger('click'); + $dragTarget.remove(); + $(this).off('click'); + $overlay.remove(); + }, + show : function() { + this.trigger('click'); + }, + hide : function() { + $('#sidenav-overlay').trigger('click'); + } + }; + + + $.fn.sideNav = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.sideNav' ); + } + }; // Plugin end +}( jQuery )); +;/** + * Extend jquery with a scrollspy plugin. + * This watches the window scroll and fires events when elements are scrolled into viewport. + * + * throttle() and getTime() taken from Underscore.js + * https://github.com/jashkenas/underscore + * + * @author Copyright 2013 John Smart + * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE + * @see https://github.com/thesmart + * @version 0.1.2 + */ +(function($) { + + var jWindow = $(window); + var elements = []; + var elementsInView = []; + var isSpying = false; + var ticks = 0; + var unique_id = 1; + var offset = { + top : 0, + right : 0, + bottom : 0, + left : 0, + } + + /** + * Find elements that are within the boundary + * @param {number} top + * @param {number} right + * @param {number} bottom + * @param {number} left + * @return {jQuery} A collection of elements + */ + function findElements(top, right, bottom, left) { + var hits = $(); + $.each(elements, function(i, element) { + if (element.height() > 0) { + var elTop = element.offset().top, + elLeft = element.offset().left, + elRight = elLeft + element.width(), + elBottom = elTop + element.height(); + + var isIntersect = !(elLeft > right || + elRight < left || + elTop > bottom || + elBottom < top); + + if (isIntersect) { + hits.push(element); + } + } + }); + + return hits; + } + + + /** + * Called when the user scrolls the window + */ + function onScroll(scrollOffset) { + // unique tick id + ++ticks; + + // viewport rectangle + var top = jWindow.scrollTop(), + left = jWindow.scrollLeft(), + right = left + jWindow.width(), + bottom = top + jWindow.height(); + + // determine which elements are in view + var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left); + $.each(intersections, function(i, element) { + + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick != 'number') { + // entered into view + element.triggerHandler('scrollSpy:enter'); + } + + // update tick id + element.data('scrollSpy:ticks', ticks); + }); + + // determine which elements are no longer in view + $.each(elementsInView, function(i, element) { + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick == 'number' && lastTick !== ticks) { + // exited from view + element.triggerHandler('scrollSpy:exit'); + element.data('scrollSpy:ticks', null); + } + }); + + // remember elements in view for next tick + elementsInView = intersections; + } + + /** + * Called when window is resized + */ + function onWinSize() { + jWindow.trigger('scrollSpy:winSize'); + } + + /** + * Get time in ms + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @type {function} + * @return {number} + */ + var getTime = (Date.now || function () { + return new Date().getTime(); + }); + + /** + * Returns a function, that, when invoked, will only be triggered at most once + * during a given window of time. Normally, the throttled function will run + * as much as it can, without ever going more than once per `wait` duration; + * but if you'd like to disable the execution on the leading edge, pass + * `{leading: false}`. To disable execution on the trailing edge, ditto. + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @param {function} func + * @param {number} wait + * @param {Object=} options + * @returns {Function} + */ + function throttle(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + options || (options = {}); + var later = function () { + previous = options.leading === false ? 0 : getTime(); + timeout = null; + result = func.apply(context, args); + context = args = null; + }; + return function () { + var now = getTime(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + /** + * Enables ScrollSpy using a selector + * @param {jQuery|string} selector The elements collection, or a selector + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.scrollSpy = function(selector, options) { + var defaults = { + throttle: 100, + scrollOffset: 200 // offset - 200 allows elements near bottom of page to scroll + }; + options = $.extend(defaults, options); + + var visible = []; + selector = $(selector); + selector.each(function(i, element) { + elements.push($(element)); + $(element).data("scrollSpy:id", i); + // Smooth scroll to section + $('a[href="#' + $(element).attr('id') + '"]').click(function(e) { + e.preventDefault(); + var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1; + $('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'}); + }); + }); + + offset.top = options.offsetTop || 0; + offset.right = options.offsetRight || 0; + offset.bottom = options.offsetBottom || 0; + offset.left = options.offsetLeft || 0; + + var throttledScroll = throttle(function() { + onScroll(options.scrollOffset); + }, options.throttle || 100); + var readyScroll = function(){ + $(document).ready(throttledScroll); + }; + + if (!isSpying) { + jWindow.on('scroll', readyScroll); + jWindow.on('resize', readyScroll); + isSpying = true; + } + + // perform a scan once, after current execution context, and after dom is ready + setTimeout(readyScroll, 0); + + + selector.on('scrollSpy:enter', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + var $this = $(this); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) { + visible.unshift($(this)); + } + else { + visible.push($(this)); + } + } + else { + visible.push($(this)); + } + + + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + }); + selector.on('scrollSpy:exit', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + var $this = $(this); + visible = $.grep(visible, function(value) { + return value.attr('id') != $this.attr('id'); + }); + if (visible[0]) { // Check if empty + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + } + } + }); + + return selector; + }; + + /** + * Listen for window resize events + * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms + * @returns {jQuery} $(window) + */ + $.winSizeSpy = function(options) { + $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls + options = options || { + throttle: 100 + }; + return jWindow.on('resize', throttle(onWinSize, options.throttle || 100)); + }; + + /** + * Enables ScrollSpy on a collection of elements + * e.g. $('.scrollSpy').scrollSpy() + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.fn.scrollSpy = function(options) { + return $.scrollSpy($(this), options); + }; + +})(jQuery); +;(function ($) { + $(document).ready(function() { + + // Function to update labels of text fields + Materialize.updateTextFields = function() { + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + $(input_selector).each(function(index, element) { + if ($(element).val().length > 0 || element.autofocus ||$(this).attr('placeholder') !== undefined || $(element)[0].validity.badInput === true) { + $(this).siblings('label').addClass('active'); + } + else { + $(this).siblings('label').removeClass('active'); + } + }); + }; + + // Text based inputs + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + + // Add active if form auto complete + $(document).on('change', input_selector, function () { + if($(this).val().length !== 0 || $(this).attr('placeholder') !== undefined) { + $(this).siblings('label').addClass('active'); + } + validate_field($(this)); + }); + + // Add active if input element has been pre-populated on document ready + $(document).ready(function() { + Materialize.updateTextFields(); + }); + + // HTML DOM FORM RESET handling + $(document).on('reset', function(e) { + var formReset = $(e.target); + if (formReset.is('form')) { + formReset.find(input_selector).removeClass('valid').removeClass('invalid'); + formReset.find(input_selector).each(function () { + if ($(this).attr('value') === '') { + $(this).siblings('label').removeClass('active'); + } + }); + + // Reset select + formReset.find('select.initialized').each(function () { + var reset_text = formReset.find('option[selected]').text(); + formReset.siblings('input.select-dropdown').val(reset_text); + }); + } + }); + + // Add active when element has focus + $(document).on('focus', input_selector, function () { + $(this).siblings('label, .prefix').addClass('active'); + }); + + $(document).on('blur', input_selector, function () { + var $inputElement = $(this); + var selector = ".prefix"; + + if ($inputElement.val().length === 0 && $inputElement[0].validity.badInput !== true && $inputElement.attr('placeholder') === undefined) { + selector += ", label"; + } + + $inputElement.siblings(selector).removeClass('active'); + + validate_field($inputElement); + }); + + window.validate_field = function(object) { + var hasLength = object.attr('length') !== undefined; + var lenAttr = parseInt(object.attr('length')); + var len = object.val().length; + + if (object.val().length === 0 && object[0].validity.badInput === false) { + if (object.hasClass('validate')) { + object.removeClass('valid'); + object.removeClass('invalid'); + } + } + else { + if (object.hasClass('validate')) { + // Check for character counter attributes + if ((object.is(':valid') && hasLength && (len <= lenAttr)) || (object.is(':valid') && !hasLength)) { + object.removeClass('invalid'); + object.addClass('valid'); + } + else { + object.removeClass('valid'); + object.addClass('invalid'); + } + } + } + }; + + // Radio and Checkbox focus class + var radio_checkbox = 'input[type=radio], input[type=checkbox]'; + $(document).on('keyup.radio', radio_checkbox, function(e) { + // TAB, check if tabbing to radio or checkbox. + if (e.which === 9) { + $(this).addClass('tabbed'); + var $this = $(this); + $this.one('blur', function(e) { + + $(this).removeClass('tabbed'); + }); + return; + } + }); + + // Textarea Auto Resize + var hiddenDiv = $('.hiddendiv').first(); + if (!hiddenDiv.length) { + hiddenDiv = $('
'); + $('body').append(hiddenDiv); + } + var text_area_selector = '.materialize-textarea'; + + function textareaAutoResize($textarea) { + // Set font properties of hiddenDiv + + var fontFamily = $textarea.css('font-family'); + var fontSize = $textarea.css('font-size'); + var lineHeight = $textarea.css('line-height'); + + if (fontSize) { hiddenDiv.css('font-size', fontSize); } + if (fontFamily) { hiddenDiv.css('font-family', fontFamily); } + if (lineHeight) { hiddenDiv.css('line-height', lineHeight); } + + if ($textarea.attr('wrap') === "off") { + hiddenDiv.css('overflow-wrap', "normal") + .css('white-space', "pre"); + } + + hiddenDiv.text($textarea.val() + '\n'); + var content = hiddenDiv.html().replace(/\n/g, '
'); + hiddenDiv.html(content); + + + // When textarea is hidden, width goes crazy. + // Approximate with half of window size + + if ($textarea.is(':visible')) { + hiddenDiv.css('width', $textarea.width()); + } + else { + hiddenDiv.css('width', $(window).width()/2); + } + + $textarea.css('height', hiddenDiv.height()); + } + + $(text_area_selector).each(function () { + var $textarea = $(this); + if ($textarea.val().length) { + textareaAutoResize($textarea); + } + }); + + $('body').on('keyup keydown autoresize', text_area_selector, function () { + textareaAutoResize($(this)); + }); + + // File Input Path + $(document).on('change', '.file-field input[type="file"]', function () { + var file_field = $(this).closest('.file-field'); + var path_input = file_field.find('input.file-path'); + var files = $(this)[0].files; + var file_names = []; + for (var i = 0; i < files.length; i++) { + file_names.push(files[i].name); + } + path_input.val(file_names.join(", ")); + path_input.trigger('change'); + }); + + /**************** + * Range Input * + ****************/ + + var range_type = 'input[type=range]'; + var range_mousedown = false; + var left; + + $(range_type).each(function () { + var thumb = $(''); + $(this).after(thumb); + }); + + var range_wrapper = '.range-field'; + $(document).on('change', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + thumb.find('.value').html($(this).val()); + }); + + $(document).on('input mousedown touchstart', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + var width = $(this).outerWidth(); + + // If thumb indicator does not exist yet, create it + if (thumb.length <= 0) { + thumb = $(''); + $(this).after(thumb); + } + + // Set indicator value + thumb.find('.value').html($(this).val()); + + range_mousedown = true; + $(this).addClass('active'); + + if (!thumb.hasClass('active')) { + thumb.velocity({ height: "30px", width: "30px", top: "-20px", marginLeft: "-15px"}, { duration: 300, easing: 'easeOutExpo' }); + } + + if (e.type !== 'input') { + if(e.pageX === undefined || e.pageX === null){//mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + } + + thumb.find('.value').html($(this).val()); + }); + + $(document).on('mouseup touchend', range_wrapper, function() { + range_mousedown = false; + $(this).removeClass('active'); + }); + + $(document).on('mousemove touchmove', range_wrapper, function(e) { + var thumb = $(this).children('.thumb'); + var left; + if (range_mousedown) { + if (!thumb.hasClass('active')) { + thumb.velocity({ height: '30px', width: '30px', top: '-20px', marginLeft: '-15px'}, { duration: 300, easing: 'easeOutExpo' }); + } + if (e.pageX === undefined || e.pageX === null) { //mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + var width = $(this).outerWidth(); + + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + thumb.find('.value').html(thumb.siblings(range_type).val()); + } + }); + + $(document).on('mouseout touchleave', range_wrapper, function() { + if (!range_mousedown) { + + var thumb = $(this).children('.thumb'); + + if (thumb.hasClass('active')) { + thumb.velocity({ height: '0', width: '0', top: '10px', marginLeft: '-6px'}, { duration: 100 }); + } + thumb.removeClass('active'); + } + }); + + /************************** + * Auto complete plugin * + *************************/ + $.fn.autocomplete = function (options) { + // Defaults + var defaults = { + data: {} + }; + + options = $.extend(defaults, options); + + return this.each(function() { + var $input = $(this); + var data = options.data, + $inputDiv = $input.closest('.input-field'); // Div to append on + + // Check if data isn't empty + if (!$.isEmptyObject(data)) { + // Create autocomplete element + var $autocomplete = $(''); + + // Append autocomplete element + if ($inputDiv.length) { + $inputDiv.append($autocomplete); // Set ul in body + } else { + $input.after($autocomplete); + } + + var highlight = function(string, $el) { + var img = $el.find('img'); + var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""), + matchEnd = matchStart + string.length - 1, + beforeMatch = $el.text().slice(0, matchStart), + matchText = $el.text().slice(matchStart, matchEnd + 1), + afterMatch = $el.text().slice(matchEnd + 1); + $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + ""); + if (img.length) { + $el.prepend(img); + } + }; + + // Perform search + $input.on('keyup', function (e) { + // Capture Enter + if (e.which === 13) { + $autocomplete.find('li').first().click(); + return; + } + + var val = $input.val().toLowerCase(); + $autocomplete.empty(); + + // Check if the input isn't empty + if (val !== '') { + for(var key in data) { + if (data.hasOwnProperty(key) && + key.toLowerCase().indexOf(val) !== -1 && + key.toLowerCase() !== val) { + var autocompleteOption = $('
  • '); + if(!!data[key]) { + autocompleteOption.append(''+ key +''); + } else { + autocompleteOption.append(''+ key +''); + } + $autocomplete.append(autocompleteOption); + + highlight(val, autocompleteOption); + } + } + } + }); + + // Set input value + $autocomplete.on('click', 'li', function () { + $input.val($(this).text().trim()); + $input.trigger('change'); + $autocomplete.empty(); + }); + } + }); + }; + + }); // End of $(document).ready + + /******************* + * Select Plugin * + ******************/ + $.fn.material_select = function (callback) { + $(this).each(function(){ + var $select = $(this); + + if ($select.hasClass('browser-default')) { + return; // Continue to next (return false breaks out of entire loop) + } + + var multiple = $select.attr('multiple') ? true : false, + lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt + + if (lastID) { + $select.parent().find('span.caret').remove(); + $select.parent().find('input').remove(); + + $select.unwrap(); + $('ul#select-options-'+lastID).remove(); + } + + // If destroying the select, remove the selelct-id and reset it to it's uninitialized state. + if(callback === 'destroy') { + $select.data('select-id', null).removeClass('initialized'); + return; + } + + var uniqueID = Materialize.guid(); + $select.data('select-id', uniqueID); + var wrapper = $('
    '); + wrapper.addClass($select.attr('class')); + var options = $(''), + selectChildren = $select.children('option, optgroup'), + valuesSelected = [], + optionsHover = false; + + var label = $select.find('option:selected').html() || $select.find('option:first').html() || ""; + + // Function that renders and appends the option taking into + // account type and possible image icon. + var appendOptionWithIcon = function(select, option, type) { + // Add disabled attr if disabled + var disabledClass = (option.is(':disabled')) ? 'disabled ' : ''; + var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : ''; + + // add icons + var icon_url = option.data('icon'); + var classes = option.attr('class'); + if (!!icon_url) { + var classString = ''; + if (!!classes) classString = ' class="' + classes + '"'; + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
  • ' + option.html() + '
  • ')); + } else { + options.append($('
  • ' + option.html() + '
  • ')); + } + return true; + } + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
  • ' + option.html() + '
  • ')); + } else { + options.append($('
  • ' + option.html() + '
  • ')); + } + }; + + /* Create dropdown structure. */ + if (selectChildren.length) { + selectChildren.each(function() { + if ($(this).is('option')) { + // Direct descendant option. + if (multiple) { + appendOptionWithIcon($select, $(this), 'multiple'); + + } else { + appendOptionWithIcon($select, $(this)); + } + } else if ($(this).is('optgroup')) { + // Optgroup. + var selectOptions = $(this).children('option'); + options.append($('
  • ' + $(this).attr('label') + '
  • ')); + + selectOptions.each(function() { + appendOptionWithIcon($select, $(this), 'optgroup-option'); + }); + } + }); + } + + options.find('li:not(.optgroup)').each(function (i) { + $(this).click(function (e) { + // Check if option element is disabled + if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) { + var selected = true; + + if (multiple) { + $('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; }); + selected = toggleEntryFromArray(valuesSelected, $(this).index(), $select); + $newSelect.trigger('focus'); + } else { + options.find('li').removeClass('active'); + $(this).toggleClass('active'); + $newSelect.val($(this).text()); + } + + activateOption(options, $(this)); + $select.find('option').eq(i).prop('selected', selected); + // Trigger onchange() event + $select.trigger('change'); + if (typeof callback !== 'undefined') callback(); + } + + e.stopPropagation(); + }); + }); + + // Wrap Elements + $select.wrap(wrapper); + // Add Select Display Element + var dropdownIcon = $(''); + if ($select.is(':disabled')) + dropdownIcon.addClass('disabled'); + + // escape double quotes + var sanitizedLabelHtml = label.replace(/"/g, '"'); + + var $newSelect = $(''); + $select.before($newSelect); + $newSelect.before(dropdownIcon); + + $newSelect.after(options); + // Check if section element is disabled + if (!$select.is(':disabled')) { + $newSelect.dropdown({'hover': false, 'closeOnClick': false}); + } + + // Copy tabindex + if ($select.attr('tabindex')) { + $($newSelect[0]).attr('tabindex', $select.attr('tabindex')); + } + + $select.addClass('initialized'); + + $newSelect.on({ + 'focus': function (){ + if ($('ul.select-dropdown').not(options[0]).is(':visible')) { + $('input.select-dropdown').trigger('close'); + } + if (!options.is(':visible')) { + $(this).trigger('open', ['focus']); + var label = $(this).val(); + var selectedOption = options.find('li').filter(function() { + return $(this).text().toLowerCase() === label.toLowerCase(); + })[0]; + activateOption(options, selectedOption); + } + }, + 'click': function (e){ + e.stopPropagation(); + } + }); + + $newSelect.on('blur', function() { + if (!multiple) { + $(this).trigger('close'); + } + options.find('li.selected').removeClass('selected'); + }); + + options.hover(function() { + optionsHover = true; + }, function () { + optionsHover = false; + }); + + $(window).on({ + 'click': function () { + multiple && (optionsHover || $newSelect.trigger('close')); + } + }); + + // Add initial multiple selections. + if (multiple) { + $select.find("option:selected:not(:disabled)").each(function () { + var index = $(this).index(); + + toggleEntryFromArray(valuesSelected, index, $select); + options.find("li").eq(index).find(":checkbox").prop("checked", true); + }); + } + + // Make option as selected and scroll to selected position + var activateOption = function(collection, newOption) { + if (newOption) { + collection.find('li.selected').removeClass('selected'); + var option = $(newOption); + option.addClass('selected'); + options.scrollTo(option); + } + }; + + // Allow user to search by typing + // this array is cleared after 1 second + var filterQuery = [], + onKeyDown = function(e){ + // TAB - switch to another input + if(e.which == 9){ + $newSelect.trigger('close'); + return; + } + + // ARROW DOWN WHEN SELECT IS CLOSED - open select options + if(e.which == 40 && !options.is(':visible')){ + $newSelect.trigger('open'); + return; + } + + // ENTER WHEN SELECT IS CLOSED - submit form + if(e.which == 13 && !options.is(':visible')){ + return; + } + + e.preventDefault(); + + // CASE WHEN USER TYPE LETTERS + var letter = String.fromCharCode(e.which).toLowerCase(), + nonLetters = [9,13,27,38,40]; + if (letter && (nonLetters.indexOf(e.which) === -1)) { + filterQuery.push(letter); + + var string = filterQuery.join(''), + newOption = options.find('li').filter(function() { + return $(this).text().toLowerCase().indexOf(string) === 0; + })[0]; + + if (newOption) { + activateOption(options, newOption); + } + } + + // ENTER - select option and close when select options are opened + if (e.which == 13) { + var activeOption = options.find('li.selected:not(.disabled)')[0]; + if(activeOption){ + $(activeOption).trigger('click'); + if (!multiple) { + $newSelect.trigger('close'); + } + } + } + + // ARROW DOWN - move to next not disabled option + if (e.which == 40) { + if (options.find('li.selected').length) { + newOption = options.find('li.selected').next('li:not(.disabled)')[0]; + } else { + newOption = options.find('li:not(.disabled)')[0]; + } + activateOption(options, newOption); + } + + // ESC - close options + if (e.which == 27) { + $newSelect.trigger('close'); + } + + // ARROW UP - move to previous not disabled option + if (e.which == 38) { + newOption = options.find('li.selected').prev('li:not(.disabled)')[0]; + if(newOption) + activateOption(options, newOption); + } + + // Automaticaly clean filter query so user can search again by starting letters + setTimeout(function(){ filterQuery = []; }, 1000); + }; + + $newSelect.on('keydown', onKeyDown); + }); + + function toggleEntryFromArray(entriesArray, entryIndex, select) { + var index = entriesArray.indexOf(entryIndex), + notAdded = index === -1; + + if (notAdded) { + entriesArray.push(entryIndex); + } else { + entriesArray.splice(index, 1); + } + + select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active'); + + // use notAdded instead of true (to detect if the option is selected or not) + select.find('option').eq(entryIndex).prop('selected', notAdded); + setValueToInput(entriesArray, select); + + return notAdded; + } + + function setValueToInput(entriesArray, select) { + var value = ''; + + for (var i = 0, count = entriesArray.length; i < count; i++) { + var text = select.find('option').eq(entriesArray[i]).text(); + + i === 0 ? value += text : value += ', ' + text; + } + + if (value === '') { + value = select.find('option:disabled').eq(0).text(); + } + + select.siblings('input.select-dropdown').val(value); + } + }; + +}( jQuery )); +;(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + indicators: true, + height: 400, + transition: 500, + interval: 6000 + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each slider, we want to keep track of + // which slide is active and its associated content + var $this = $(this); + var $slider = $this.find('ul.slides').first(); + var $slides = $slider.find('> li'); + var $active_index = $slider.find('.active').index(); + var $active, $indicators, $interval; + if ($active_index != -1) { $active = $slides.eq($active_index); } + + // Transitions the caption depending on alignment + function captionTransition(caption, duration) { + if (caption.hasClass("center-align")) { + caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("right-align")) { + caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("left-align")) { + caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false}); + } + } + + // This function will transition the slide to any index of the next slide + function moveToSlide(index) { + // Wrap around indices. + if (index >= $slides.length) index = 0; + else if (index < 0) index = $slides.length -1; + + $active_index = $slider.find('.active').index(); + + // Only do if index changes + if ($active_index != index) { + $active = $slides.eq($active_index); + $caption = $active.find('.caption'); + + $active.removeClass('active'); + $active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad', + complete: function() { + $slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false}); + } }); + captionTransition($caption, options.transition); + + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).removeClass('active'); + } + + $slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).addClass('active'); + + + // Update indicators + if (options.indicators) { + $indicators.eq(index).addClass('active'); + } + } + } + + // Set height of slider + // If fullscreen, do nothing + if (!$this.hasClass('fullscreen')) { + if (options.indicators) { + // Add height if indicators are present + $this.height(options.height + 40); + } + else { + $this.height(options.height); + } + $slider.height(options.height); + } + + + // Set initial positions of captions + $slides.find('.caption').each(function () { + captionTransition($(this), 0); + }); + + // Move img src into background-image + $slides.find('img').each(function () { + var placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; + if ($(this).attr('src') !== placeholderBase64) { + $(this).css('background-image', 'url(' + $(this).attr('src') + ')' ); + $(this).attr('src', placeholderBase64); + } + }); + + // dynamically add indicators + if (options.indicators) { + $indicators = $('
      '); + $slides.each(function( index ) { + var $indicator = $('
    • '); + + // Handle clicks on indicators + $indicator.click(function () { + var $parent = $slider.parent(); + var curr_index = $parent.find($(this)).index(); + moveToSlide(curr_index); + + // reset interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + $indicators.append($indicator); + }); + $this.append($indicators); + $indicators = $this.find('ul.indicators').find('li.indicator-item'); + } + + if ($active) { + $active.show(); + } + else { + $slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + + $active_index = 0; + $active = $slides.eq($active_index); + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).addClass('active'); + } + } + + // Adjust height to current slide + $active.find('img').each(function() { + $active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + }); + + // auto scroll + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + + }, options.transition + options.interval + ); + + + // HammerJS, Swipe navigation + + // Touch Event + var panning = false; + var swipeLeft = false; + var swipeRight = false; + + $this.hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + + // reset interval + clearInterval($interval); + + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $curr_slide = $slider.find('.active'); + $curr_slide.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) { + swipeRight = true; + } + // Swipe Right + else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) { + swipeLeft = true; + } + + // Make Slide Behind active slide visible + var next_slide; + if (swipeLeft) { + next_slide = $curr_slide.next(); + if (next_slide.length === 0) { + next_slide = $slides.first(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + if (swipeRight) { + next_slide = $curr_slide.prev(); + if (next_slide.length === 0) { + next_slide = $slides.last(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + + } + + }).bind('panend', function(e) { + if (e.gesture.pointerType === "touch") { + + $curr_slide = $slider.find('.active'); + panning = false; + curr_index = $slider.find('.active').index(); + + if (!swipeRight && !swipeLeft || $slides.length <=1) { + // Return to original spot + $curr_slide.velocity({ translateX: 0 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else if (swipeLeft) { + moveToSlide(curr_index + 1); + $curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + else if (swipeRight) { + moveToSlide(curr_index - 1); + $curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + swipeLeft = false; + swipeRight = false; + + // Restart interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + } + }); + + $this.on('sliderPause', function() { + clearInterval($interval); + }); + + $this.on('sliderStart', function() { + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + + $this.on('sliderNext', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + }); + + $this.on('sliderPrev', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index - 1); + }); + + }); + + + + }, + pause : function() { + $(this).trigger('sliderPause'); + }, + start : function() { + $(this).trigger('sliderStart'); + }, + next : function() { + $(this).trigger('sliderNext'); + }, + prev : function() { + $(this).trigger('sliderPrev'); + } + }; + + + $.fn.slider = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' ); + } + }; // Plugin end +}( jQuery )); +;(function ($) { + $(document).ready(function() { + + $(document).on('click.card', '.card', function (e) { + if ($(this).find('> .card-reveal').length) { + if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) { + // Make Reveal animate down and display none + $(this).find('.card-reveal').velocity( + {translateY: 0}, { + duration: 225, + queue: false, + easing: 'easeInOutQuad', + complete: function() { $(this).css({ display: 'none'}); } + } + ); + } + else if ($(e.target).is($('.card .activator')) || + $(e.target).is($('.card .activator i')) ) { + $(e.target).closest('.card').css('overflow', 'hidden'); + $(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'}); + } + } + }); + + }); +}( jQuery ));;(function ($) { + var chipsHandleEvents = false; + var materialChipsDefaults = { + data: [], + placeholder: '', + secondaryPlaceholder: '', + }; + + $(document).ready(function() { + // Handle removal of static chips. + $(document).on('click', '.chip .close', function(e){ + var $chips = $(this).closest('.chips'); + if ($chips.attr('data-initialized')) { + return; + } + $(this).closest('.chip').remove(); + }); + }); + + $.fn.material_chip = function (options) { + var self = this; + this.$el = $(this); + this.$document = $(document); + this.SELS = { + CHIPS: '.chips', + CHIP: '.chip', + INPUT: 'input', + DELETE: '.material-icons', + SELECTED_CHIP: '.selected', + }; + + if ('data' === options) { + return this.$el.data('chips'); + } + + var curr_options = $.extend({}, materialChipsDefaults, options); + + + // Initialize + this.init = function() { + var i = 0; + var chips; + self.$el.each(function(){ + var $chips = $(this); + var chipId = Materialize.guid(); + + if (!curr_options.data || !(curr_options.data instanceof Array)) { + curr_options.data = []; + } + $chips.data('chips', curr_options.data); + $chips.attr('data-index', i); + $chips.attr('data-initialized', true); + + if (!$chips.hasClass(self.SELS.CHIPS)) { + $chips.addClass('chips'); + } + + self.chips($chips, chipId); + i++; + }); + }; + + this.handleEvents = function(){ + var SELS = self.SELS; + + self.$document.off('click.chips-focus', SELS.CHIPS).on('click.chips-focus', SELS.CHIPS, function(e){ + $(e.target).find(SELS.INPUT).focus(); + }); + + self.$document.off('click.chips-select', SELS.CHIP).on('click.chips-select', SELS.CHIP, function(e){ + $(SELS.CHIP).removeClass('selected'); + $(this).toggleClass('selected'); + }); + + self.$document.off('keydown.chips').on('keydown.chips', function(e){ + if ($(e.target).is('input, textarea')) { + return; + } + + // delete + var $chip = self.$document.find(SELS.CHIP + SELS.SELECTED_CHIP); + var $chips = $chip.closest(SELS.CHIPS); + var length = $chip.siblings(SELS.CHIP).length; + var index; + + if (!$chip.length) { + return; + } + + if (e.which === 8 || e.which === 46) { + e.preventDefault(); + + index = $chip.index(); + self.deleteChip(index, $chips); + + var selectIndex = null; + if ((index + 1) < length) { + selectIndex = index; + } else if (index === length || (index + 1) === length) { + selectIndex = length - 1; + } + + if (selectIndex < 0) selectIndex = null; + + if (null !== selectIndex) { + self.selectChip(selectIndex, $chips); + } + if (!length) $chips.find('input').focus(); + + // left + } else if (e.which === 37) { + index = $chip.index() - 1; + if (index < 0) { + return; + } + $(SELS.CHIP).removeClass('selected'); + self.selectChip(index, $chips); + + // right + } else if (e.which === 39) { + index = $chip.index() + 1; + $(SELS.CHIP).removeClass('selected'); + if (index > length) { + $chips.find('input').focus(); + return; + } + self.selectChip(index, $chips); + } + }); + + self.$document.off('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.addClass('focus'); + $currChips.siblings('label, .prefix').addClass('active'); + $(SELS.CHIP).removeClass('selected'); + }); + + self.$document.off('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.removeClass('focus'); + + // Remove active if empty + if (!$currChips.data('chips').length) { + $currChips.siblings('label').removeClass('active'); + } + $currChips.siblings('.prefix').removeClass('active'); + }); + + self.$document.off('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT).on('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var chipsLength = $chips.children(SELS.CHIP).length; + + // enter + if (13 === e.which) { + e.preventDefault(); + self.addChip({tag: $target.val()}, $chips); + $target.val(''); + return; + } + + // delete or left + if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) { + self.selectChip(chipsLength - 1, $chips); + $target.blur(); + return; + } + }); + + // Click on delete icon in chip. + self.$document.off('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE).on('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE, function(e) { + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var $chip = $target.closest(SELS.CHIP); + e.stopPropagation(); + self.deleteChip($chip.index(), $chips); + $chips.find('input').focus(); + }); + }; + + this.chips = function($chips, chipId) { + var html = ''; + $chips.data('chips').forEach(function(elem){ + html += self.renderChip(elem); + }); + html += ''; + $chips.html(html); + self.setPlaceholder($chips); + + // Set for attribute for label + var label = $chips.next('label'); + if (label.length) { + label.attr('for', chipId); + + if ($chips.data('chips').length) { + label.addClass('active'); + } + } + }; + + this.renderChip = function(elem) { + if (!elem.tag) return; + + var html = '
      ' + elem.tag; + if (elem.image) { + html += ' '; + } + html += 'close'; + html += '
      '; + return html; + }; + + this.setPlaceholder = function($chips) { + if ($chips.data('chips').length && curr_options.placeholder) { + $chips.find('input').prop('placeholder', curr_options.placeholder); + + } else if (!$chips.data('chips').length && curr_options.secondaryPlaceholder) { + $chips.find('input').prop('placeholder', curr_options.secondaryPlaceholder); + } + }; + + this.isValid = function($chips, elem) { + var chips = $chips.data('chips'); + var exists = false; + for (var i=0; i < chips.length; i++) { + if (chips[i].tag === elem.tag) { + exists = true; + return; + } + } + return '' !== elem.tag && !exists; + }; + + this.addChip = function(elem, $chips) { + if (!self.isValid($chips, elem)) { + return; + } + var chipHtml = self.renderChip(elem); + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + newData.push(oldData[i]); + } + newData.push(elem); + + $chips.data('chips', newData); + $(chipHtml).insertBefore($chips.find('input')); + $chips.trigger('chip.add', elem); + self.setPlaceholder($chips); + }; + + this.deleteChip = function(chipIndex, $chips) { + var chip = $chips.data('chips')[chipIndex]; + $chips.find('.chip').eq(chipIndex).remove(); + + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + if (i !== chipIndex) { + newData.push(oldData[i]); + } + } + + $chips.data('chips', newData); + $chips.trigger('chip.delete', chip); + self.setPlaceholder($chips); + }; + + this.selectChip = function(chipIndex, $chips) { + var $chip = $chips.find('.chip').eq(chipIndex); + if ($chip && false === $chip.hasClass('selected')) { + $chip.addClass('selected'); + $chips.trigger('chip.select', $chips.data('chips')[chipIndex]); + } + }; + + this.getChipsElement = function(index, $chips) { + return $chips.eq(index); + }; + + // init + this.init(); + + if (!chipsHandleEvents) { + this.handleEvents(); + chipsHandleEvents = true; + } + }; +}( jQuery ));;(function ($) { + $.fn.pushpin = function (options) { + // Defaults + var defaults = { + top: 0, + bottom: Infinity, + offset: 0 + }; + + // Remove pushpin event and classes + if (options === "remove") { + this.each(function () { + if (id = $(this).data('pushpin-id')) { + $(window).off('scroll.' + id); + $(this).removeData('pushpin-id').removeClass('pin-top pinned pin-bottom').removeAttr('style'); + } + }); + return false; + } + + options = $.extend(defaults, options); + + + $index = 0; + return this.each(function() { + var $uniqueId = Materialize.guid(), + $this = $(this), + $original_offset = $(this).offset().top; + + function removePinClasses(object) { + object.removeClass('pin-top'); + object.removeClass('pinned'); + object.removeClass('pin-bottom'); + } + + function updateElements(objects, scrolled) { + objects.each(function () { + // Add position fixed (because its between top and bottom) + if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) { + removePinClasses($(this)); + $(this).css('top', options.offset); + $(this).addClass('pinned'); + } + + // Add pin-top (when scrolled position is above top) + if (scrolled < options.top && !$(this).hasClass('pin-top')) { + removePinClasses($(this)); + $(this).css('top', 0); + $(this).addClass('pin-top'); + } + + // Add pin-bottom (when scrolled position is below bottom) + if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) { + removePinClasses($(this)); + $(this).addClass('pin-bottom'); + $(this).css('top', options.bottom - $original_offset); + } + }); + } + + $(this).data('pushpin-id', $uniqueId); + updateElements($this, $(window).scrollTop()); + $(window).on('scroll.' + $uniqueId, function () { + var $scrolled = $(window).scrollTop() + options.offset; + updateElements($this, $scrolled); + }); + + }); + + }; +}( jQuery ));;(function ($) { + $(document).ready(function() { + + // jQuery reverse + $.fn.reverse = [].reverse; + + // Hover behaviour: make sure this doesn't work on .click-to-toggle FABs! + $(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + openFABMenu($this); + }); + $(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + closeFABMenu($this); + }); + + // Toggle-on-click behaviour. + $(document).on('click.fabClickToggle', '.fixed-action-btn.click-to-toggle > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + if ($menu.hasClass('active')) { + closeFABMenu($menu); + } else { + openFABMenu($menu); + } + }); + + // Toolbar transition behaviour. + $(document).on('click.fabToolbar', '.fixed-action-btn.toolbar > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + FABtoToolbar($menu); + }); + + }); + + $.fn.extend({ + openFAB: function() { + openFABMenu($(this)); + }, + closeFAB: function() { + closeFABMenu($(this)); + }, + openToolbar: function() { + FABtoToolbar($(this)); + }, + closeToolbar: function() { + toolbarToFAB($(this)); + } + }); + + + var openFABMenu = function (btn) { + var $this = btn; + if ($this.hasClass('active') === false) { + + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.addClass('active'); + $this.find('ul .btn-floating').velocity( + { scaleY: ".4", scaleX: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 0 }); + + var time = 0; + $this.find('ul .btn-floating').reverse().each( function () { + $(this).velocity( + { opacity: "1", scaleX: "1", scaleY: "1", translateY: "0", translateX: '0'}, + { duration: 80, delay: time }); + time += 40; + }); + } + }; + + var closeFABMenu = function (btn) { + var $this = btn; + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.removeClass('active'); + var time = 0; + $this.find('ul .btn-floating').velocity("stop", true); + $this.find('ul .btn-floating').velocity( + { opacity: "0", scaleX: ".4", scaleY: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 80 } + ); + }; + + + /** + * Transform FAB into toolbar + * @param {Object} object jQuery object + */ + var FABtoToolbar = function(btn) { + if (btn.attr('data-open') === "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnRect = btn[0].getBoundingClientRect(); + var anchor = btn.find('> a').first(); + var menu = btn.find('> ul').first(); + var backdrop = $('
      '); + var fabColor = anchor.css('background-color'); + anchor.append(backdrop); + + offsetX = btnRect.left - (windowWidth / 2) + (btnRect.width / 2); + offsetY = windowHeight - btnRect.bottom; + scaleFactor = windowWidth / backdrop.width(); + btn.attr('data-origin-bottom', btnRect.bottom); + btn.attr('data-origin-left', btnRect.left); + btn.attr('data-origin-width', btnRect.width); + + // Set initial state + btn.addClass('active'); + btn.attr('data-open', true); + btn.css({ + 'text-align': 'center', + width: '100%', + bottom: 0, + left: 0, + transform: 'translateX(' + offsetX + 'px)', + transition: 'none' + }); + anchor.css({ + transform: 'translateY(' + -offsetY + 'px)', + transition: 'none' + }); + backdrop.css({ + 'background-color': fabColor + }); + + + setTimeout(function() { + btn.css({ + transform: '', + transition: 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s' + }); + anchor.css({ + overflow: 'visible', + transform: '', + transition: 'transform .2s' + }); + + setTimeout(function() { + btn.css({ + overflow: 'hidden', + 'background-color': fabColor + }); + backdrop.css({ + transform: 'scale(' + scaleFactor + ')', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + menu.find('> li > a').css({ + opacity: 1 + }); + + // Scroll to close. + $(window).on('scroll.fabToolbarClose', function() { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + }); + + $(document).on('click.fabToolbarClose', function(e) { + if (!$(e.target).closest(menu).length) { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + } + }); + }, 100); + }, 0); + }; + + /** + * Transform toolbar back into FAB + * @param {Object} object jQuery object + */ + var toolbarToFAB = function(btn) { + if (btn.attr('data-open') !== "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnWidth = btn.attr('data-origin-width'); + var btnBottom = btn.attr('data-origin-bottom'); + var btnLeft = btn.attr('data-origin-left'); + var anchor = btn.find('> .btn-floating').first(); + var menu = btn.find('> ul').first(); + var backdrop = btn.find('.fab-backdrop'); + var fabColor = anchor.css('background-color'); + + offsetX = btnLeft - (windowWidth / 2) + (btnWidth / 2); + offsetY = windowHeight - btnBottom; + scaleFactor = windowWidth / backdrop.width(); + + + // Hide backdrop + btn.removeClass('active'); + btn.attr('data-open', false); + btn.css({ + 'background-color': 'transparent', + transition: 'none' + }); + anchor.css({ + transition: 'none' + }); + backdrop.css({ + transform: 'scale(0)', + 'background-color': fabColor + }); + menu.find('> li > a').css({ + opacity: '' + }); + + setTimeout(function() { + backdrop.remove(); + + // Set initial state. + btn.css({ + 'text-align': '', + width: '', + bottom: '', + left: '', + overflow: '', + 'background-color': '', + transform: 'translate3d(' + -offsetX + 'px,0,0)' + }); + anchor.css({ + overflow: '', + transform: 'translate3d(0,' + offsetY + 'px,0)' + }); + + setTimeout(function() { + btn.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s' + }); + anchor.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + }, 20); + }, 200); + }; + + +}( jQuery )); +;(function ($) { + // Image transition function + Materialize.fadeInImage = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + element.css({opacity: 0}); + $(element).velocity({opacity: 1}, { + duration: 650, + queue: false, + easing: 'easeOutSine' + }); + $(element).velocity({opacity: 1}, { + duration: 1300, + queue: false, + easing: 'swing', + step: function(now, fx) { + fx.start = 100; + var grayscale_setting = now/100; + var brightness_setting = 150 - (100 - now)/1.75; + + if (brightness_setting < 100) { + brightness_setting = 100; + } + if (now >= 0) { + $(this).css({ + "-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)", + "filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)" + }); + } + } + }); + }; + + // Horizontal staggered list + Materialize.showStaggeredList = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + var time = 0; + element.find('li').velocity( + { translateX: "-100px"}, + { duration: 0 }); + + element.find('li').each(function() { + $(this).velocity( + { opacity: "1", translateX: "0"}, + { duration: 800, delay: time, easing: [60, 10] }); + time += 120; + }); + }; + + + $(document).ready(function() { + // Hardcoded .staggered-list scrollFire + // var staggeredListOptions = []; + // $('ul.staggered-list').each(function (i) { + + // var label = 'scrollFire-' + i; + // $(this).addClass(label); + // staggeredListOptions.push( + // {selector: 'ul.staggered-list.' + label, + // offset: 200, + // callback: 'showStaggeredList("ul.staggered-list.' + label + '")'}); + // }); + // scrollFire(staggeredListOptions); + + // HammerJS, Swipe navigation + + // Touch Event + var swipeLeft = false; + var swipeRight = false; + + + // Dismissible Collections + $('.dismissable').each(function() { + $(this).hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + var $this = $(this); + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $this.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) { + swipeLeft = true; + } + + // Swipe Right + if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) { + swipeRight = true; + } + } + }).bind('panend', function(e) { + // Reset if collection is moved back into original position + if (Math.abs(e.gesture.deltaX) < ($(this).innerWidth() / 2)) { + swipeRight = false; + swipeLeft = false; + } + + if (e.gesture.pointerType === "touch") { + var $this = $(this); + if (swipeLeft || swipeRight) { + var fullWidth; + if (swipeLeft) { fullWidth = $this.innerWidth(); } + else { fullWidth = -1 * $this.innerWidth(); } + + $this.velocity({ translateX: fullWidth, + }, {duration: 100, queue: false, easing: 'easeOutQuad', complete: + function() { + $this.css('border', 'none'); + $this.velocity({ height: 0, padding: 0, + }, {duration: 200, queue: false, easing: 'easeOutQuad', complete: + function() { $this.remove(); } + }); + } + }); + } + else { + $this.velocity({ translateX: 0, + }, {duration: 100, queue: false, easing: 'easeOutQuad'}); + } + swipeLeft = false; + swipeRight = false; + } + }); + + }); + + + // time = 0 + // // Vertical Staggered list + // $('ul.staggered-list.vertical li').velocity( + // { translateY: "100px"}, + // { duration: 0 }); + + // $('ul.staggered-list.vertical li').each(function() { + // $(this).velocity( + // { opacity: "1", translateY: "0"}, + // { duration: 800, delay: time, easing: [60, 25] }); + // time += 120; + // }); + + // // Fade in and Scale + // $('.fade-in.scale').velocity( + // { scaleX: .4, scaleY: .4, translateX: -600}, + // { duration: 0}); + // $('.fade-in').each(function() { + // $(this).velocity( + // { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0}, + // { duration: 800, easing: [60, 10] }); + // }); + }); +}( jQuery )); +;(function($) { + + // Input: Array of JSON objects {selector, offset, callback} + + Materialize.scrollFire = function(options) { + + var didScroll = false; + + window.addEventListener("scroll", function() { + didScroll = true; + }); + + // Rate limit to 100ms + setInterval(function() { + if(didScroll) { + didScroll = false; + + var windowScroll = window.pageYOffset + window.innerHeight; + + for (var i = 0 ; i < options.length; i++) { + // Get options from each line + var value = options[i]; + var selector = value.selector, + offset = value.offset, + callback = value.callback; + + var currentElement = document.querySelector(selector); + if ( currentElement !== null) { + var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset; + + if (windowScroll > (elementOffset + offset)) { + if (value.done !== true) { + if (typeof(callback) === 'function') { + callback.call(this, currentElement); + } else if (typeof(callback) === 'string') { + var callbackFunc = new Function(callback); + callbackFunc(currentElement); + } + value.done = true; + } + } + } + } + } + }, 100); + }; + +})(jQuery); +;/*! + * pickadate.js v3.5.0, 2014/04/13 + * By Amsul, http://amsul.ca + * Hosted on http://amsul.github.io/pickadate.js + * Licensed under MIT + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( 'picker', ['jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('jquery') ) + + // Browser globals. + else this.Picker = factory( jQuery ) + +}(function( $ ) { + +var $window = $( window ) +var $document = $( document ) +var $html = $( document.documentElement ) + + +/** + * The picker constructor that creates a blank picker. + */ +function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { + + // If there’s no element, return the picker constructor. + if ( !ELEMENT ) return PickerConstructor + + + var + IS_DEFAULT_THEME = false, + + + // The state of the picker. + STATE = { + id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) + }, + + + // Merge the defaults and options passed. + SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {}, + + + // Merge the default classes with the settings classes. + CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ), + + + // The element node wrapper into a jQuery object. + $ELEMENT = $( ELEMENT ), + + + // Pseudo picker constructor. + PickerInstance = function() { + return this.start() + }, + + + // The picker prototype. + P = PickerInstance.prototype = { + + constructor: PickerInstance, + + $node: $ELEMENT, + + + /** + * Initialize everything + */ + start: function() { + + // If it’s already started, do nothing. + if ( STATE && STATE.start ) return P + + + // Update the picker states. + STATE.methods = {} + STATE.start = true + STATE.open = false + STATE.type = ELEMENT.type + + + // Confirm focus state, convert into text input to remove UA stylings, + // and set as readonly to prevent keyboard popup. + ELEMENT.autofocus = ELEMENT == getActiveElement() + ELEMENT.readOnly = !SETTINGS.editable + ELEMENT.id = ELEMENT.id || STATE.id + if ( ELEMENT.type != 'text' ) { + ELEMENT.type = 'text' + } + + + // Create a new picker component with the settings. + P.component = new COMPONENT(P, SETTINGS) + + + // Create the picker root with a holder and then prepare it. + P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"') ) + prepareElementRoot() + + + // If there’s a format for the hidden input element, create the element. + if ( SETTINGS.formatSubmit ) { + prepareElementHidden() + } + + + // Prepare the input element. + prepareElement() + + + // Insert the root as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) + else $ELEMENT.after( P.$root ) + + + // Bind the default component and settings events. + P.on({ + start: P.component.onStart, + render: P.component.onRender, + stop: P.component.onStop, + open: P.component.onOpen, + close: P.component.onClose, + set: P.component.onSet + }).on({ + start: SETTINGS.onStart, + render: SETTINGS.onRender, + stop: SETTINGS.onStop, + open: SETTINGS.onOpen, + close: SETTINGS.onClose, + set: SETTINGS.onSet + }) + + + // Once we’re all set, check the theme in use. + IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] ) + + + // If the element has autofocus, open the picker. + if ( ELEMENT.autofocus ) { + P.open() + } + + + // Trigger queued the “start” and “render” events. + return P.trigger( 'start' ).trigger( 'render' ) + }, //start + + + /** + * Render a new picker + */ + render: function( entireComponent ) { + + // Insert a new component holder in the root or box. + if ( entireComponent ) P.$root.html( createWrappedComponent() ) + else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) + + // Trigger the queued “render” events. + return P.trigger( 'render' ) + }, //render + + + /** + * Destroy everything + */ + stop: function() { + + // If it’s already stopped, do nothing. + if ( !STATE.start ) return P + + // Then close the picker. + P.close() + + // Remove the hidden field. + if ( P._hidden ) { + P._hidden.parentNode.removeChild( P._hidden ) + } + + // Remove the root. + P.$root.remove() + + // Remove the input class, remove the stored data, and unbind + // the events (after a tick for IE - see `P.close`). + $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) + setTimeout( function() { + $ELEMENT.off( '.' + STATE.id ) + }, 0) + + // Restore the element state + ELEMENT.type = STATE.type + ELEMENT.readOnly = false + + // Trigger the queued “stop” events. + P.trigger( 'stop' ) + + // Reset the picker states. + STATE.methods = {} + STATE.start = false + + return P + }, //stop + + + /** + * Open up the picker + */ + open: function( dontGiveFocus ) { + + // If it’s already open, do nothing. + if ( STATE.open ) return P + + // Add the “active” class. + $ELEMENT.addClass( CLASSES.active ) + aria( ELEMENT, 'expanded', true ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So add the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Add the “opened” class to the picker root. + P.$root.addClass( CLASSES.opened ) + aria( P.$root[0], 'hidden', false ) + + }, 0 ) + + // If we have to give focus, bind the element and doc events. + if ( dontGiveFocus !== false ) { + + // Set it as open. + STATE.open = true + + // Prevent the page from scrolling. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', 'hidden' ). + css( 'padding-right', '+=' + getScrollbarWidth() ) + } + + // Pass focus to the root element’s jQuery object. + // * Workaround for iOS8 to bring the picker’s root into view. + P.$root.eq(0).focus() + + // Bind the document events. + $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { + + var target = event.target + + // If the target of the event is not the element, close the picker picker. + // * Don’t worry about clicks or focusins on the root because those don’t bubble up. + // Also, for Firefox, a click on an `option` element bubbles up directly + // to the doc. So make sure the target wasn't the doc. + // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling, + // which causes the picker to unexpectedly close when right-clicking it. So make + // sure the event wasn’t a right-click. + if ( target != ELEMENT && target != document && event.which != 3 ) { + + // If the target was the holder that covers the screen, + // keep the element focused to maintain tabindex. + P.close( target === P.$root.children()[0] ) + } + + }).on( 'keydown.' + STATE.id, function( event ) { + + var + // Get the keycode. + keycode = event.keyCode, + + // Translate that to a selection change. + keycodeToMove = P.component.key[ keycode ], + + // Grab the target. + target = event.target + + + // On escape, close the picker and give focus. + if ( keycode == 27 ) { + P.close( true ) + } + + + // Check if there is a key movement or “enter” keypress on the element. + else if ( target == P.$root[0] && ( keycodeToMove || keycode == 13 ) ) { + + // Prevent the default action to stop page movement. + event.preventDefault() + + // Trigger the key movement action. + if ( keycodeToMove ) { + PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] ) + } + + // On “enter”, if the highlighted item isn’t disabled, set the value and close. + else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) { + P.set( 'select', P.component.item.highlight ).close() + } + } + + + // If the target is within the root and “enter” is pressed, + // prevent the default action and trigger a click on the target instead. + else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { + event.preventDefault() + target.click() + } + }) + } + + // Trigger the queued “open” events. + return P.trigger( 'open' ) + }, //open + + + /** + * Close the picker + */ + close: function( giveFocus ) { + + // If we need to give focus, do it before changing states. + if ( giveFocus ) { + // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :| + // The focus is triggered *after* the close has completed - causing it + // to open again. So unbind and rebind the event at the next tick. + P.$root.off( 'focus.toOpen' ).eq(0).focus() + setTimeout( function() { + P.$root.on( 'focus.toOpen', handleFocusToOpenEvent ) + }, 0 ) + } + + // Remove the “active” class. + $ELEMENT.removeClass( CLASSES.active ) + aria( ELEMENT, 'expanded', false ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So remove the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Remove the “opened” and “focused” class from the picker root. + P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) + aria( P.$root[0], 'hidden', true ) + + }, 0 ) + + // If it’s already closed, do nothing more. + if ( !STATE.open ) return P + + // Set it as closed. + STATE.open = false + + // Allow the page to scroll. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', '' ). + css( 'padding-right', '-=' + getScrollbarWidth() ) + } + + // Unbind the document events. + $document.off( '.' + STATE.id ) + + // Trigger the queued “close” events. + return P.trigger( 'close' ) + }, //close + + + /** + * Clear the values + */ + clear: function( options ) { + return P.set( 'clear', null, options ) + }, //clear + + + /** + * Set something + */ + set: function( thing, value, options ) { + + var thingItem, thingValue, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + // Make sure we have usable options. + options = thingIsObject && $.isPlainObject( value ) ? value : options || {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = value + } + + // Go through the things of items to set. + for ( thingItem in thingObject ) { + + // Grab the value of the thing. + thingValue = thingObject[ thingItem ] + + // First, if the item exists and there’s a value, set it. + if ( thingItem in P.component.item ) { + if ( thingValue === undefined ) thingValue = null + P.component.set( thingItem, thingValue, options ) + } + + // Then, check to update the element value and broadcast a change. + if ( thingItem == 'select' || thingItem == 'clear' ) { + $ELEMENT. + val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ). + trigger( 'change' ) + } + } + + // Render a new picker. + P.render() + } + + // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`. + return options.muted ? P : P.trigger( 'set', thingObject ) + }, //set + + + /** + * Get something + */ + get: function( thing, format ) { + + // Make sure there’s something to get. + thing = thing || 'value' + + // If a picker state exists, return that. + if ( STATE[ thing ] != null ) { + return STATE[ thing ] + } + + // Return the submission value, if that. + if ( thing == 'valueSubmit' ) { + if ( P._hidden ) { + return P._hidden.value + } + thing = 'value' + } + + // Return the value, if that. + if ( thing == 'value' ) { + return ELEMENT.value + } + + // Check if a component item exists, return that. + if ( thing in P.component.item ) { + if ( typeof format == 'string' ) { + var thingValue = P.component.get( thing ) + return thingValue ? + PickerConstructor._.trigger( + P.component.formats.toString, + P.component, + [ format, thingValue ] + ) : '' + } + return P.component.get( thing ) + } + }, //get + + + + /** + * Bind events on the things. + */ + on: function( thing, method, internal ) { + + var thingName, thingMethod, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = method + } + + // Go through the things to bind to. + for ( thingName in thingObject ) { + + // Grab the method of the thing. + thingMethod = thingObject[ thingName ] + + // If it was an internal binding, prefix it. + if ( internal ) { + thingName = '_' + thingName + } + + // Make sure the thing methods collection exists. + STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] + + // Add the method to the relative method collection. + STATE.methods[ thingName ].push( thingMethod ) + } + } + + return P + }, //on + + + + /** + * Unbind events on the things. + */ + off: function() { + var i, thingName, + names = arguments; + for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { + thingName = names[i] + if ( thingName in STATE.methods ) { + delete STATE.methods[thingName] + } + } + return P + }, + + + /** + * Fire off method events. + */ + trigger: function( name, data ) { + var _trigger = function( name ) { + var methodList = STATE.methods[ name ] + if ( methodList ) { + methodList.map( function( method ) { + PickerConstructor._.trigger( method, P, [ data ] ) + }) + } + } + _trigger( '_' + name ) + _trigger( name ) + return P + } //trigger + } //PickerInstance.prototype + + + /** + * Wrap the picker holder components together. + */ + function createWrappedComponent() { + + // Create a picker wrapper holder + return PickerConstructor._.node( 'div', + + // Create a picker wrapper node + PickerConstructor._.node( 'div', + + // Create a picker frame + PickerConstructor._.node( 'div', + + // Create a picker box node + PickerConstructor._.node( 'div', + + // Create the components nodes. + P.component.nodes( STATE.open ), + + // The picker box class + CLASSES.box + ), + + // Picker wrap class + CLASSES.wrap + ), + + // Picker frame class + CLASSES.frame + ), + + // Picker holder class + CLASSES.holder + ) //endreturn + } //createWrappedComponent + + + + /** + * Prepare the input element with all bindings. + */ + function prepareElement() { + + $ELEMENT. + + // Store the picker data by component name. + data(NAME, P). + + // Add the “input” class name. + addClass(CLASSES.input). + + // Remove the tabindex. + attr('tabindex', -1). + + // If there’s a `data-value`, update the value of the element. + val( $ELEMENT.data('value') ? + P.get('select', SETTINGS.format) : + ELEMENT.value + ) + + + // Only bind keydown events if the element isn’t editable. + if ( !SETTINGS.editable ) { + + $ELEMENT. + + // On focus/click, focus onto the root to open it up. + on( 'focus.' + STATE.id + ' click.' + STATE.id, function( event ) { + event.preventDefault() + P.$root.eq(0).focus() + }). + + // Handle keyboard event based on the picker being opened or not. + on( 'keydown.' + STATE.id, handleKeydownEvent ) + } + + + // Update the aria attributes. + aria(ELEMENT, { + haspopup: true, + expanded: false, + readonly: false, + owns: ELEMENT.id + '_root' + }) + } + + + /** + * Prepare the root picker element with all bindings. + */ + function prepareElementRoot() { + + P.$root. + + on({ + + // For iOS8. + keydown: handleKeydownEvent, + + // When something within the root is focused, stop from bubbling + // to the doc and remove the “focused” state from the root. + focusin: function( event ) { + P.$root.removeClass( CLASSES.focused ) + event.stopPropagation() + }, + + // When something within the root holder is clicked, stop it + // from bubbling to the doc. + 'mousedown click': function( event ) { + + var target = event.target + + // Make sure the target isn’t the root holder so it can bubble up. + if ( target != P.$root.children()[ 0 ] ) { + + event.stopPropagation() + + // * For mousedown events, cancel the default action in order to + // prevent cases where focus is shifted onto external elements + // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). + // Also, for Firefox, don’t prevent action on the `option` element. + if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) { + + event.preventDefault() + + // Re-focus onto the root so that users can click away + // from elements focused within the picker. + P.$root.eq(0).focus() + } + } + } + }). + + // Add/remove the “target” class on focus and blur. + on({ + focus: function() { + $ELEMENT.addClass( CLASSES.target ) + }, + blur: function() { + $ELEMENT.removeClass( CLASSES.target ) + } + }). + + // Open the picker and adjust the root “focused” state + on( 'focus.toOpen', handleFocusToOpenEvent ). + + // If there’s a click on an actionable element, carry out the actions. + on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() { + + var $target = $( this ), + targetData = $target.data(), + targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ), + + // * For IE, non-focusable elements can be active elements as well + // (http://stackoverflow.com/a/2684561). + activeElement = getActiveElement() + activeElement = activeElement && ( activeElement.type || activeElement.href ) + + // If it’s disabled or nothing inside is actively focused, re-focus the element. + if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { + P.$root.eq(0).focus() + } + + // If something is superficially changed, update the `highlight` based on the `nav`. + if ( !targetDisabled && targetData.nav ) { + P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } ) + } + + // If something is picked, set `select` then close with focus. + else if ( !targetDisabled && 'pick' in targetData ) { + P.set( 'select', targetData.pick ) + } + + // If a “clear” button is pressed, empty the values and close with focus. + else if ( targetData.clear ) { + P.clear().close( true ) + } + + else if ( targetData.close ) { + P.close( true ) + } + + }) //P.$root + + aria( P.$root[0], 'hidden', true ) + } + + + /** + * Prepare the hidden input element along with all bindings. + */ + function prepareElementHidden() { + + var name + + if ( SETTINGS.hiddenName === true ) { + name = ELEMENT.name + ELEMENT.name = '' + } + else { + name = [ + typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', + typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' + ] + name = name[0] + ELEMENT.name + name[1] + } + + P._hidden = $( + '' + )[0] + + $ELEMENT. + + // If the value changes, update the hidden input with the correct format. + on('change.' + STATE.id, function() { + P._hidden.value = ELEMENT.value ? + P.get('select', SETTINGS.formatSubmit) : + '' + }) + + + // Insert the hidden input as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P._hidden ) + else $ELEMENT.after( P._hidden ) + } + + + // For iOS8. + function handleKeydownEvent( event ) { + + var keycode = event.keyCode, + + // Check if one of the delete keys was pressed. + isKeycodeDelete = /^(8|46)$/.test(keycode) + + // For some reason IE clears the input value on “escape”. + if ( keycode == 27 ) { + P.close() + return false + } + + // Check if `space` or `delete` was pressed or the picker is closed with a key movement. + if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { + + // Prevent it from moving the page and bubbling to doc. + event.preventDefault() + event.stopPropagation() + + // If `delete` was pressed, clear the values and close the picker. + // Otherwise open the picker. + if ( isKeycodeDelete ) { P.clear().close() } + else { P.open() } + } + } + + + // Separated for IE + function handleFocusToOpenEvent( event ) { + + // Stop the event from propagating to the doc. + event.stopPropagation() + + // If it’s a focus event, add the “focused” class to the root. + if ( event.type == 'focus' ) { + P.$root.addClass( CLASSES.focused ) + } + + // And then finally open the picker. + P.open() + } + + + // Return a new picker instance. + return new PickerInstance() +} //PickerConstructor + + + +/** + * The default classes and prefix to use for the HTML classes. + */ +PickerConstructor.klasses = function( prefix ) { + prefix = prefix || 'picker' + return { + + picker: prefix, + opened: prefix + '--opened', + focused: prefix + '--focused', + + input: prefix + '__input', + active: prefix + '__input--active', + target: prefix + '__input--target', + + holder: prefix + '__holder', + + frame: prefix + '__frame', + wrap: prefix + '__wrap', + + box: prefix + '__box' + } +} //PickerConstructor.klasses + + + +/** + * Check if the default theme is being used. + */ +function isUsingDefaultTheme( element ) { + + var theme, + prop = 'position' + + // For IE. + if ( element.currentStyle ) { + theme = element.currentStyle[prop] + } + + // For normal browsers. + else if ( window.getComputedStyle ) { + theme = getComputedStyle( element )[prop] + } + + return theme == 'fixed' +} + + + +/** + * Get the width of the browser’s scrollbar. + * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js + */ +function getScrollbarWidth() { + + if ( $html.height() <= $window.height() ) { + return 0 + } + + var $outer = $( '
      ' ). + appendTo( 'body' ) + + // Get the width without scrollbars. + var widthWithoutScroll = $outer[0].offsetWidth + + // Force adding scrollbars. + $outer.css( 'overflow', 'scroll' ) + + // Add the inner div. + var $inner = $( '
      ' ).appendTo( $outer ) + + // Get the width with scrollbars. + var widthWithScroll = $inner[0].offsetWidth + + // Remove the divs. + $outer.remove() + + // Return the difference between the widths. + return widthWithoutScroll - widthWithScroll +} + + + +/** + * PickerConstructor helper methods. + */ +PickerConstructor._ = { + + /** + * Create a group of nodes. Expects: + * ` + { + min: {Integer}, + max: {Integer}, + i: {Integer}, + node: {String}, + item: {Function} + } + * ` + */ + group: function( groupObject ) { + + var + // Scope for the looped object + loopObjectScope, + + // Create the nodes list + nodesList = '', + + // The counter starts from the `min` + counter = PickerConstructor._.trigger( groupObject.min, groupObject ) + + + // Loop from the `min` to `max`, incrementing by `i` + for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { + + // Trigger the `item` function within scope of the object + loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) + + // Splice the subgroup and create nodes out of the sub nodes + nodesList += PickerConstructor._.node( + groupObject.node, + loopObjectScope[ 0 ], // the node + loopObjectScope[ 1 ], // the classes + loopObjectScope[ 2 ] // the attributes + ) + } + + // Return the list of nodes + return nodesList + }, //group + + + /** + * Create a dom node string + */ + node: function( wrapper, item, klass, attribute ) { + + // If the item is false-y, just return an empty string + if ( !item ) return '' + + // If the item is an array, do a join + item = $.isArray( item ) ? item.join( '' ) : item + + // Check for the class + klass = klass ? ' class="' + klass + '"' : '' + + // Check for any attributes + attribute = attribute ? ' ' + attribute : '' + + // Return the wrapped item + return '<' + wrapper + klass + attribute + '>' + item + '' + }, //node + + + /** + * Lead numbers below 10 with a zero. + */ + lead: function( number ) { + return ( number < 10 ? '0': '' ) + number + }, + + + /** + * Trigger a function otherwise return the value. + */ + trigger: function( callback, scope, args ) { + return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback + }, + + + /** + * If the second character is a digit, length is 2 otherwise 1. + */ + digits: function( string ) { + return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 + }, + + + /** + * Tell if something is a date object. + */ + isDate: function( value ) { + return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) + }, + + + /** + * Tell if something is an integer. + */ + isInteger: function( value ) { + return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 + }, + + + /** + * Create ARIA attribute strings. + */ + ariaAttr: ariaAttr +} //PickerConstructor._ + + + +/** + * Extend the picker with a component and defaults. + */ +PickerConstructor.extend = function( name, Component ) { + + // Extend jQuery. + $.fn[ name ] = function( options, action ) { + + // Grab the component data. + var componentData = this.data( name ) + + // If the picker is requested, return the data object. + if ( options == 'picker' ) { + return componentData + } + + // If the component data exists and `options` is a string, carry out the action. + if ( componentData && typeof options == 'string' ) { + return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) + } + + // Otherwise go through each matched element and if the component + // doesn’t exist, create a new picker using `this` element + // and merging the defaults and options with a deep copy. + return this.each( function() { + var $this = $( this ) + if ( !$this.data( name ) ) { + new PickerConstructor( this, name, Component, options ) + } + }) + } + + // Set the defaults. + $.fn[ name ].defaults = Component.defaults +} //PickerConstructor.extend + + + +function aria(element, attribute, value) { + if ( $.isPlainObject(attribute) ) { + for ( var key in attribute ) { + ariaSet(element, key, attribute[key]) + } + } + else { + ariaSet(element, attribute, value) + } +} +function ariaSet(element, attribute, value) { + element.setAttribute( + (attribute == 'role' ? '' : 'aria-') + attribute, + value + ) +} +function ariaAttr(attribute, data) { + if ( !$.isPlainObject(attribute) ) { + attribute = { attribute: data } + } + data = '' + for ( var key in attribute ) { + var attr = (key == 'role' ? '' : 'aria-') + key, + attrVal = attribute[key] + data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' + } + return data +} + +// IE8 bug throws an error for activeElements within iframes. +function getActiveElement() { + try { + return document.activeElement + } catch ( err ) { } +} + + + +// Expose the picker constructor. +return PickerConstructor + + +})); + + +;/*! + * Date picker for pickadate.js v3.5.0 + * http://amsul.github.io/pickadate.js/date.htm + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( ['picker', 'jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('./picker.js'), require('jquery') ) + + // Browser globals. + else factory( Picker, jQuery ) + +}(function( Picker, $ ) { + + +/** + * Globals and constants + */ +var DAYS_IN_WEEK = 7, + WEEKS_IN_CALENDAR = 6, + _ = Picker._ + + + +/** + * The date picker constructor + */ +function DatePicker( picker, settings ) { + + var calendar = this, + element = picker.$node[ 0 ], + elementValue = element.value, + elementDataValue = picker.$node.data( 'value' ), + valueString = elementDataValue || elementValue, + formatString = elementDataValue ? settings.formatSubmit : settings.format, + isRTL = function() { + + return element.currentStyle ? + + // For IE. + element.currentStyle.direction == 'rtl' : + + // For normal browsers. + getComputedStyle( picker.$root[0] ).direction == 'rtl' + } + + calendar.settings = settings + calendar.$node = picker.$node + + // The queue of methods that will be used to build item objects. + calendar.queue = { + min: 'measure create', + max: 'measure create', + now: 'now create', + select: 'parse create validate', + highlight: 'parse navigate create validate', + view: 'parse create validate viewset', + disable: 'deactivate', + enable: 'activate' + } + + // The component's item object. + calendar.item = {} + + calendar.item.clear = null + calendar.item.disable = ( settings.disable || [] ).slice( 0 ) + calendar.item.enable = -(function( collectionDisabled ) { + return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 + })( calendar.item.disable ) + + calendar. + set( 'min', settings.min ). + set( 'max', settings.max ). + set( 'now' ) + + // When there’s a value, set the `select`, which in turn + // also sets the `highlight` and `view`. + if ( valueString ) { + calendar.set( 'select', valueString, { format: formatString }) + } + + // If there’s no value, default to highlighting “today”. + else { + calendar. + set( 'select', null ). + set( 'highlight', calendar.item.now ) + } + + + // The keycode to movement mapping. + calendar.key = { + 40: 7, // Down + 38: -7, // Up + 39: function() { return isRTL() ? -1 : 1 }, // Right + 37: function() { return isRTL() ? 1 : -1 }, // Left + go: function( timeChange ) { + var highlightedObject = calendar.item.highlight, + targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) + calendar.set( + 'highlight', + targetDate, + { interval: timeChange } + ) + this.render() + } + } + + + // Bind some picker events. + picker. + on( 'render', function() { + picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) + } + }) + picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) + } + }) + }, 1 ). + on( 'open', function() { + var includeToday = '' + if ( calendar.disabled( calendar.get('now') ) ) { + includeToday = ':not(.' + settings.klass.buttonToday + ')' + } + picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false ) + }, 1 ). + on( 'close', function() { + picker.$root.find( 'button, select' ).attr( 'disabled', true ) + }, 1 ) + +} //DatePicker + + +/** + * Set a datepicker item object. + */ +DatePicker.prototype.set = function( type, value, options ) { + + var calendar = this, + calendarItem = calendar.item + + // If the value is `null` just set it immediately. + if ( value === null ) { + if ( type == 'clear' ) type = 'select' + calendarItem[ type ] = value + return calendar + } + + // Otherwise go through the queue of methods, and invoke the functions. + // Update this as the time unit, and set the final value as this item. + // * In the case of `enable`, keep the queue but set `disable` instead. + // And in the case of `flip`, keep the queue but set `enable` instead. + calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { + value = calendar[ method ]( type, value, options ) + return value + }).pop() + + // Check if we need to cascade through more updates. + if ( type == 'select' ) { + calendar.set( 'highlight', calendarItem.select, options ) + } + else if ( type == 'highlight' ) { + calendar.set( 'view', calendarItem.highlight, options ) + } + else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { + if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) { + calendar.set( 'select', calendarItem.select, options ) + } + if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) { + calendar.set( 'highlight', calendarItem.highlight, options ) + } + } + + return calendar +} //DatePicker.prototype.set + + +/** + * Get a datepicker item object. + */ +DatePicker.prototype.get = function( type ) { + return this.item[ type ] +} //DatePicker.prototype.get + + +/** + * Create a picker date object. + */ +DatePicker.prototype.create = function( type, value, options ) { + + var isInfiniteValue, + calendar = this + + // If there’s no value, use the type as the value. + value = value === undefined ? type : value + + + // If it’s infinity, update the value. + if ( value == -Infinity || value == Infinity ) { + isInfiniteValue = value + } + + // If it’s an object, use the native date object. + else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { + value = value.obj + } + + // If it’s an array, convert it into a date and make sure + // that it’s a valid date – otherwise default to today. + else if ( $.isArray( value ) ) { + value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) + value = _.isDate( value ) ? value : calendar.create().obj + } + + // If it’s a number or date object, make a normalized date. + else if ( _.isInteger( value ) || _.isDate( value ) ) { + value = calendar.normalize( new Date( value ), options ) + } + + // If it’s a literal true or any other case, set it to now. + else /*if ( value === true )*/ { + value = calendar.now( type, value, options ) + } + + // Return the compiled object. + return { + year: isInfiniteValue || value.getFullYear(), + month: isInfiniteValue || value.getMonth(), + date: isInfiniteValue || value.getDate(), + day: isInfiniteValue || value.getDay(), + obj: isInfiniteValue || value, + pick: isInfiniteValue || value.getTime() + } +} //DatePicker.prototype.create + + +/** + * Create a range limit object using an array, date object, + * literal “true”, or integer relative to another time. + */ +DatePicker.prototype.createRange = function( from, to ) { + + var calendar = this, + createDate = function( date ) { + if ( date === true || $.isArray( date ) || _.isDate( date ) ) { + return calendar.create( date ) + } + return date + } + + // Create objects if possible. + if ( !_.isInteger( from ) ) { + from = createDate( from ) + } + if ( !_.isInteger( to ) ) { + to = createDate( to ) + } + + // Create relative dates. + if ( _.isInteger( from ) && $.isPlainObject( to ) ) { + from = [ to.year, to.month, to.date + from ]; + } + else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { + to = [ from.year, from.month, from.date + to ]; + } + + return { + from: createDate( from ), + to: createDate( to ) + } +} //DatePicker.prototype.createRange + + +/** + * Check if a date unit falls within a date range object. + */ +DatePicker.prototype.withinRange = function( range, dateUnit ) { + range = this.createRange(range.from, range.to) + return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick +} + + +/** + * Check if two date range objects overlap. + */ +DatePicker.prototype.overlapRanges = function( one, two ) { + + var calendar = this + + // Convert the ranges into comparable dates. + one = calendar.createRange( one.from, one.to ) + two = calendar.createRange( two.from, two.to ) + + return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || + calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) +} + + +/** + * Get the date today. + */ +DatePicker.prototype.now = function( type, value, options ) { + value = new Date() + if ( options && options.rel ) { + value.setDate( value.getDate() + options.rel ) + } + return this.normalize( value, options ) +} + + +/** + * Navigate to next/prev month. + */ +DatePicker.prototype.navigate = function( type, value, options ) { + + var targetDateObject, + targetYear, + targetMonth, + targetDate, + isTargetArray = $.isArray( value ), + isTargetObject = $.isPlainObject( value ), + viewsetObject = this.item.view/*, + safety = 100*/ + + + if ( isTargetArray || isTargetObject ) { + + if ( isTargetObject ) { + targetYear = value.year + targetMonth = value.month + targetDate = value.date + } + else { + targetYear = +value[0] + targetMonth = +value[1] + targetDate = +value[2] + } + + // If we’re navigating months but the view is in a different + // month, navigate to the view’s year and month. + if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { + targetYear = viewsetObject.year + targetMonth = viewsetObject.month + } + + // Figure out the expected target year and month. + targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) + targetYear = targetDateObject.getFullYear() + targetMonth = targetDateObject.getMonth() + + // If the month we’re going to doesn’t have enough days, + // keep decreasing the date until we reach the month’s last date. + while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) { + targetDate -= 1 + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.' + }*/ + } + + value = [ targetYear, targetMonth, targetDate ] + } + + return value +} //DatePicker.prototype.navigate + + +/** + * Normalize a date by setting the hours to midnight. + */ +DatePicker.prototype.normalize = function( value/*, options*/ ) { + value.setHours( 0, 0, 0, 0 ) + return value +} + + +/** + * Measure the range of dates. + */ +DatePicker.prototype.measure = function( type, value/*, options*/ ) { + + var calendar = this + + // If it’s anything false-y, remove the limits. + if ( !value ) { + value = type == 'min' ? -Infinity : Infinity + } + + // If it’s a string, parse it. + else if ( typeof value == 'string' ) { + value = calendar.parse( type, value ) + } + + // If it's an integer, get a date relative to today. + else if ( _.isInteger( value ) ) { + value = calendar.now( type, value, { rel: value } ) + } + + return value +} ///DatePicker.prototype.measure + + +/** + * Create a viewset object based on navigation. + */ +DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { + return this.create([ dateObject.year, dateObject.month, 1 ]) +} + + +/** + * Validate a date as enabled and shift if needed. + */ +DatePicker.prototype.validate = function( type, dateObject, options ) { + + var calendar = this, + + // Keep a reference to the original date. + originalDateObject = dateObject, + + // Make sure we have an interval. + interval = options && options.interval ? options.interval : 1, + + // Check if the calendar enabled dates are inverted. + isFlippedBase = calendar.item.enable === -1, + + // Check if we have any enabled dates after/before now. + hasEnabledBeforeTarget, hasEnabledAfterTarget, + + // The min & max limits. + minLimitObject = calendar.item.min, + maxLimitObject = calendar.item.max, + + // Check if we’ve reached the limit during shifting. + reachedMin, reachedMax, + + // Check if the calendar is inverted and at least one weekday is enabled. + hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) { + + // If there’s a date, check where it is relative to the target. + if ( $.isArray( value ) ) { + var dateTime = calendar.create( value ).pick + if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true + else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true + } + + // Return only integers for enabled weekdays. + return _.isInteger( value ) + }).length/*, + + safety = 100*/ + + + + // Cases to validate for: + // [1] Not inverted and date disabled. + // [2] Inverted and some dates enabled. + // [3] Not inverted and out of range. + // + // Cases to **not** validate for: + // • Navigating months. + // • Not inverted and date enabled. + // • Inverted and all dates disabled. + // • ..and anything else. + if ( !options || !options.nav ) if ( + /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) || + /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) || + /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) ) + ) { + + + // When inverted, flip the direction if there aren’t any enabled weekdays + // and there are no enabled dates in the direction of the interval. + if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) { + interval *= -1 + } + + + // Keep looping until we reach an enabled date. + while ( /*safety &&*/ calendar.disabled( dateObject ) ) { + + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.' + }*/ + + + // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval. + if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { + dateObject = originalDateObject + interval = interval > 0 ? 1 : -1 + } + + + // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. + if ( dateObject.pick <= minLimitObject.pick ) { + reachedMin = true + interval = 1 + dateObject = calendar.create([ + minLimitObject.year, + minLimitObject.month, + minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1) + ]) + } + else if ( dateObject.pick >= maxLimitObject.pick ) { + reachedMax = true + interval = -1 + dateObject = calendar.create([ + maxLimitObject.year, + maxLimitObject.month, + maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1) + ]) + } + + + // If we’ve reached both limits, just break out of the loop. + if ( reachedMin && reachedMax ) { + break + } + + + // Finally, create the shifted date using the interval and keep looping. + dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ]) + } + + } //endif + + + // Return the date object settled on. + return dateObject +} //DatePicker.prototype.validate + + +/** + * Check if a date is disabled. + */ +DatePicker.prototype.disabled = function( dateToVerify ) { + + var + calendar = this, + + // Filter through the disabled dates to check if this is one. + isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) { + + // If the date is a number, match the weekday with 0index and `firstDay` check. + if ( _.isInteger( dateToDisable ) ) { + return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7 + } + + // If it’s an array or a native JS date, create and match the exact date. + if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) { + return dateToVerify.pick === calendar.create( dateToDisable ).pick + } + + // If it’s an object, match a date within the “from” and “to” range. + if ( $.isPlainObject( dateToDisable ) ) { + return calendar.withinRange( dateToDisable, dateToVerify ) + } + }) + + // If this date matches a disabled date, confirm it’s not inverted. + isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { + return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || + $.isPlainObject( dateToDisable ) && dateToDisable.inverted + }).length + + // Check the calendar “enabled” flag and respectively flip the + // disabled state. Then also check if it’s beyond the min/max limits. + return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || + dateToVerify.pick < calendar.item.min.pick || + dateToVerify.pick > calendar.item.max.pick + +} //DatePicker.prototype.disabled + + +/** + * Parse a string into a usable type. + */ +DatePicker.prototype.parse = function( type, value, options ) { + + var calendar = this, + parsingObject = {} + + // If it’s already parsed, we’re good. + if ( !value || typeof value != 'string' ) { + return value + } + + // We need a `.format` to parse the value with. + if ( !( options && options.format ) ) { + options = options || {} + options.format = calendar.settings.format + } + + // Convert the format into an array and then map through it. + calendar.formats.toArray( options.format ).map( function( label ) { + + var + // Grab the formatting label. + formattingLabel = calendar.formats[ label ], + + // The format length is from the formatting label function or the + // label length without the escaping exclamation (!) mark. + formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length + + // If there's a format label, split the value up to the format length. + // Then add it to the parsing object with appropriate label. + if ( formattingLabel ) { + parsingObject[ label ] = value.substr( 0, formatLength ) + } + + // Update the value as the substring from format length to end. + value = value.substr( formatLength ) + }) + + // Compensate for month 0index. + return [ + parsingObject.yyyy || parsingObject.yy, + +( parsingObject.mm || parsingObject.m ) - 1, + parsingObject.dd || parsingObject.d + ] +} //DatePicker.prototype.parse + + +/** + * Various formats to display the object in. + */ +DatePicker.prototype.formats = (function() { + + // Return the length of the first word in a collection. + function getWordLengthFromCollection( string, collection, dateObject ) { + + // Grab the first word from the string. + var word = string.match( /\w+/ )[ 0 ] + + // If there's no month index, add it to the date object + if ( !dateObject.mm && !dateObject.m ) { + dateObject.m = collection.indexOf( word ) + 1 + } + + // Return the length of the word. + return word.length + } + + // Get the length of the first word in a string. + function getFirstWordLength( string ) { + return string.match( /\w+/ )[ 0 ].length + } + + return { + + d: function( string, dateObject ) { + + // If there's string, then get the digits length. + // Otherwise return the selected date. + return string ? _.digits( string ) : dateObject.date + }, + dd: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected date with a leading zero. + return string ? 2 : _.lead( dateObject.date ) + }, + ddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the short selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ] + }, + dddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the full selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ] + }, + m: function( string, dateObject ) { + + // If there's a string, then get the length of the digits + // Otherwise return the selected month with 0index compensation. + return string ? _.digits( string ) : dateObject.month + 1 + }, + mm: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected month with 0index and leading zero. + return string ? 2 : _.lead( dateObject.month + 1 ) + }, + mmm: function( string, dateObject ) { + + var collection = this.settings.monthsShort + + // If there's a string, get length of the relevant month from the short + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + mmmm: function( string, dateObject ) { + + var collection = this.settings.monthsFull + + // If there's a string, get length of the relevant month from the full + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + yy: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected year by slicing out the first 2 digits. + return string ? 2 : ( '' + dateObject.year ).slice( 2 ) + }, + yyyy: function( string, dateObject ) { + + // If there's a string, then the length is always 4. + // Otherwise return the selected year. + return string ? 4 : dateObject.year + }, + + // Create an array by splitting the formatting string passed. + toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) }, + + // Format an object into a string using the formatting options. + toString: function ( formatString, itemObject ) { + var calendar = this + return calendar.formats.toArray( formatString ).map( function( label ) { + return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) + }).join( '' ) + } + } +})() //DatePicker.prototype.formats + + + + +/** + * Check if two date units are the exact. + */ +DatePicker.prototype.isDateExact = function( one, two ) { + + var calendar = this + + // When we’re working with weekdays, do a direct comparison. + if ( + ( _.isInteger( one ) && _.isInteger( two ) ) || + ( typeof one == 'boolean' && typeof two == 'boolean' ) + ) { + return one === two + } + + // When we’re working with date representations, compare the “pick” value. + if ( + ( _.isDate( one ) || $.isArray( one ) ) && + ( _.isDate( two ) || $.isArray( two ) ) + ) { + return calendar.create( one ).pick === calendar.create( two ).pick + } + + // When we’re working with range objects, compare the “from” and “to”. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to ) + } + + return false +} + + +/** + * Check if two date units overlap. + */ +DatePicker.prototype.isDateOverlap = function( one, two ) { + + var calendar = this, + firstDay = calendar.settings.firstDay ? 1 : 0 + + // When we’re working with a weekday index, compare the days. + if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { + one = one % 7 + firstDay + return one === calendar.create( two ).day + 1 + } + if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { + two = two % 7 + firstDay + return two === calendar.create( one ).day + 1 + } + + // When we’re working with range objects, check if the ranges overlap. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.overlapRanges( one, two ) + } + + return false +} + + +/** + * Flip the “enabled” state. + */ +DatePicker.prototype.flipEnable = function(val) { + var itemObject = this.item + itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) +} + + +/** + * Mark a collection of dates as “disabled”. + */ +DatePicker.prototype.deactivate = function( type, datesToDisable ) { + + var calendar = this, + disabledItems = calendar.item.disable.slice(0) + + + // If we’re flipping, that’s all we need to do. + if ( datesToDisable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToDisable === false ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToDisable === true ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the dates to disable. + else { + + datesToDisable.map(function( unitToDisable ) { + + var matchFound + + // When we have disabled items, check for matches. + // If something is matched, immediately break out. + for ( var index = 0; index < disabledItems.length; index += 1 ) { + if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { + matchFound = true + break + } + } + + // If nothing was found, add the validated unit to the collection. + if ( !matchFound ) { + if ( + _.isInteger( unitToDisable ) || + _.isDate( unitToDisable ) || + $.isArray( unitToDisable ) || + ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) + ) { + disabledItems.push( unitToDisable ) + } + } + }) + } + + // Return the updated collection. + return disabledItems +} //DatePicker.prototype.deactivate + + +/** + * Mark a collection of dates as “enabled”. + */ +DatePicker.prototype.activate = function( type, datesToEnable ) { + + var calendar = this, + disabledItems = calendar.item.disable, + disabledItemsCount = disabledItems.length + + // If we’re flipping, that’s all we need to do. + if ( datesToEnable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToEnable === true ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToEnable === false ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the disabled dates. + else { + + datesToEnable.map(function( unitToEnable ) { + + var matchFound, + disabledUnit, + index, + isExactRange + + // Go through the disabled items and try to find a match. + for ( index = 0; index < disabledItemsCount; index += 1 ) { + + disabledUnit = disabledItems[index] + + // When an exact match is found, remove it from the collection. + if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { + matchFound = disabledItems[index] = null + isExactRange = true + break + } + + // When an overlapped match is found, add the “inverted” state to it. + else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { + if ( $.isPlainObject( unitToEnable ) ) { + unitToEnable.inverted = true + matchFound = unitToEnable + } + else if ( $.isArray( unitToEnable ) ) { + matchFound = unitToEnable + if ( !matchFound[3] ) matchFound.push( 'inverted' ) + } + else if ( _.isDate( unitToEnable ) ) { + matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] + } + break + } + } + + // If a match was found, remove a previous duplicate entry. + if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // In the event that we’re dealing with an exact range of dates, + // make sure there are no “inverted” dates because of it. + if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // If something is still matched, add it into the collection. + if ( matchFound ) { + disabledItems.push( matchFound ) + } + }) + } + + // Return the updated collection. + return disabledItems.filter(function( val ) { return val != null }) +} //DatePicker.prototype.activate + + +/** + * Create a string for the nodes in the picker. + */ +DatePicker.prototype.nodes = function( isOpen ) { + + var + calendar = this, + settings = calendar.settings, + calendarItem = calendar.item, + nowObject = calendarItem.now, + selectedObject = calendarItem.select, + highlightedObject = calendarItem.highlight, + viewsetObject = calendarItem.view, + disabledCollection = calendarItem.disable, + minLimitObject = calendarItem.min, + maxLimitObject = calendarItem.max, + + + // Create the calendar table head using a copy of weekday labels collection. + // * We do a copy so we don't mutate the original array. + tableHead = (function( collection, fullCollection ) { + + // If the first day should be Monday, move Sunday to the end. + if ( settings.firstDay ) { + collection.push( collection.shift() ) + fullCollection.push( fullCollection.shift() ) + } + + // Create and return the table head group. + return _.node( + 'thead', + _.node( + 'tr', + _.group({ + min: 0, + max: DAYS_IN_WEEK - 1, + i: 1, + node: 'th', + item: function( counter ) { + return [ + collection[ counter ], + settings.klass.weekdays, + 'scope=col title="' + fullCollection[ counter ] + '"' + ] + } + }) + ) + ) //endreturn + + // Materialize modified + })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysLetter ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead + + + // Create the nav for next/prev month. + createMonthNav = function( next ) { + + // Otherwise, return the created month tag. + return _.node( + 'div', + ' ', + settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + ( + + // If the focused month is outside the range, disabled the button. + ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) || + ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ? + ' ' + settings.klass.navDisabled : '' + ), + 'data-nav=' + ( next || -1 ) + ' ' + + _.ariaAttr({ + role: 'button', + controls: calendar.$node[0].id + '_table' + }) + ' ' + + 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"' + ) //endreturn + }, //createMonthNav + + + // Create the month label. + //Materialize modified + createMonthLabel = function(override) { + + var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull + + // Materialize modified + if (override == "short_months") { + monthsCollection = settings.monthsShort; + } + + // If there are months to select, add a dropdown menu. + if ( settings.selectMonths && override == undefined) { + + return _.node( 'select', + _.group({ + min: 0, + max: 11, + i: 1, + node: 'option', + item: function( loopedMonth ) { + + return [ + + // The looped month and no classes. + monthsCollection[ loopedMonth ], 0, + + // Set the value and selected index. + 'value=' + loopedMonth + + ( viewsetObject.month == loopedMonth ? ' selected' : '' ) + + ( + ( + ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) || + ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month ) + ) ? + ' disabled' : '' + ) + ] + } + }), + settings.klass.selectMonth + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelMonthSelect + '"' + ) + } + + // Materialize modified + if (override == "short_months") + if (selectedObject != null) + return _.node( 'div', monthsCollection[ selectedObject.month ] ); + else return _.node( 'div', monthsCollection[ viewsetObject.month ] ); + + // If there's a need for a month selector + return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month ) + }, //createMonthLabel + + + // Create the year label. + // Materialize modified + createYearLabel = function(override) { + + var focusedYear = viewsetObject.year, + + // If years selector is set to a literal "true", set it to 5. Otherwise + // divide in half to get half before and half after focused year. + numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) + + // If there are years to select, add a dropdown menu. + if ( numberYears ) { + + var + minYear = minLimitObject.year, + maxYear = maxLimitObject.year, + lowestYear = focusedYear - numberYears, + highestYear = focusedYear + numberYears + + // If the min year is greater than the lowest year, increase the highest year + // by the difference and set the lowest year to the min year. + if ( minYear > lowestYear ) { + highestYear += minYear - lowestYear + lowestYear = minYear + } + + // If the max year is less than the highest year, decrease the lowest year + // by the lower of the two: available and needed years. Then set the + // highest year to the max year. + if ( maxYear < highestYear ) { + + var availableYears = lowestYear - minYear, + neededYears = highestYear - maxYear + + lowestYear -= availableYears > neededYears ? neededYears : availableYears + highestYear = maxYear + } + + if ( settings.selectYears && override == undefined ) { + return _.node( 'select', + _.group({ + min: lowestYear, + max: highestYear, + i: 1, + node: 'option', + item: function( loopedYear ) { + return [ + + // The looped year and no classes. + loopedYear, 0, + + // Set the value and selected index. + 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' ) + ] + } + }), + settings.klass.selectYear + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelYearSelect + '"' + ) + } + } + + // Materialize modified + if (override == "raw") + return _.node( 'div', focusedYear ) + + // Otherwise just return the year focused + return _.node( 'div', focusedYear, settings.klass.year ) + } //createYearLabel + + + // Materialize modified + createDayLabel = function() { + if (selectedObject != null) + return _.node( 'div', selectedObject.date) + else return _.node( 'div', nowObject.date) + } + createWeekdayLabel = function() { + var display_day; + + if (selectedObject != null) + display_day = selectedObject.day; + else + display_day = nowObject.day; + var weekday = settings.weekdaysFull[ display_day ] + return weekday + } + + + // Create and return the entire calendar. +return _.node( + // Date presentation View + 'div', + _.node( + 'div', + createWeekdayLabel(), + "picker__weekday-display" + )+ + _.node( + // Div for short Month + 'div', + createMonthLabel("short_months"), + settings.klass.month_display + )+ + _.node( + // Div for Day + 'div', + createDayLabel() , + settings.klass.day_display + )+ + _.node( + // Div for Year + 'div', + createYearLabel("raw") , + settings.klass.year_display + ), + settings.klass.date_display + )+ + // Calendar container + _.node('div', + _.node('div', + ( settings.selectYears ? createMonthLabel() + createYearLabel() : createMonthLabel() + createYearLabel() ) + + createMonthNav() + createMonthNav( 1 ), + settings.klass.header + ) + _.node( + 'table', + tableHead + + _.node( + 'tbody', + _.group({ + min: 0, + max: WEEKS_IN_CALENDAR - 1, + i: 1, + node: 'tr', + item: function( rowCounter ) { + + // If Monday is the first day and the month starts on Sunday, shift the date back a week. + var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 + + return [ + _.group({ + min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index + max: function() { + return this.min + DAYS_IN_WEEK - 1 + }, + i: 1, + node: 'td', + item: function( targetDate ) { + + // Convert the time date from a relative date to a target date. + targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) + + var isSelected = selectedObject && selectedObject.pick == targetDate.pick, + isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, + isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick, + formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] ) + + return [ + _.node( + 'div', + targetDate.date, + (function( klasses ) { + + // Add the `infocus` or `outfocus` classes based on month in view. + klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) + + // Add the `today` class if needed. + if ( nowObject.pick == targetDate.pick ) { + klasses.push( settings.klass.now ) + } + + // Add the `selected` class if something's selected and the time matches. + if ( isSelected ) { + klasses.push( settings.klass.selected ) + } + + // Add the `highlighted` class if something's highlighted and the time matches. + if ( isHighlighted ) { + klasses.push( settings.klass.highlighted ) + } + + // Add the `disabled` class if something's disabled and the object matches. + if ( isDisabled ) { + klasses.push( settings.klass.disabled ) + } + + return klasses.join( ' ' ) + })([ settings.klass.day ]), + 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({ + role: 'gridcell', + label: formattedDate, + selected: isSelected && calendar.$node.val() === formattedDate ? true : null, + activedescendant: isHighlighted ? true : null, + disabled: isDisabled ? true : null + }) + ), + '', + _.ariaAttr({ role: 'presentation' }) + ] //endreturn + } + }) + ] //endreturn + } + }) + ), + settings.klass.table, + 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({ + role: 'grid', + controls: calendar.$node[0].id, + readonly: true + }) + ) + , settings.klass.calendar_container) // end calendar + + + + + // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”. + _.node( + 'div', + _.node( 'button', settings.today, "btn-flat picker__today", + 'type=button data-pick=' + nowObject.pick + + ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node( 'button', settings.clear, "btn-flat picker__clear", + 'type=button data-clear=1' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node('button', settings.close, "btn-flat picker__close", + 'type=button data-close=true ' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ), + settings.klass.footer + ) //endreturn +} //DatePicker.prototype.nodes + + + + +/** + * The date picker defaults. + */ +DatePicker.defaults = (function( prefix ) { + + return { + + // The title label to use for the month nav buttons + labelMonthNext: 'Next month', + labelMonthPrev: 'Previous month', + + // The title label to use for the dropdown selectors + labelMonthSelect: 'Select a month', + labelYearSelect: 'Select a year', + + // Months and weekdays + monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], + monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], + weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], + weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], + + // Materialize modified + weekdaysLetter: [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ], + + // Today and clear + today: 'Today', + clear: 'Clear', + close: 'Close', + + // The format to show on the `input` element + format: 'd mmmm, yyyy', + + // Classes + klass: { + + table: prefix + 'table', + + header: prefix + 'header', + + + // Materialize Added klasses + date_display: prefix + 'date-display', + day_display: prefix + 'day-display', + month_display: prefix + 'month-display', + year_display: prefix + 'year-display', + calendar_container: prefix + 'calendar-container', + // end + + + + navPrev: prefix + 'nav--prev', + navNext: prefix + 'nav--next', + navDisabled: prefix + 'nav--disabled', + + month: prefix + 'month', + year: prefix + 'year', + + selectMonth: prefix + 'select--month', + selectYear: prefix + 'select--year', + + weekdays: prefix + 'weekday', + + day: prefix + 'day', + disabled: prefix + 'day--disabled', + selected: prefix + 'day--selected', + highlighted: prefix + 'day--highlighted', + now: prefix + 'day--today', + infocus: prefix + 'day--infocus', + outfocus: prefix + 'day--outfocus', + + footer: prefix + 'footer', + + buttonClear: prefix + 'button--clear', + buttonToday: prefix + 'button--today', + buttonClose: prefix + 'button--close' + } + } +})( Picker.klasses().picker + '__' ) + + + + + +/** + * Extend the picker to add the date picker. + */ +Picker.extend( 'pickadate', DatePicker ) + + +})); + + +;(function ($) { + + $.fn.characterCounter = function(){ + return this.each(function(){ + var $input = $(this); + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + // character counter has already been added appended to the parent container + if ($counterElement.length) { + return; + } + + var itHasLengthAttribute = $input.attr('length') !== undefined; + + if(itHasLengthAttribute){ + $input.on('input', updateCounter); + $input.on('focus', updateCounter); + $input.on('blur', removeCounterElement); + + addCounterElement($input); + } + + }); + }; + + function updateCounter(){ + var maxLength = +$(this).attr('length'), + actualLength = +$(this).val().length, + isValidLength = actualLength <= maxLength; + + $(this).parent().find('span[class="character-counter"]') + .html( actualLength + '/' + maxLength); + + addInputStyle(isValidLength, $(this)); + } + + function addCounterElement($input) { + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + if ($counterElement.length) { + return; + } + + $counterElement = $('') + .addClass('character-counter') + .css('float','right') + .css('font-size','12px') + .css('height', 1); + + $input.parent().append($counterElement); + } + + function removeCounterElement(){ + $(this).parent().find('span[class="character-counter"]').html(''); + } + + function addInputStyle(isValidLength, $input){ + var inputHasInvalidClass = $input.hasClass('invalid'); + if (isValidLength && inputHasInvalidClass) { + $input.removeClass('invalid'); + } + else if(!isValidLength && !inputHasInvalidClass){ + $input.removeClass('valid'); + $input.addClass('invalid'); + } + } + + $(document).ready(function(){ + $('input, textarea').characterCounter(); + }); + +}( jQuery )); +;(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + time_constant: 200, // ms + dist: -100, // zoom scale TODO: make this more intuitive as an option + shift: 0, // spacing for center image + padding: 0, // Padding between non center items + full_width: false, // Change to full width styles + indicators: false, // Toggle indicators + no_wrap: false // Don't wrap around and cycle through items. + }; + options = $.extend(defaults, options); + + return this.each(function() { + + var images, offset, center, pressed, dim, count, + reference, referenceY, amplitude, target, velocity, + xform, frame, timestamp, ticker, dragged, vertical_dragged; + var $indicators = $('
        '); + + + // Initialize + var view = $(this); + var showIndicators = view.attr('data-indicators') || options.indicators; + + // Don't double initialize. + if (view.hasClass('initialized')) { + // Redraw carousel. + $(this).trigger('carouselNext', [0.000001]); + return true; + } + + + // Options + if (options.full_width) { + options.dist = 0; + var firstImage = view.find('.carousel-item img').first(); + if (firstImage.length) { + imageHeight = firstImage.on('load', function(){ + view.css('height', $(this).height()); + }); + } else { + imageHeight = view.find('.carousel-item').first().height(); + view.css('height', imageHeight); + } + + // Offset fixed items when indicators. + if (showIndicators) { + view.find('.carousel-fixed-item').addClass('with-indicators'); + } + } + + + view.addClass('initialized'); + pressed = false; + offset = target = 0; + images = []; + item_width = view.find('.carousel-item').first().innerWidth(); + dim = item_width * 2 + options.padding; + + view.find('.carousel-item').each(function (i) { + images.push($(this)[0]); + if (showIndicators) { + var $indicator = $('
      • '); + + // Add active to first by default. + if (i === 0) { + $indicator.addClass('active'); + } + + // Handle clicks on indicators. + $indicator.click(function () { + var index = $(this).index(); + cycleTo(index); + }); + $indicators.append($indicator); + } + }); + + if (showIndicators) { + view.append($indicators); + } + count = images.length; + + + function setupEvents() { + if (typeof window.ontouchstart !== 'undefined') { + view[0].addEventListener('touchstart', tap); + view[0].addEventListener('touchmove', drag); + view[0].addEventListener('touchend', release); + } + view[0].addEventListener('mousedown', tap); + view[0].addEventListener('mousemove', drag); + view[0].addEventListener('mouseup', release); + view[0].addEventListener('mouseleave', release); + view[0].addEventListener('click', click); + } + + function xpos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientX; + } + + // mouse event + return e.clientX; + } + + function ypos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientY; + } + + // mouse event + return e.clientY; + } + + function wrap(x) { + return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x; + } + + function scroll(x) { + var i, half, delta, dir, tween, el, alignment, xTranslation; + + offset = (typeof x === 'number') ? x : offset; + center = Math.floor((offset + dim / 2) / dim); + delta = offset - center * dim; + dir = (delta < 0) ? 1 : -1; + tween = -dir * delta * 2 / dim; + half = count >> 1; + + if (!options.full_width) { + alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) '; + alignment += 'translateY(' + (view[0].clientHeight - item_width) / 2 + 'px)'; + } else { + alignment = 'translateX(0)'; + } + + // Set indicator active + if (showIndicators) { + var diff = (center % count); + var activeIndicator = $indicators.find('.indicator-item.active'); + if (activeIndicator.index() !== diff) { + activeIndicator.removeClass('active'); + $indicators.find('.indicator-item').eq(diff).addClass('active'); + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween * i) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + for (i = 1; i <= half; ++i) { + // right side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 + tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center + i < count) { + el = images[wrap(center + i)]; + el.style[xform] = alignment + + ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + + // left side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 - tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center - i >= 0) { + el = images[wrap(center - i)]; + el.style[xform] = alignment + + ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + function track() { + var now, elapsed, delta, v; + + now = Date.now(); + elapsed = now - timestamp; + timestamp = now; + delta = offset - frame; + frame = offset; + + v = 1000 * delta / (1 + elapsed); + velocity = 0.8 * v + 0.2 * velocity; + } + + function autoScroll() { + var elapsed, delta; + + if (amplitude) { + elapsed = Date.now() - timestamp; + delta = amplitude * Math.exp(-elapsed / options.time_constant); + if (delta > 2 || delta < -2) { + scroll(target - delta); + requestAnimationFrame(autoScroll); + } else { + scroll(target); + } + } + } + + function click(e) { + // Disable clicks if carousel was dragged. + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + return false; + + } else if (!options.full_width) { + var clickedIndex = $(e.target).closest('.carousel-item').index(); + var diff = (center % count) - clickedIndex; + + // Disable clicks if carousel was shifted by click + if (diff !== 0) { + e.preventDefault(); + e.stopPropagation(); + } + cycleTo(clickedIndex); + } + } + + function cycleTo(n) { + var diff = (center % count) - n; + + // Account for wraparound. + if (!options.no_wrap) { + if (diff < 0) { + if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; } + + } else if (diff > 0) { + if (Math.abs(diff - count) < diff) { diff -= count; } + } + } + + // Call prev or next accordingly. + if (diff < 0) { + view.trigger('carouselNext', [Math.abs(diff)]); + + } else if (diff > 0) { + view.trigger('carouselPrev', [diff]); + } + } + + function tap(e) { + pressed = true; + dragged = false; + vertical_dragged = false; + reference = xpos(e); + referenceY = ypos(e); + + velocity = amplitude = 0; + frame = offset; + timestamp = Date.now(); + clearInterval(ticker); + ticker = setInterval(track, 100); + + } + + function drag(e) { + var x, delta, deltaY; + if (pressed) { + x = xpos(e); + y = ypos(e); + delta = reference - x; + deltaY = Math.abs(referenceY - y); + if (deltaY < 30 && !vertical_dragged) { + // If vertical scrolling don't allow dragging. + if (delta > 2 || delta < -2) { + dragged = true; + reference = x; + scroll(offset + delta); + } + + } else if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + + } else { + // Vertical scrolling. + vertical_dragged = true; + } + } + + if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + + function release(e) { + if (pressed) { + pressed = false; + } else { + return; + } + + clearInterval(ticker); + target = offset; + if (velocity > 10 || velocity < -10) { + amplitude = 0.9 * velocity; + target = offset + amplitude; + } + target = Math.round(target / dim) * dim; + + // No wrap of items. + if (options.no_wrap) { + if (target >= dim * (count - 1)) { + target = dim * (count - 1); + } else if (target < 0) { + target = 0; + } + } + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } + + xform = 'transform'; + ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { + var e = prefix + 'Transform'; + if (typeof document.body.style[e] !== 'undefined') { + xform = e; + return false; + } + return true; + }); + + + + window.onresize = scroll; + + setupEvents(); + scroll(offset); + + $(this).on('carouselNext', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset + dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselPrev', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset - dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselSet', function(e, n) { + if (n === undefined) { + n = 0; + } + cycleTo(n); + }); + + }); + + + + }, + next : function(n) { + $(this).trigger('carouselNext', [n]); + }, + prev : function(n) { + $(this).trigger('carouselPrev', [n]); + }, + set : function(n) { + $(this).trigger('carouselSet', [n]); + } + }; + + + $.fn.carousel = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' ); + } + }; // Plugin end +}( jQuery )); diff --git a/assets/js/tabs.js b/assets/js/tabs.js new file mode 100644 index 0000000..23e17ad --- /dev/null +++ b/assets/js/tabs.js @@ -0,0 +1,138 @@ +(function ($) { + + var methods = { + init : function(options) { + var defaults = { + onShow: null + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each set of tabs, we want to keep track of + // which tab is active and its associated content + var $this = $(this), + window_width = $(window).width(); + + var $active, $content, $links = $this.find('li.tab a'), + $tabs_width = $this.width(), + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length, + $index = 0; // TODO: maybe index = $('.active');? + + // Finds right attribute for indicator based on active tab. + // el: jQuery Object + var calcRightPos = function(el) { + return $tabs_width - el.position().left - el.outerWidth() - $this.scrollLeft(); + }; + + // Finds left attribute for indicator based on active tab. + // el: jQuery Object + var calcLeftPos = function(el) { + return el.position().left + $this.scrollLeft(); + }; + + // NOTE: Changed. If the location.hash matches one of the links, use that as the active tab. + setTimeout(function() { + $active = $('li.tab a.active'); + $active.addClass('active'); + }, 0); + + // append indicator then set indicator width to tab width + $this.append('
        '); + var $indicator = $this.find('.indicator'); + + setTimeout(function() { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + }, 0); + + $(window).resize(function () { + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + if ($tab_width !== 0 && $tabs_width !== 0) { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + } + }); + + // Bind the click event handler + $this.on('click', 'a', function(e) { + if ($(this).parent().hasClass('disabled')) { + e.preventDefault(); + return; + } + + // Act as regular link if target attribute is specified. + if (!!$(this).attr("target")) { + return; + } + + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + + // Make the old tab inactive. + $active.removeClass('active'); + if ($content !== undefined) { + $content.hide(); + } + + // Update the variables with the new link and content + $active = $(this); + // $content = $(Materialize.escapeHash(this.hash)); + $links = $this.find('li.tab a'); + var activeRect = $active.position(); + + // Make the tab active. + $active.addClass('active'); + var $prev_index = $index; + $index = $links.index($(this)); + if ($index < 0) { + $index = 0; + } + // Change url to current tab + // window.location.hash = $active.attr('href'); + + if ($content !== undefined) { + $content.show(); + if (typeof(options.onShow) === "function") { + options.onShow.call(this, $content); + } + } + + // Update indicator + + if (($index - $prev_index) >= 0) { + $indicator.velocity({"right": calcRightPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"left": calcLeftPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + + } else { + $indicator.velocity({"left": calcLeftPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"right": calcRightPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + } + + // Prevent the anchor's default click action + e.preventDefault(); + }); + }); + + }, + select_tab : function( id ) { + this.find('a[href="#' + id + '"]').trigger('click'); + } + }; + + $.fn.tabs = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tabs' ); + } + }; + + $(document).ready(function(){ + $('ul.tabs').tabs(); + }); +}( jQuery )); diff --git a/assets/libs/materialize/LICENSE b/assets/libs/materialize/LICENSE new file mode 100644 index 0000000..5038d18 --- /dev/null +++ b/assets/libs/materialize/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Materialize + +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/assets/libs/materialize/README.md b/assets/libs/materialize/README.md new file mode 100755 index 0000000..32791ed --- /dev/null +++ b/assets/libs/materialize/README.md @@ -0,0 +1,48 @@ +![alt tag](https://raw.github.com/dogfalo/materialize/master/images/materialize.gif) +=========== + +[![Travis CI](https://travis-ci.org/Dogfalo/materialize.svg?branch=master)](https://travis-ci.org/Dogfalo/materialize)[![devDependency Status](https://david-dm.org/Dogfalo/materialize/dev-status.svg)](https://david-dm.org/Dogfalo/materialize#info=devDependencies)[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Dogfalo/materialize?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[Materialize](http://materializecss.com/), a CSS Framework based on material design + +### Current Version : v0.97.7 + +## Sass Requirements: +- Ruby Sass 3.3+, LibSass 0.6+ + +## Supported Browsers: +Chrome 35+, Firefox 31+, Safari 7+, IE 10+ + +## Changelog +- v0.97.7 (July 23rd) + - Basic horizontal cards + - Carousel bug fixes and new features + - Updated sidenav styles and new component + - Meteor package now supports Sass + - Autocomplete form component + - Chips jQuery plugin +- v0.97.6 (April 1st) + - **Removed deprecated material icons from project** + - **Changed /font directory to /fonts** + - Datepicker and ScrollSpy now compatible with jQuery 2.2.x + - Responsive tables now work with empty cells + - Added focus states to checkboxes, switches, and radio buttons + - Sidenav and Modals no longer cause flicker with scrollbar + - Materialbox overflow and z-index issues fixed + - Added new option for Card actions within a Card reveal +- v0.97.5 (Dec 21, 2015) + - Fixed Meteor package crash +- v0.97.4 (Dec 20, 2015) + - Added Jasmine testing with Travis CI + - Select bugfixes + - Grid Offset bugfix + - Dropdown overflow bugfix + - Range slider error bugfix + + + +## Contributing +[Please read CONTRIBUTING.md for more information](CONTRIBUTING.md) + +## Testing +We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](https://docs.google.com/document/d/1dVM6qGt_b_y9RRhr9X7oZfFydaJIEqB9CT7yekv-4XE/edit?usp=sharing) diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Bold.eot b/assets/libs/materialize/fonts/roboto/Roboto-Bold.eot new file mode 100644 index 0000000..b73776e Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Bold.eot differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Bold.ttf b/assets/libs/materialize/fonts/roboto/Roboto-Bold.ttf new file mode 100644 index 0000000..68822ca Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Bold.ttf differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff b/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff new file mode 100644 index 0000000..1f75afd Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff2 b/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff2 new file mode 100644 index 0000000..350d1c3 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Bold.woff2 differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Light.eot b/assets/libs/materialize/fonts/roboto/Roboto-Light.eot new file mode 100644 index 0000000..072cdc4 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Light.eot differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Light.ttf b/assets/libs/materialize/fonts/roboto/Roboto-Light.ttf new file mode 100644 index 0000000..aa45340 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Light.ttf differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Light.woff b/assets/libs/materialize/fonts/roboto/Roboto-Light.woff new file mode 100644 index 0000000..3480c6c Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Light.woff differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Light.woff2 b/assets/libs/materialize/fonts/roboto/Roboto-Light.woff2 new file mode 100644 index 0000000..9a4d98c Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Light.woff2 differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Medium.eot b/assets/libs/materialize/fonts/roboto/Roboto-Medium.eot new file mode 100644 index 0000000..f9ad995 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Medium.eot differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Medium.ttf b/assets/libs/materialize/fonts/roboto/Roboto-Medium.ttf new file mode 100644 index 0000000..a3c1a1f Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Medium.ttf differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff b/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff new file mode 100644 index 0000000..1186773 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff2 b/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff2 new file mode 100644 index 0000000..d10a592 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Medium.woff2 differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Regular.eot b/assets/libs/materialize/fonts/roboto/Roboto-Regular.eot new file mode 100644 index 0000000..9b5e8e4 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Regular.eot differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Regular.ttf b/assets/libs/materialize/fonts/roboto/Roboto-Regular.ttf new file mode 100644 index 0000000..0e58508 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Regular.ttf differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff b/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff new file mode 100644 index 0000000..f823258 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff2 b/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff2 new file mode 100644 index 0000000..b7082ef Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Regular.woff2 differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Thin.eot b/assets/libs/materialize/fonts/roboto/Roboto-Thin.eot new file mode 100644 index 0000000..2284a3b Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Thin.eot differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Thin.ttf b/assets/libs/materialize/fonts/roboto/Roboto-Thin.ttf new file mode 100644 index 0000000..8779333 Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Thin.ttf differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff b/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff new file mode 100644 index 0000000..2a98c1e Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff differ diff --git a/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff2 b/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff2 new file mode 100644 index 0000000..a38025a Binary files /dev/null and b/assets/libs/materialize/fonts/roboto/Roboto-Thin.woff2 differ diff --git a/assets/libs/materialize/js/animation.js b/assets/libs/materialize/js/animation.js new file mode 100644 index 0000000..d194de7 --- /dev/null +++ b/assets/libs/materialize/js/animation.js @@ -0,0 +1,9 @@ + // Custom Easing + jQuery.extend( jQuery.easing, + { + easeInOutMaterial: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return c/4*((t-=2)*t*t + 2) + b; + } + }); + diff --git a/assets/libs/materialize/js/bin/materialize.js b/assets/libs/materialize/js/bin/materialize.js new file mode 100644 index 0000000..82b1af6 --- /dev/null +++ b/assets/libs/materialize/js/bin/materialize.js @@ -0,0 +1,7778 @@ +/*! + * Materialize v0.97.8 (http://materializecss.com) + * Copyright 2014-2015 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +// Check for jQuery. +if (typeof(jQuery) === 'undefined') { + var jQuery; + // Check if require is a defined function. + if (typeof(require) === 'function') { + jQuery = $ = require('jquery'); + // Else use the dollar sign alias. + } else { + jQuery = $; + } +} +;/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright © 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +jQuery.easing['jswing'] = jQuery.easing['swing']; + +jQuery.extend( jQuery.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert(jQuery.easing.default); + return jQuery.easing[jQuery.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright © 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */; // Custom Easing + jQuery.extend( jQuery.easing, + { + easeInOutMaterial: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return c/4*((t-=2)*t*t + 2) + b; + } + }); + +;/*! VelocityJS.org (1.2.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ +/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ +/*! Note that this has been modified by Materialize to confirm that Velocity is not already being imported. */ +jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(e){function t(e){var t=e.length,a=r.type(e);return"function"===a||r.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===a||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;ln;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;cO;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)})); +;!function(a,b,c,d){"use strict";function k(a,b,c){return setTimeout(q(a,c),b)}function l(a,b,c){return Array.isArray(a)?(m(a,c[b],c),!0):!1}function m(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e-1}function x(a){return a.trim().split(/\s+/g)}function y(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function B(a,b){for(var c,f,g=b[0].toUpperCase()+b.slice(1),h=0;h1&&!c.firstMultiple?c.firstMultiple=gb(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=hb(d);b.timeStamp=j(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=lb(h,i),b.distance=kb(h,i),eb(c,b),b.offsetDirection=jb(b.deltaX,b.deltaY),b.scale=g?nb(g.pointers,d):1,b.rotation=g?mb(g.pointers,d):0,fb(c,b);var k=a.element;v(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function eb(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===O||f.eventType===Q)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function fb(a,b){var f,g,h,j,c=a.lastInterval||b,e=b.timeStamp-c.timeStamp;if(b.eventType!=R&&(e>N||c.velocity===d)){var k=c.deltaX-b.deltaX,l=c.deltaY-b.deltaY,m=ib(e,k,l);g=m.x,h=m.y,f=i(m.x)>i(m.y)?m.x:m.y,j=jb(k,l),a.lastInterval=b}else f=c.velocity,g=c.velocityX,h=c.velocityY,j=c.direction;b.velocity=f,b.velocityX=g,b.velocityY=h,b.direction=j}function gb(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:h(c/b),y:h(d/b)}}function ib(a,b,c){return{x:b/a||0,y:c/a||0}}function jb(a,b){return a===b?S:i(a)>=i(b)?a>0?T:U:b>0?V:W}function kb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function lb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function mb(a,b){return lb(b[1],b[0],_)-lb(a[1],a[0],_)}function nb(a,b){return kb(b[0],b[1],_)/kb(a[0],a[1],_)}function rb(){this.evEl=pb,this.evWin=qb,this.allow=!0,this.pressed=!1,ab.apply(this,arguments)}function wb(){this.evEl=ub,this.evWin=vb,ab.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function Ab(){this.evTarget=yb,this.evWin=zb,this.started=!1,ab.apply(this,arguments)}function Bb(a,b){var c=z(a.touches),d=z(a.changedTouches);return b&(Q|R)&&(c=A(c.concat(d),"identifier",!0)),[c,d]}function Eb(){this.evTarget=Db,this.targetIds={},ab.apply(this,arguments)}function Fb(a,b){var c=z(a.touches),d=this.targetIds;if(b&(O|P)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=z(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return v(a.target,i)}),b===O)for(e=0;eh&&(b.push(a),h=b.length-1):e&(Q|R)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var xb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},yb="touchstart",zb="touchstart touchmove touchend touchcancel";p(Ab,ab,{handler:function(a){var b=xb[a.type];if(b===O&&(this.started=!0),this.started){var c=Bb.call(this,a,b);b&(Q|R)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}});var Cb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},Db="touchstart touchmove touchend touchcancel";p(Eb,ab,{handler:function(a){var b=Cb[a.type],c=Fb.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}),p(Gb,ab,{handler:function(a,b,c){var d=c.pointerType==J,e=c.pointerType==L;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Q|R)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Hb=B(f.style,"touchAction"),Ib=Hb!==d,Jb="compute",Kb="auto",Lb="manipulation",Mb="none",Nb="pan-x",Ob="pan-y";Pb.prototype={set:function(a){a==Jb&&(a=this.compute()),Ib&&(this.manager.element.style[Hb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return m(this.manager.recognizers,function(b){r(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),Qb(a.join(" "))},preventDefaults:function(a){if(!Ib){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return b.preventDefault(),void 0;var d=this.actions,e=w(d,Mb),f=w(d,Ob),g=w(d,Nb);return e||f&&c&X||g&&c&Y?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var Rb=1,Sb=2,Tb=4,Ub=8,Vb=Ub,Wb=16,Xb=32;Yb.prototype={defaults:{},set:function(a){return n(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(l(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_b(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return l(a,"dropRecognizeWith",this)?this:(a=_b(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(l(a,"requireFailure",this))return this;var b=this.requireFail;return a=_b(a,this),-1===y(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(l(a,"dropRequireFailure",this))return this;a=_b(a,this);var b=y(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function d(d){b.manager.emit(b.options.event+(d?Zb(c):""),a)}var b=this,c=this.state;Ub>c&&d(!0),d(),c>=Ub&&d(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):(this.state=Xb,void 0)},canEmit:function(){for(var a=0;af?T:U,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?S:0>g?V:W,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return ac.prototype.attrTest.call(this,a)&&(this.state&Sb||!(this.state&Sb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),p(cc,ac,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&Sb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),p(dc,Yb,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[Kb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Q|R)&&!e)this.reset();else if(a.eventType&O)this.reset(),this._timer=k(function(){this.state=Vb,this.tryEmit()},b.time,this);else if(a.eventType&Q)return Vb;return Xb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===Vb&&(a&&a.eventType&Q?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=j(),this.manager.emit(this.options.event,this._input)))}}),p(ec,ac,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&Sb)}}),p(fc,ac,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:X|Y,pointers:1},getTouchAction:function(){return bc.prototype.getTouchAction.call(this)},attrTest:function(a){var c,b=this.options.direction;return b&(X|Y)?c=a.velocity:b&X?c=a.velocityX:b&Y&&(c=a.velocityY),this._super.attrTest.call(this,a)&&b&a.direction&&a.distance>this.options.threshold&&i(c)>this.options.velocity&&a.eventType&Q},emit:function(a){var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),p(gc,Yb,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[Lb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance= 0 && !requestAnimationFrame) { + requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; + cancelAnimationFrame = window[vendors[i] + 'CancelRequestAnimationFrame']; + } + + // polyfill with setTimeout fallback + // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945 + if (!requestAnimationFrame || !cancelAnimationFrame) { + requestAnimationFrame = function(callback) { + var now = +Date.now(), + nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { + callback(lastTime = nextTime); + }, nextTime - now); + }; + + cancelAnimationFrame = clearTimeout; + } + + // export to window + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; +}(window)); + + +// Unique ID +Materialize.guid = (function() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + + s4() + '-' + s4() + s4() + s4(); + }; +})(); + +/** + * Escapes hash from special characters + * @param {string} hash String returned from this.hash + * @returns {string} + */ +Materialize.escapeHash = function(hash) { + return hash.replace( /(:|\.|\[|\]|,|=)/g, "\\$1" ); +}; + +Materialize.elementOrParentIsFixed = function(element) { + var $element = $(element); + var $checkElements = $element.add($element.parents()); + var isFixed = false; + $checkElements.each(function(){ + if ($(this).css("position") === "fixed") { + isFixed = true; + return false; + } + }); + return isFixed; +}; + +// Velocity has conflicts when loaded with jQuery, this will check for it +// First, check if in noConflict mode +var Vel; +if (jQuery) { + Vel = jQuery.Velocity; +} else if ($) { + Vel = $.Velocity; +} else { + Vel = Velocity; +} +;(function ($) { + $.fn.collapsible = function(options) { + var defaults = { + accordion: undefined, + onOpen: undefined, + onClose: undefined + }; + + options = $.extend(defaults, options); + + + return this.each(function() { + + var $this = $(this); + + var $panel_headers = $(this).find('> li > .collapsible-header'); + + var collapsible_type = $this.data("collapsible"); + + // Turn off any existing event handlers + $this.off('click.collapse', '> li > .collapsible-header'); + $panel_headers.off('click.collapse'); + + + /**************** + Helper Functions + ****************/ + + // Accordion Open + function accordionOpen(object) { + $panel_headers = $this.find('> li > .collapsible-header'); + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else{ + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + + $panel_headers.not(object).removeClass('active').parent().removeClass('active'); + + // Close previously open accordion elements. + $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() { + if ($(this).is(':visible')) { + $(this).slideUp({ + duration: 350, + easing: "easeOutQuart", + queue: false, + complete: + function() { + $(this).css('height', ''); + execCallbacks($(this).siblings('.collapsible-header')); + } + }); + } + }); + } + + // Expandable Open + function expandableOpen(object) { + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else { + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + } + + // Open collapsible. object: .collapsible-header + function collapsibleOpen(object) { + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + accordionOpen(object); + } else { // Handle Expandables + expandableOpen(object); + } + + execCallbacks(object); + } + + // Handle callbacks + function execCallbacks(object) { + if (object.hasClass('active')) { + if (typeof(options.onOpen) === "function") { + options.onOpen.call(this, object.parent()); + } + } else { + if (typeof(options.onClose) === "function") { + options.onClose.call(this, object.parent()); + } + } + } + + /** + * Check if object is children of panel header + * @param {Object} object Jquery object + * @return {Boolean} true if it is children + */ + function isChildrenOfPanelHeader(object) { + + var panelHeader = getPanelHeader(object); + + return panelHeader.length > 0; + } + + /** + * Get panel header from a children element + * @param {Object} object Jquery object + * @return {Object} panel header object + */ + function getPanelHeader(object) { + + return object.closest('li > .collapsible-header'); + } + + /***** End Helper Functions *****/ + + + + // Add click handler to only direct collapsible header children + $this.on('click.collapse', '> li > .collapsible-header', function(e) { + var element = $(e.target); + + if (isChildrenOfPanelHeader(element)) { + element = getPanelHeader(element); + } + + element.toggleClass('active'); + + collapsibleOpen(element); + }); + + + // Open first active + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + collapsibleOpen($panel_headers.filter('.active').first()); + + } else { // Handle Expandables + $panel_headers.filter('.active').each(function() { + collapsibleOpen($(this)); + }); + } + + }); + }; + + $(document).ready(function(){ + $('.collapsible').collapsible(); + }); +}( jQuery ));;(function ($) { + + // Add posibility to scroll to selected option + // usefull for select for example + $.fn.scrollTo = function(elem) { + $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); + return this; + }; + + $.fn.dropdown = function (options) { + var defaults = { + inDuration: 300, + outDuration: 225, + constrain_width: true, // Constrains width of dropdown to the activator + hover: false, + gutter: 0, // Spacing from edge + belowOrigin: false, + alignment: 'left', + stopPropagation: false + }; + + // Open dropdown. + if (options === "open") { + this.each(function() { + $(this).trigger('open'); + }); + return false; + } + + // Close dropdown. + if (options === "close") { + this.each(function() { + $(this).trigger('close'); + }); + return false; + } + + this.each(function(){ + var origin = $(this); + var curr_options = $.extend({}, defaults, options); + var isFocused = false; + + // Dropdown menu + var activates = $("#"+ origin.attr('data-activates')); + + function updateOptions() { + if (origin.data('induration') !== undefined) + curr_options.inDuration = origin.data('induration'); + if (origin.data('outduration') !== undefined) + curr_options.outDuration = origin.data('outduration'); + if (origin.data('constrainwidth') !== undefined) + curr_options.constrain_width = origin.data('constrainwidth'); + if (origin.data('hover') !== undefined) + curr_options.hover = origin.data('hover'); + if (origin.data('gutter') !== undefined) + curr_options.gutter = origin.data('gutter'); + if (origin.data('beloworigin') !== undefined) + curr_options.belowOrigin = origin.data('beloworigin'); + if (origin.data('alignment') !== undefined) + curr_options.alignment = origin.data('alignment'); + if (origin.data('stoppropagation') !== undefined) + curr_options.stopPropagation = origin.data('stoppropagation'); + } + + updateOptions(); + + // Attach dropdown to its activator + origin.after(activates); + + /* + Helper function to position and resize dropdown. + Used in hover and click handler. + */ + function placeDropdown(eventType) { + // Check for simultaneous focus and click events. + if (eventType === 'focus') { + isFocused = true; + } + + // Check html data attributes + updateOptions(); + + // Set Dropdown state + activates.addClass('active'); + origin.addClass('active'); + + // Constrain width + if (curr_options.constrain_width === true) { + activates.css('width', origin.outerWidth()); + + } else { + activates.css('white-space', 'nowrap'); + } + + // Offscreen detection + var windowHeight = window.innerHeight; + var originHeight = origin.innerHeight(); + var offsetLeft = origin.offset().left; + var offsetTop = origin.offset().top - $(window).scrollTop(); + var currAlignment = curr_options.alignment; + var gutterSpacing = 0; + var leftPosition = 0; + + // Below Origin + var verticalOffset = 0; + if (curr_options.belowOrigin === true) { + verticalOffset = originHeight; + } + + // Check for scrolling positioned container. + var scrollYOffset = 0; + var scrollXOffset = 0; + var wrapper = origin.parent(); + if (!wrapper.is('body')) { + if (wrapper[0].scrollHeight > wrapper[0].clientHeight) { + scrollYOffset = wrapper[0].scrollTop; + } + if (wrapper[0].scrollWidth > wrapper[0].clientWidth) { + scrollXOffset = wrapper[0].scrollLeft; + } + } + + + if (offsetLeft + activates.innerWidth() > $(window).width()) { + // Dropdown goes past screen on right, force right alignment + currAlignment = 'right'; + + } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { + // Dropdown goes past screen on left, force left alignment + currAlignment = 'left'; + } + // Vertical bottom offscreen detection + if (offsetTop + activates.innerHeight() > windowHeight) { + // If going upwards still goes offscreen, just crop height of dropdown. + if (offsetTop + originHeight - activates.innerHeight() < 0) { + var adjustedHeight = windowHeight - offsetTop - verticalOffset; + activates.css('max-height', adjustedHeight); + } else { + // Flow upwards. + if (!verticalOffset) { + verticalOffset += originHeight; + } + verticalOffset -= activates.innerHeight(); + } + } + + // Handle edge alignment + if (currAlignment === 'left') { + gutterSpacing = curr_options.gutter; + leftPosition = origin.position().left + gutterSpacing; + } + else if (currAlignment === 'right') { + var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); + gutterSpacing = -curr_options.gutter; + leftPosition = offsetRight + gutterSpacing; + } + + // Position dropdown + activates.css({ + position: 'absolute', + top: origin.position().top + verticalOffset + scrollYOffset, + left: leftPosition + scrollXOffset + }); + + + // Show dropdown + activates.stop(true, true).css('opacity', 0) + .slideDown({ + queue: false, + duration: curr_options.inDuration, + easing: 'easeOutCubic', + complete: function() { + $(this).css('height', ''); + } + }) + .animate( {opacity: 1}, {queue: false, duration: curr_options.inDuration, easing: 'easeOutSine'}); + } + + function hideDropdown() { + // Check for simultaneous focus and click events. + isFocused = false; + activates.fadeOut(curr_options.outDuration); + activates.removeClass('active'); + origin.removeClass('active'); + setTimeout(function() { activates.css('max-height', ''); }, curr_options.outDuration); + } + + // Hover + if (curr_options.hover) { + var open = false; + origin.unbind('click.' + origin.attr('id')); + // Hover handler to show dropdown + origin.on('mouseenter', function(e){ // Mouse over + if (open === false) { + placeDropdown(); + open = true; + } + }); + origin.on('mouseleave', function(e){ + // If hover on origin then to something other than dropdown content, then close + var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element + if(!$(toEl).closest('.dropdown-content').is(activates)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + activates.on('mouseleave', function(e){ // Mouse out + var toEl = e.toElement || e.relatedTarget; + if(!$(toEl).closest('.dropdown-button').is(origin)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + // Click + } else { + // Click handler to show dropdown + origin.unbind('click.' + origin.attr('id')); + origin.bind('click.'+origin.attr('id'), function(e){ + if (!isFocused) { + if ( origin[0] == e.currentTarget && + !origin.hasClass('active') && + ($(e.target).closest('.dropdown-content').length === 0)) { + e.preventDefault(); // Prevents button click from moving window + if (curr_options.stopPropagation) { + e.stopPropagation(); + } + placeDropdown('click'); + } + // If origin is clicked and menu is open, close menu + else if (origin.hasClass('active')) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + // If menu open, add click close handler to document + if (activates.hasClass('active')) { + $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) { + if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + }); + } + } + }); + + } // End else + + // Listen to open and close event - useful for select component + origin.on('open', function(e, eventType) { + placeDropdown(eventType); + }); + origin.on('close', hideDropdown); + + + }); + }; // End dropdown plugin + + $(document).ready(function(){ + $('.dropdown-button').dropdown(); + }); +}( jQuery )); +;(function($) { + var _stack = 0, + _lastID = 0, + _generateID = function() { + _lastID++; + return 'materialize-modal-overlay-' + _lastID; + }; + + var methods = { + init : function(options) { + var defaults = { + opacity: 0.5, + in_duration: 350, + out_duration: 250, + ready: undefined, + complete: undefined, + dismissible: true, + starting_top: '4%', + ending_top: '10%' + }; + + // Override defaults + options = $.extend(defaults, options); + + return this.each(function() { + var $modal = $(this); + var modal_id = $(this).attr("id") || '#' + $(this).data('target'); + + var closeModal = function() { + var overlayID = $modal.data('overlay-id'); + var $overlay = $('#' + overlayID); + $modal.removeClass('open'); + + // Enable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $modal.find('.modal-close').off('click.close'); + $(document).off('keyup.modal' + overlayID); + + $overlay.velocity( { opacity: 0}, {duration: options.out_duration, queue: false, ease: "easeOutQuart"}); + + + // Define Bottom Sheet animation + var exitVelocityOptions = { + duration: options.out_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + $(this).css({display:"none"}); + + // Call complete callback + if (typeof(options.complete) === "function") { + options.complete.call(this, $modal); + } + $overlay.remove(); + _stack--; + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "-100%", opacity: 0}, exitVelocityOptions); + } + else { + $modal.velocity( + { top: options.starting_top, opacity: 0, scaleX: 0.7}, + exitVelocityOptions + ); + } + }; + + var openModal = function($trigger) { + var $body = $('body'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + if ($modal.hasClass('open')) { + return; + } + + var overlayID = _generateID(); + var $overlay = $(''); + lStack = (++_stack); + + // Store a reference of the overlay + $overlay.attr('id', overlayID).css('z-index', 1000 + lStack * 2); + $modal.data('overlay-id', overlayID).css('z-index', 1000 + lStack * 2 + 1); + $modal.addClass('open'); + + $("body").append($overlay); + + if (options.dismissible) { + $overlay.click(function() { + closeModal(); + }); + // Return on ESC + $(document).on('keyup.modal' + overlayID, function(e) { + if (e.keyCode === 27) { // ESC key + closeModal(); + } + }); + } + + $modal.find(".modal-close").on('click.close', function(e) { + closeModal(); + }); + + $overlay.css({ display : "block", opacity : 0 }); + + $modal.css({ + display : "block", + opacity: 0 + }); + + $overlay.velocity({opacity: options.opacity}, {duration: options.in_duration, queue: false, ease: "easeOutCubic"}); + $modal.data('associated-overlay', $overlay[0]); + + // Define Bottom Sheet animation + var enterVelocityOptions = { + duration: options.in_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + if (typeof(options.ready) === "function") { + options.ready.call(this, $modal, $trigger); + } + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "0", opacity: 1}, enterVelocityOptions); + } + else { + $.Velocity.hook($modal, "scaleX", 0.7); + $modal.css({ top: options.starting_top }); + $modal.velocity({top: options.ending_top, opacity: 1, scaleX: '1'}, enterVelocityOptions); + } + + }; + + // Reset handlers + $(document).off('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]'); + $(this).off('openModal'); + $(this).off('closeModal'); + + // Close Handlers + $(document).on('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]', function(e) { + options.starting_top = ($(this).offset().top - $(window).scrollTop()) /1.15; + openModal($(this)); + e.preventDefault(); + }); // done set on click + + $(this).on('openModal', function() { + var modal_id = $(this).attr("href") || '#' + $(this).data('target'); + openModal(); + }); + + $(this).on('closeModal', function() { + closeModal(); + }); + }); // done return + }, + open : function() { + $(this).trigger('openModal'); + }, + close : function() { + $(this).trigger('closeModal'); + } + }; + + $.fn.modal = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.modal' ); + } + }; +})(jQuery); +;(function ($) { + + $.fn.materialbox = function () { + + return this.each(function() { + + if ($(this).hasClass('initialized')) { + return; + } + + $(this).addClass('initialized'); + + var overlayActive = false; + var doneAnimating = true; + var inDuration = 275; + var outDuration = 200; + var origin = $(this); + var placeholder = $('
        ').addClass('material-placeholder'); + var originalWidth = 0; + var originalHeight = 0; + var ancestorsChanged; + var ancestor; + origin.wrap(placeholder); + + + origin.on('click', function(){ + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.width(); + var originalHeight = origin.height(); + + + // If already modal, return to original + if (doneAnimating === false) { + returnToOriginal(); + return false; + } + else if (overlayActive && doneAnimating===true) { + returnToOriginal(); + return false; + } + + + // Set states + doneAnimating = false; + origin.addClass('active'); + overlayActive = true; + + // Set positioning for placeholder + placeholder.css({ + width: placeholder[0].getBoundingClientRect().width, + height: placeholder[0].getBoundingClientRect().height, + position: 'relative', + top: 0, + left: 0 + }); + + // Find ancestor with overflow: hidden; and remove it + ancestorsChanged = undefined; + ancestor = placeholder[0].parentNode; + var count = 0; + while (ancestor !== null && !$(ancestor).is(document)) { + var curr = $(ancestor); + if (curr.css('overflow') !== 'visible') { + curr.css('overflow', 'visible'); + if (ancestorsChanged === undefined) { + ancestorsChanged = curr; + } + else { + ancestorsChanged = ancestorsChanged.add(curr); + } + } + ancestor = ancestor.parentNode; + } + + // Set css on origin + origin.css({position: 'absolute', 'z-index': 1000}) + .data('width', originalWidth) + .data('height', originalHeight); + + // Add overlay + var overlay = $('
        ') + .css({ + opacity: 0 + }) + .click(function(){ + if (doneAnimating === true) + returnToOriginal(); + }); + // Animate Overlay + // Put before in origin image to preserve z-index layering. + origin.before(overlay); + overlay.velocity({opacity: 1}, + {duration: inDuration, queue: false, easing: 'easeOutQuad'} ); + + // Add and animate caption if it exists + if (origin.data('caption') !== "") { + var $photo_caption = $('
        '); + $photo_caption.text(origin.data('caption')); + $('body').append($photo_caption); + $photo_caption.css({ "display": "inline" }); + $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'}); + } + + // Resize Image + var ratio = 0; + var widthPercent = originalWidth / windowWidth; + var heightPercent = originalHeight / windowHeight; + var newWidth = 0; + var newHeight = 0; + + if (widthPercent > heightPercent) { + ratio = originalHeight / originalWidth; + newWidth = windowWidth * 0.9; + newHeight = windowWidth * 0.9 * ratio; + } + else { + ratio = originalWidth / originalHeight; + newWidth = (windowHeight * 0.9) * ratio; + newHeight = windowHeight * 0.9; + } + + // Animate image + set z-index + if(origin.hasClass('responsive-img')) { + origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false, + complete: function(){ + origin.css({left: 0, top: 0}) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); + } // End Complete + }); // End Velocity + } + else { + origin.css('left', 0) + .css('top', 0) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); // End Velocity + } + + }); // End origin on click + + + // Return on scroll + $(window).scroll(function() { + if (overlayActive) { + returnToOriginal(); + } + }); + + // Return on ESC + $(document).keyup(function(e) { + + if (e.keyCode === 27 && doneAnimating === true) { // ESC key + if (overlayActive) { + returnToOriginal(); + } + } + }); + + + // This function returns the modaled image to the original spot + function returnToOriginal() { + + doneAnimating = false; + + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.data('width'); + var originalHeight = origin.data('height'); + + origin.velocity("stop", true); + $('#materialbox-overlay').velocity("stop", true); + $('.materialbox-caption').velocity("stop", true); + + + $('#materialbox-overlay').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + // Remove Overlay + overlayActive = false; + $(this).remove(); + } + }); + + // Resize Image + origin.velocity( + { + width: originalWidth, + height: originalHeight, + left: 0, + top: 0 + }, + { + duration: outDuration, + queue: false, easing: 'easeOutQuad' + } + ); + + // Remove Caption + reset css settings on image + $('.materialbox-caption').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + placeholder.css({ + height: '', + width: '', + position: '', + top: '', + left: '' + }); + + origin.css({ + height: '', + top: '', + left: '', + width: '', + 'max-width': '', + position: '', + 'z-index': '' + }); + + // Remove class + origin.removeClass('active'); + doneAnimating = true; + $(this).remove(); + + // Remove overflow overrides on ancestors + if (ancestorsChanged) { + ancestorsChanged.css('overflow', ''); + } + } + }); + + } + }); +}; + +$(document).ready(function(){ + $('.materialboxed').materialbox(); +}); + +}( jQuery )); +;(function ($) { + + $.fn.parallax = function () { + var window_width = $(window).width(); + // Parallax Scripts + return this.each(function(i) { + var $this = $(this); + $this.addClass('parallax'); + + function updateParallax(initial) { + var container_height; + if (window_width < 601) { + container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height(); + } + else { + container_height = ($this.height() > 0) ? $this.height() : 500; + } + var $img = $this.children("img").first(); + var img_height = $img.height(); + var parallax_dist = img_height - container_height; + var bottom = $this.offset().top + container_height; + var top = $this.offset().top; + var scrollTop = $(window).scrollTop(); + var windowHeight = window.innerHeight; + var windowBottom = scrollTop + windowHeight; + var percentScrolled = (windowBottom - top) / (container_height + windowHeight); + var parallax = Math.round((parallax_dist * percentScrolled)); + + if (initial) { + $img.css('display', 'block'); + } + if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) { + $img.css('transform', "translate3D(-50%," + parallax + "px, 0)"); + } + + } + + // Wait for image load + $this.children("img").one("load", function() { + updateParallax(true); + }).each(function() { + if (this.complete) $(this).trigger("load"); + }); + + $(window).scroll(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + $(window).resize(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + }); + + }; +}( jQuery )); +;(function ($) { + + var methods = { + init : function(options) { + var defaults = { + onShow: null + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each set of tabs, we want to keep track of + // which tab is active and its associated content + var $this = $(this), + window_width = $(window).width(); + + var $active, $content, $links = $this.find('li.tab a'), + $tabs_width = $this.width(), + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length, + $index = 0; + + // Finds right attribute for indicator based on active tab. + // el: jQuery Object + var calcRightPos = function(el) { + return $tabs_width - el.position().left - el.outerWidth() - $this.scrollLeft(); + }; + + // Finds left attribute for indicator based on active tab. + // el: jQuery Object + var calcLeftPos = function(el) { + return el.position().left + $this.scrollLeft(); + }; + + // If the location.hash matches one of the links, use that as the active tab. + $active = $($links.filter('[href="'+location.hash+'"]')); + + // If no match is found, use the first link or any with class 'active' as the initial active tab. + if ($active.length === 0) { + $active = $(this).find('li.tab a.active').first(); + } + if ($active.length === 0) { + $active = $(this).find('li.tab a').first(); + } + + $active.addClass('active'); + $index = $links.index($active); + if ($index < 0) { + $index = 0; + } + + if ($active[0] !== undefined) { + $content = $($active[0].hash); + } + + // append indicator then set indicator width to tab width + $this.append('
        '); + var $indicator = $this.find('.indicator'); + if ($this.is(":visible")) { + // $indicator.css({"right": $tabs_width - (($index + 1) * $tab_width)}); + // $indicator.css({"left": $index * $tab_width}); + setTimeout(function() { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + }, 0); + } + $(window).resize(function () { + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + if ($index < 0) { + $index = 0; + } + if ($tab_width !== 0 && $tabs_width !== 0) { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + } + }); + + // Hide the remaining content + $links.not($active).each(function () { + $(Materialize.escapeHash(this.hash)).hide(); + }); + + + // Bind the click event handler + $this.on('click', 'a', function(e) { + if ($(this).parent().hasClass('disabled')) { + e.preventDefault(); + return; + } + + // Act as regular link if target attribute is specified. + if (!!$(this).attr("target")) { + return; + } + + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + + // Make the old tab inactive. + $active.removeClass('active'); + if ($content !== undefined) { + $content.hide(); + } + + // Update the variables with the new link and content + $active = $(this); + $content = $(Materialize.escapeHash(this.hash)); + $links = $this.find('li.tab a'); + var activeRect = $active.position(); + + // Make the tab active. + $active.addClass('active'); + var $prev_index = $index; + $index = $links.index($(this)); + if ($index < 0) { + $index = 0; + } + // Change url to current tab + // window.location.hash = $active.attr('href'); + + if ($content !== undefined) { + $content.show(); + if (typeof(options.onShow) === "function") { + options.onShow.call(this, $content); + } + } + + // Update indicator + + if (($index - $prev_index) >= 0) { + $indicator.velocity({"right": calcRightPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"left": calcLeftPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + + } else { + $indicator.velocity({"left": calcLeftPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"right": calcRightPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + } + + // Prevent the anchor's default click action + e.preventDefault(); + }); + }); + + }, + select_tab : function( id ) { + this.find('a[href="#' + id + '"]').trigger('click'); + } + }; + + $.fn.tabs = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tabs' ); + } + }; + + $(document).ready(function(){ + $('ul.tabs').tabs(); + }); +}( jQuery )); +;(function ($) { + $.fn.tooltip = function (options) { + var timeout = null, + margin = 5; + + // Defaults + var defaults = { + delay: 350, + tooltip: '', + position: 'bottom', + html: false + }; + + // Remove tooltip from the activator + if (options === "remove") { + this.each(function() { + $('#' + $(this).attr('data-tooltip-id')).remove(); + $(this).off('mouseenter.tooltip mouseleave.tooltip'); + }); + return false; + } + + options = $.extend(defaults, options); + + return this.each(function() { + var tooltipId = Materialize.guid(); + var origin = $(this); + + // Destroy old tooltip + if (origin.attr('data-tooltip-id')) { + $('#' + origin.attr('data-tooltip-id')).remove(); + } + + origin.attr('data-tooltip-id', tooltipId); + + // Get attributes. + var allowHtml, + tooltipDelay, + tooltipPosition, + tooltipText, + tooltipEl, + backdrop; + var setAttributes = function() { + allowHtml = origin.attr('data-html') ? origin.attr('data-html') === 'true' : options.html; + tooltipDelay = origin.attr('data-delay'); + tooltipDelay = (tooltipDelay === undefined || tooltipDelay === '') ? + options.delay : tooltipDelay; + tooltipPosition = origin.attr('data-position'); + tooltipPosition = (tooltipPosition === undefined || tooltipPosition === '') ? + options.position : tooltipPosition; + tooltipText = origin.attr('data-tooltip'); + tooltipText = (tooltipText === undefined || tooltipText === '') ? + options.tooltip : tooltipText; + }; + setAttributes(); + + var renderTooltipEl = function() { + var tooltip = $('
        '); + + // Create Text span + if (allowHtml) { + tooltipText = $('').html(tooltipText); + } else{ + tooltipText = $('').text(tooltipText); + } + + // Create tooltip + tooltip.append(tooltipText) + .appendTo($('body')) + .attr('id', tooltipId); + + // Create backdrop + backdrop = $('
        '); + backdrop.appendTo(tooltip); + return tooltip; + }; + tooltipEl = renderTooltipEl(); + + // Destroy previously binded events + origin.off('mouseenter.tooltip mouseleave.tooltip'); + // Mouse In + var started = false, timeoutRef; + origin.on({'mouseenter.tooltip': function(e) { + var showTooltip = function() { + setAttributes(); + started = true; + tooltipEl.velocity('stop'); + backdrop.velocity('stop'); + tooltipEl.css({ display: 'block', left: '0px', top: '0px' }); + + // Tooltip positioning + var originWidth = origin.outerWidth(); + var originHeight = origin.outerHeight(); + + var tooltipHeight = tooltipEl.outerHeight(); + var tooltipWidth = tooltipEl.outerWidth(); + var tooltipVerticalMovement = '0px'; + var tooltipHorizontalMovement = '0px'; + var scaleXFactor = 8; + var scaleYFactor = 8; + var targetTop, targetLeft, newCoordinates; + + if (tooltipPosition === "top") { + // Top Position + targetTop = origin.offset().top - tooltipHeight - margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipVerticalMovement = '-10px'; + backdrop.css({ + bottom: 0, + left: 0, + borderRadius: '14px 14px 0 0', + transformOrigin: '50% 100%', + marginTop: tooltipHeight, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + // Left Position + else if (tooltipPosition === "left") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left - tooltipWidth - margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '-10px'; + backdrop.css({ + top: '-7px', + right: 0, + width: '14px', + height: '14px', + borderRadius: '14px 0 0 14px', + transformOrigin: '95% 50%', + marginTop: tooltipHeight/2, + marginLeft: tooltipWidth + }); + } + // Right Position + else if (tooltipPosition === "right") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left + originWidth + margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '+10px'; + backdrop.css({ + top: '-7px', + left: 0, + width: '14px', + height: '14px', + borderRadius: '0 14px 14px 0', + transformOrigin: '5% 50%', + marginTop: tooltipHeight/2, + marginLeft: '0px' + }); + } + else { + // Bottom Position + targetTop = origin.offset().top + origin.outerHeight() + margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + tooltipVerticalMovement = '+10px'; + backdrop.css({ + top: 0, + left: 0, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + + // Set tooptip css placement + tooltipEl.css({ + top: newCoordinates.y, + left: newCoordinates.x + }); + + // Calculate Scale to fill + scaleXFactor = Math.SQRT2 * tooltipWidth / parseInt(backdrop.css('width')); + scaleYFactor = Math.SQRT2 * tooltipHeight / parseInt(backdrop.css('height')); + + tooltipEl.velocity({ marginTop: tooltipVerticalMovement, marginLeft: tooltipHorizontalMovement}, { duration: 350, queue: false }) + .velocity({opacity: 1}, {duration: 300, delay: 50, queue: false}); + backdrop.css({ display: 'block' }) + .velocity({opacity:1},{duration: 55, delay: 0, queue: false}) + .velocity({scaleX: scaleXFactor, scaleY: scaleYFactor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'}); + }; + + timeoutRef = setTimeout(showTooltip, tooltipDelay); // End Interval + + // Mouse Out + }, + 'mouseleave.tooltip': function(){ + // Reset State + started = false; + clearTimeout(timeoutRef); + + // Animate back + setTimeout(function() { + if (started !== true) { + tooltipEl.velocity({ + opacity: 0, marginTop: 0, marginLeft: 0}, { duration: 225, queue: false}); + backdrop.velocity({opacity: 0, scaleX: 1, scaleY: 1}, { + duration:225, + queue: false, + complete: function(){ + backdrop.css('display', 'none'); + tooltipEl.css('display', 'none'); + started = false;} + }); + } + },225); + } + }); + }); + }; + + var repositionWithinScreen = function(x, y, width, height) { + var newX = x; + var newY = y; + + if (newX < 0) { + newX = 4; + } else if (newX + width > window.innerWidth) { + newX -= newX + width - window.innerWidth; + } + + if (newY < 0) { + newY = 4; + } else if (newY + height > window.innerHeight + $(window).scrollTop) { + newY -= newY + height - window.innerHeight; + } + + return {x: newX, y: newY}; + }; + + $(document).ready(function(){ + $('.tooltipped').tooltip(); + }); +}( jQuery )); +;/*! + * Waves v0.6.4 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */ + +;(function(window) { + 'use strict'; + + var Waves = Waves || {}; + var $$ = document.querySelectorAll.bind(document); + + // Find exact position of element + function isWindow(obj) { + return obj !== null && obj === obj.window; + } + + function getWindow(elem) { + return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; + } + + function offset(elem) { + var docElem, win, + box = {top: 0, left: 0}, + doc = elem && elem.ownerDocument; + + docElem = doc.documentElement; + + if (typeof elem.getBoundingClientRect !== typeof undefined) { + box = elem.getBoundingClientRect(); + } + win = getWindow(doc); + return { + top: box.top + win.pageYOffset - docElem.clientTop, + left: box.left + win.pageXOffset - docElem.clientLeft + }; + } + + function convertStyle(obj) { + var style = ''; + + for (var a in obj) { + if (obj.hasOwnProperty(a)) { + style += (a + ':' + obj[a] + ';'); + } + } + + return style; + } + + var Effect = { + + // Effect delay + duration: 750, + + show: function(e, element) { + + // Disable right click + if (e.button === 2) { + return false; + } + + var el = element || this; + + // Create ripple + var ripple = document.createElement('div'); + ripple.className = 'waves-ripple'; + el.appendChild(ripple); + + // Get click coordinate and element witdh + var pos = offset(el); + var relativeY = (e.pageY - pos.top); + var relativeX = (e.pageX - pos.left); + var scale = 'scale('+((el.clientWidth / 100) * 10)+')'; + + // Support for touch devices + if ('touches' in e) { + relativeY = (e.touches[0].pageY - pos.top); + relativeX = (e.touches[0].pageX - pos.left); + } + + // Attach data to element + ripple.setAttribute('data-hold', Date.now()); + ripple.setAttribute('data-scale', scale); + ripple.setAttribute('data-x', relativeX); + ripple.setAttribute('data-y', relativeY); + + // Set ripple position + var rippleStyle = { + 'top': relativeY+'px', + 'left': relativeX+'px' + }; + + ripple.className = ripple.className + ' waves-notransition'; + ripple.setAttribute('style', convertStyle(rippleStyle)); + ripple.className = ripple.className.replace('waves-notransition', ''); + + // Scale the ripple + rippleStyle['-webkit-transform'] = scale; + rippleStyle['-moz-transform'] = scale; + rippleStyle['-ms-transform'] = scale; + rippleStyle['-o-transform'] = scale; + rippleStyle.transform = scale; + rippleStyle.opacity = '1'; + + rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-o-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['transition-duration'] = Effect.duration + 'ms'; + + rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + + ripple.setAttribute('style', convertStyle(rippleStyle)); + }, + + hide: function(e) { + TouchHandler.touchup(e); + + var el = this; + var width = el.clientWidth * 1.4; + + // Get first ripple + var ripple = null; + var ripples = el.getElementsByClassName('waves-ripple'); + if (ripples.length > 0) { + ripple = ripples[ripples.length - 1]; + } else { + return false; + } + + var relativeX = ripple.getAttribute('data-x'); + var relativeY = ripple.getAttribute('data-y'); + var scale = ripple.getAttribute('data-scale'); + + // Get delay beetween mousedown and mouse leave + var diff = Date.now() - Number(ripple.getAttribute('data-hold')); + var delay = 350 - diff; + + if (delay < 0) { + delay = 0; + } + + // Fade out ripple after delay + setTimeout(function() { + var style = { + 'top': relativeY+'px', + 'left': relativeX+'px', + 'opacity': '0', + + // Duration + '-webkit-transition-duration': Effect.duration + 'ms', + '-moz-transition-duration': Effect.duration + 'ms', + '-o-transition-duration': Effect.duration + 'ms', + 'transition-duration': Effect.duration + 'ms', + '-webkit-transform': scale, + '-moz-transform': scale, + '-ms-transform': scale, + '-o-transform': scale, + 'transform': scale, + }; + + ripple.setAttribute('style', convertStyle(style)); + + setTimeout(function() { + try { + el.removeChild(ripple); + } catch(e) { + return false; + } + }, Effect.duration); + }, delay); + }, + + // Little hack to make can perform waves effect + wrapInput: function(elements) { + for (var a = 0; a < elements.length; a++) { + var el = elements[a]; + + if (el.tagName.toLowerCase() === 'input') { + var parent = el.parentNode; + + // If input already have parent just pass through + if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) { + continue; + } + + // Put element class and style to the specified parent + var wrapper = document.createElement('i'); + wrapper.className = el.className + ' waves-input-wrapper'; + + var elementStyle = el.getAttribute('style'); + + if (!elementStyle) { + elementStyle = ''; + } + + wrapper.setAttribute('style', elementStyle); + + el.className = 'waves-button-input'; + el.removeAttribute('style'); + + // Put element as child + parent.replaceChild(wrapper, el); + wrapper.appendChild(el); + } + } + } + }; + + + /** + * Disable mousedown event for 500ms during and after touch + */ + var TouchHandler = { + /* uses an integer rather than bool so there's no issues with + * needing to clear timeouts if another touch event occurred + * within the 500ms. Cannot mouseup between touchstart and + * touchend, nor in the 500ms after touchend. */ + touches: 0, + allowEvent: function(e) { + var allow = true; + + if (e.type === 'touchstart') { + TouchHandler.touches += 1; //push + } else if (e.type === 'touchend' || e.type === 'touchcancel') { + setTimeout(function() { + if (TouchHandler.touches > 0) { + TouchHandler.touches -= 1; //pop after 500ms + } + }, 500); + } else if (e.type === 'mousedown' && TouchHandler.touches > 0) { + allow = false; + } + + return allow; + }, + touchup: function(e) { + TouchHandler.allowEvent(e); + } + }; + + + /** + * Delegated click handler for .waves-effect element. + * returns null when .waves-effect element not in "click tree" + */ + function getWavesEffectElement(e) { + if (TouchHandler.allowEvent(e) === false) { + return null; + } + + var element = null; + var target = e.target || e.srcElement; + + while (target.parentElement !== null) { + if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) { + element = target; + break; + } else if (target.classList.contains('waves-effect')) { + element = target; + break; + } + target = target.parentElement; + } + + return element; + } + + /** + * Bubble the click and show effect if .waves-effect elem was found + */ + function showEffect(e) { + var element = getWavesEffectElement(e); + + if (element !== null) { + Effect.show(e, element); + + if ('ontouchstart' in window) { + element.addEventListener('touchend', Effect.hide, false); + element.addEventListener('touchcancel', Effect.hide, false); + } + + element.addEventListener('mouseup', Effect.hide, false); + element.addEventListener('mouseleave', Effect.hide, false); + } + } + + Waves.displayEffect = function(options) { + options = options || {}; + + if ('duration' in options) { + Effect.duration = options.duration; + } + + //Wrap input inside tag + Effect.wrapInput($$('.waves-effect')); + + if ('ontouchstart' in window) { + document.body.addEventListener('touchstart', showEffect, false); + } + + document.body.addEventListener('mousedown', showEffect, false); + }; + + /** + * Attach Waves to an input element (or any element which doesn't + * bubble mouseup/mousedown events). + * Intended to be used with dynamically loaded forms/inputs, or + * where the user doesn't want a delegated click handler. + */ + Waves.attach = function(element) { + //FUTURE: automatically add waves classes and allow users + // to specify them with an options param? Eg. light/classic/button + if (element.tagName.toLowerCase() === 'input') { + Effect.wrapInput([element]); + element = element.parentElement; + } + + if ('ontouchstart' in window) { + element.addEventListener('touchstart', showEffect, false); + } + + element.addEventListener('mousedown', showEffect, false); + }; + + window.Waves = Waves; + + document.addEventListener('DOMContentLoaded', function() { + Waves.displayEffect(); + }, false); + +})(window); +;Materialize.toast = function (message, displayLength, className, completeCallback) { + className = className || ""; + + var container = document.getElementById('toast-container'); + + // Create toast container if it does not exist + if (container === null) { + // create notification container + container = document.createElement('div'); + container.id = 'toast-container'; + document.body.appendChild(container); + } + + // Select and append toast + var newToast = createToast(message); + + // only append toast if message is not undefined + if(message){ + container.appendChild(newToast); + } + + newToast.style.top = '35px'; + newToast.style.opacity = 0; + + // Animate toast in + Vel(newToast, { "top" : "0px", opacity: 1 }, {duration: 300, + easing: 'easeOutCubic', + queue: false}); + + // Allows timer to be pause while being panned + var timeLeft = displayLength; + var counterInterval; + if (timeLeft != null) { + counterInterval = setInterval (function(){ + if (newToast.parentNode === null) + window.clearInterval(counterInterval); + + // If toast is not being dragged, decrease its time remaining + if (!newToast.classList.contains('panning')) { + timeLeft -= 20; + } + + if (timeLeft <= 0) { + // Animate toast out + Vel(newToast, {"opacity": 0, marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + // Call the optional callback + if(typeof(completeCallback) === "function") + completeCallback(); + // Remove toast after it times out + this[0].parentNode.removeChild(this[0]); + } + }); + window.clearInterval(counterInterval); + } + }, 20); + } + + + + function createToast(html) { + + // Create toast + var toast = document.createElement('div'); + toast.classList.add('toast'); + if (className) { + var classes = className.split(' '); + + for (var i = 0, count = classes.length; i < count; i++) { + toast.classList.add(classes[i]); + } + } + // If type of parameter is HTML Element + if ( typeof HTMLElement === "object" ? html instanceof HTMLElement : html && typeof html === "object" && html !== null && html.nodeType === 1 && typeof html.nodeName==="string" +) { + toast.appendChild(html); + } + else if (html instanceof jQuery) { + // Check if it is jQuery object + toast.appendChild(html[0]); + } + else { + // Insert as text; + toast.innerHTML = html; + } + // Bind hammer + var hammerHandler = new Hammer(toast, {prevent_default: false}); + hammerHandler.on('pan', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // Change toast state + if (!toast.classList.contains('panning')){ + toast.classList.add('panning'); + } + + var opacityPercent = 1-Math.abs(deltaX / activationDistance); + if (opacityPercent < 0) + opacityPercent = 0; + + Vel(toast, {left: deltaX, opacity: opacityPercent }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + }); + + hammerHandler.on('panend', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // If toast dragged past activation point + if (Math.abs(deltaX) > activationDistance) { + Vel(toast, {marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + if(typeof(completeCallback) === "function") { + completeCallback(); + } + toast.parentNode.removeChild(toast); + } + }); + + } else { + toast.classList.remove('panning'); + // Put toast back into original position + Vel(toast, { left: 0, opacity: 1 }, { duration: 300, + easing: 'easeOutExpo', + queue: false + }); + + } + }); + + return toast; + } +}; +;(function ($) { + + var methods = { + init : function(options) { + var defaults = { + menuWidth: 300, + edge: 'left', + closeOnClick: false, + draggable: true + }; + options = $.extend(defaults, options); + + $(this).each(function(){ + var $this = $(this); + var menu_id = $("#"+ $this.attr('data-activates')); + + // Set to width + if (options.menuWidth != 300) { + menu_id.css('width', options.menuWidth); + } + + // Add Touch Area + var $dragTarget; + if (options.draggable) { + $dragTarget = $('
        ').attr('data-sidenav', $this.attr('data-activates')); + $('body').append($dragTarget); + } else { + $dragTarget = $(); + } + + if (options.edge == 'left') { + menu_id.css('transform', 'translateX(-100%)'); + $dragTarget.css({'left': 0}); // Add Touch Area + } + else { + menu_id.addClass('right-aligned') // Change text-alignment to right + .css('transform', 'translateX(100%)'); + $dragTarget.css({'right': 0}); // Add Touch Area + } + + // If fixed sidenav, bring menu out + if (menu_id.hasClass('fixed')) { + if (window.innerWidth > 992) { + menu_id.css('transform', 'translateX(0)'); + } + } + + // Window resize to reset on large screens fixed + if (menu_id.hasClass('fixed')) { + $(window).resize( function() { + if (window.innerWidth > 992) { + // Close menu if window is resized bigger than 992 and user has fixed sidenav + if ($('#sidenav-overlay').length !== 0 && menuOut) { + removeMenu(true); + } + else { + // menu_id.removeAttr('style'); + menu_id.css('transform', 'translateX(0%)'); + // menu_id.css('width', options.menuWidth); + } + } + else if (menuOut === false){ + if (options.edge === 'left') { + menu_id.css('transform', 'translateX(-100%)'); + } else { + menu_id.css('transform', 'translateX(100%)'); + } + + } + + }); + } + + // if closeOnClick, then add close event for all a tags in side sideNav + if (options.closeOnClick === true) { + menu_id.on("click.itemclick", "a:not(.collapsible-header)", function(){ + removeMenu(); + }); + } + + var removeMenu = function(restoreNav) { + panning = false; + menuOut = false; + // Reenable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $('#sidenav-overlay').velocity({opacity: 0}, {duration: 200, + queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + if (options.edge === 'left') { + // Reset phantom div + $dragTarget.css({width: '', right: '', left: '0'}); + menu_id.velocity( + {'translateX': '-100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + + }); + } + else { + // Reset phantom div + $dragTarget.css({width: '', right: '0', left: ''}); + menu_id.velocity( + {'translateX': '100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + }); + } + }; + + + + // Touch Event + var panning = false; + var menuOut = false; + + if (options.draggable) { + $dragTarget.on('click', function(){ + if (menuOut) { + removeMenu(); + } + }); + + $dragTarget.hammer({ + prevent_default: false + }).bind('pan', function(e) { + + if (e.gesture.pointerType == "touch") { + + var direction = e.gesture.direction; + var x = e.gesture.center.x; + var y = e.gesture.center.y; + var velocityX = e.gesture.velocityX; + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('#sidenav-overlay'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // If overlay does not exist, create one and if it is clicked, close menu + if ($overlay.length === 0) { + $overlay = $('
        '); + $overlay.css('opacity', 0).click( function(){ + removeMenu(); + }); + $('body').append($overlay); + } + + // Keep within boundaries + if (options.edge === 'left') { + if (x > options.menuWidth) { x = options.menuWidth; } + else if (x < 0) { x = 0; } + } + + if (options.edge === 'left') { + // Left Direction + if (x < (options.menuWidth / 2)) { menuOut = false; } + // Right Direction + else if (x >= (options.menuWidth / 2)) { menuOut = true; } + menu_id.css('transform', 'translateX(' + (x - options.menuWidth) + 'px)'); + } + else { + // Left Direction + if (x < (window.innerWidth - options.menuWidth / 2)) { + menuOut = true; + } + // Right Direction + else if (x >= (window.innerWidth - options.menuWidth / 2)) { + menuOut = false; + } + var rightPos = (x - options.menuWidth / 2); + if (rightPos < 0) { + rightPos = 0; + } + + menu_id.css('transform', 'translateX(' + rightPos + 'px)'); + } + + + // Percentage overlay + var overlayPerc; + if (options.edge === 'left') { + overlayPerc = x / options.menuWidth; + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + else { + overlayPerc = Math.abs((x - window.innerWidth) / options.menuWidth); + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + } + + }).bind('panend', function(e) { + + if (e.gesture.pointerType == "touch") { + var $overlay = $('
        '); + var velocityX = e.gesture.velocityX; + var x = e.gesture.center.x; + var leftPos = x - options.menuWidth; + var rightPos = x - options.menuWidth / 2; + if (leftPos > 0 ) { + leftPos = 0; + } + if (rightPos < 0) { + rightPos = 0; + } + panning = false; + + if (options.edge === 'left') { + // If velocityX <= 0.3 then the user is flinging the menu closed so ignore menuOut + if ((menuOut && velocityX <= 0.3) || velocityX < -0.5) { + // Return menu to open + if (leftPos !== 0) { + menu_id.velocity({'translateX': [0, leftPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: 0, left: ''}); + menuOut = true; + } + else if (!menuOut || velocityX > 0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + // Slide menu closed + menu_id.velocity({'translateX': [-1 * options.menuWidth - 10, leftPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: '', left: 0}); + } + } + else { + if ((menuOut && velocityX >= -0.3) || velocityX > 0.5) { + // Return menu to open + if (rightPos !== 0) { + menu_id.velocity({'translateX': [0, rightPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: '', left: 0}); + menuOut = true; + } + else if (!menuOut || velocityX < -0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + + // Slide menu closed + menu_id.velocity({'translateX': [options.menuWidth + 10, rightPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: 0, left: ''}); + } + } + + } + }); + } + + $this.click(function() { + if (menuOut === true) { + menuOut = false; + panning = false; + removeMenu(); + } + else { + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('
        '); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // Push current drag target on top of DOM tree + $('body').append($dragTarget); + + if (options.edge === 'left') { + $dragTarget.css({width: '50%', right: 0, left: ''}); + menu_id.velocity({'translateX': [0, -1 * options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else { + $dragTarget.css({width: '50%', right: '', left: 0}); + menu_id.velocity({'translateX': [0, options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.css('opacity', 0) + .click(function(){ + menuOut = false; + panning = false; + removeMenu(); + $overlay.velocity({opacity: 0}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + + }); + $('body').append($overlay); + $overlay.velocity({opacity: 1}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function () { + menuOut = true; + panning = false; + } + }); + } + + return false; + }); + }); + + + }, + destroy: function () { + var $overlay = $('#sidenav-overlay'); + var $dragTarget = $('.drag-target[data-sidenav="' + $(this).attr('data-activates') + '"]'); + $overlay.trigger('click'); + $dragTarget.remove(); + $(this).off('click'); + $overlay.remove(); + }, + show : function() { + this.trigger('click'); + }, + hide : function() { + $('#sidenav-overlay').trigger('click'); + } + }; + + + $.fn.sideNav = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.sideNav' ); + } + }; // Plugin end +}( jQuery )); +;/** + * Extend jquery with a scrollspy plugin. + * This watches the window scroll and fires events when elements are scrolled into viewport. + * + * throttle() and getTime() taken from Underscore.js + * https://github.com/jashkenas/underscore + * + * @author Copyright 2013 John Smart + * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE + * @see https://github.com/thesmart + * @version 0.1.2 + */ +(function($) { + + var jWindow = $(window); + var elements = []; + var elementsInView = []; + var isSpying = false; + var ticks = 0; + var unique_id = 1; + var offset = { + top : 0, + right : 0, + bottom : 0, + left : 0, + } + + /** + * Find elements that are within the boundary + * @param {number} top + * @param {number} right + * @param {number} bottom + * @param {number} left + * @return {jQuery} A collection of elements + */ + function findElements(top, right, bottom, left) { + var hits = $(); + $.each(elements, function(i, element) { + if (element.height() > 0) { + var elTop = element.offset().top, + elLeft = element.offset().left, + elRight = elLeft + element.width(), + elBottom = elTop + element.height(); + + var isIntersect = !(elLeft > right || + elRight < left || + elTop > bottom || + elBottom < top); + + if (isIntersect) { + hits.push(element); + } + } + }); + + return hits; + } + + + /** + * Called when the user scrolls the window + */ + function onScroll(scrollOffset) { + // unique tick id + ++ticks; + + // viewport rectangle + var top = jWindow.scrollTop(), + left = jWindow.scrollLeft(), + right = left + jWindow.width(), + bottom = top + jWindow.height(); + + // determine which elements are in view + var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left); + $.each(intersections, function(i, element) { + + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick != 'number') { + // entered into view + element.triggerHandler('scrollSpy:enter'); + } + + // update tick id + element.data('scrollSpy:ticks', ticks); + }); + + // determine which elements are no longer in view + $.each(elementsInView, function(i, element) { + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick == 'number' && lastTick !== ticks) { + // exited from view + element.triggerHandler('scrollSpy:exit'); + element.data('scrollSpy:ticks', null); + } + }); + + // remember elements in view for next tick + elementsInView = intersections; + } + + /** + * Called when window is resized + */ + function onWinSize() { + jWindow.trigger('scrollSpy:winSize'); + } + + /** + * Get time in ms + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @type {function} + * @return {number} + */ + var getTime = (Date.now || function () { + return new Date().getTime(); + }); + + /** + * Returns a function, that, when invoked, will only be triggered at most once + * during a given window of time. Normally, the throttled function will run + * as much as it can, without ever going more than once per `wait` duration; + * but if you'd like to disable the execution on the leading edge, pass + * `{leading: false}`. To disable execution on the trailing edge, ditto. + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @param {function} func + * @param {number} wait + * @param {Object=} options + * @returns {Function} + */ + function throttle(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + options || (options = {}); + var later = function () { + previous = options.leading === false ? 0 : getTime(); + timeout = null; + result = func.apply(context, args); + context = args = null; + }; + return function () { + var now = getTime(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + /** + * Enables ScrollSpy using a selector + * @param {jQuery|string} selector The elements collection, or a selector + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.scrollSpy = function(selector, options) { + var defaults = { + throttle: 100, + scrollOffset: 200 // offset - 200 allows elements near bottom of page to scroll + }; + options = $.extend(defaults, options); + + var visible = []; + selector = $(selector); + selector.each(function(i, element) { + elements.push($(element)); + $(element).data("scrollSpy:id", i); + // Smooth scroll to section + $('a[href="#' + $(element).attr('id') + '"]').click(function(e) { + e.preventDefault(); + var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1; + $('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'}); + }); + }); + + offset.top = options.offsetTop || 0; + offset.right = options.offsetRight || 0; + offset.bottom = options.offsetBottom || 0; + offset.left = options.offsetLeft || 0; + + var throttledScroll = throttle(function() { + onScroll(options.scrollOffset); + }, options.throttle || 100); + var readyScroll = function(){ + $(document).ready(throttledScroll); + }; + + if (!isSpying) { + jWindow.on('scroll', readyScroll); + jWindow.on('resize', readyScroll); + isSpying = true; + } + + // perform a scan once, after current execution context, and after dom is ready + setTimeout(readyScroll, 0); + + + selector.on('scrollSpy:enter', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + var $this = $(this); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) { + visible.unshift($(this)); + } + else { + visible.push($(this)); + } + } + else { + visible.push($(this)); + } + + + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + }); + selector.on('scrollSpy:exit', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + var $this = $(this); + visible = $.grep(visible, function(value) { + return value.attr('id') != $this.attr('id'); + }); + if (visible[0]) { // Check if empty + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + } + } + }); + + return selector; + }; + + /** + * Listen for window resize events + * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms + * @returns {jQuery} $(window) + */ + $.winSizeSpy = function(options) { + $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls + options = options || { + throttle: 100 + }; + return jWindow.on('resize', throttle(onWinSize, options.throttle || 100)); + }; + + /** + * Enables ScrollSpy on a collection of elements + * e.g. $('.scrollSpy').scrollSpy() + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.fn.scrollSpy = function(options) { + return $.scrollSpy($(this), options); + }; + +})(jQuery); +;(function ($) { + $(document).ready(function() { + + // Function to update labels of text fields + Materialize.updateTextFields = function() { + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + $(input_selector).each(function(index, element) { + if ($(element).val().length > 0 || element.autofocus ||$(this).attr('placeholder') !== undefined || $(element)[0].validity.badInput === true) { + $(this).siblings('label').addClass('active'); + } + else { + $(this).siblings('label').removeClass('active'); + } + }); + }; + + // Text based inputs + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + + // Add active if form auto complete + $(document).on('change', input_selector, function () { + if($(this).val().length !== 0 || $(this).attr('placeholder') !== undefined) { + $(this).siblings('label').addClass('active'); + } + validate_field($(this)); + }); + + // Add active if input element has been pre-populated on document ready + $(document).ready(function() { + Materialize.updateTextFields(); + }); + + // HTML DOM FORM RESET handling + $(document).on('reset', function(e) { + var formReset = $(e.target); + if (formReset.is('form')) { + formReset.find(input_selector).removeClass('valid').removeClass('invalid'); + formReset.find(input_selector).each(function () { + if ($(this).attr('value') === '') { + $(this).siblings('label').removeClass('active'); + } + }); + + // Reset select + formReset.find('select.initialized').each(function () { + var reset_text = formReset.find('option[selected]').text(); + formReset.siblings('input.select-dropdown').val(reset_text); + }); + } + }); + + // Add active when element has focus + $(document).on('focus', input_selector, function () { + $(this).siblings('label, .prefix').addClass('active'); + }); + + $(document).on('blur', input_selector, function () { + var $inputElement = $(this); + var selector = ".prefix"; + + if ($inputElement.val().length === 0 && $inputElement[0].validity.badInput !== true && $inputElement.attr('placeholder') === undefined) { + selector += ", label"; + } + + $inputElement.siblings(selector).removeClass('active'); + + validate_field($inputElement); + }); + + window.validate_field = function(object) { + var hasLength = object.attr('length') !== undefined; + var lenAttr = parseInt(object.attr('length')); + var len = object.val().length; + + if (object.val().length === 0 && object[0].validity.badInput === false) { + if (object.hasClass('validate')) { + object.removeClass('valid'); + object.removeClass('invalid'); + } + } + else { + if (object.hasClass('validate')) { + // Check for character counter attributes + if ((object.is(':valid') && hasLength && (len <= lenAttr)) || (object.is(':valid') && !hasLength)) { + object.removeClass('invalid'); + object.addClass('valid'); + } + else { + object.removeClass('valid'); + object.addClass('invalid'); + } + } + } + }; + + // Radio and Checkbox focus class + var radio_checkbox = 'input[type=radio], input[type=checkbox]'; + $(document).on('keyup.radio', radio_checkbox, function(e) { + // TAB, check if tabbing to radio or checkbox. + if (e.which === 9) { + $(this).addClass('tabbed'); + var $this = $(this); + $this.one('blur', function(e) { + + $(this).removeClass('tabbed'); + }); + return; + } + }); + + // Textarea Auto Resize + var hiddenDiv = $('.hiddendiv').first(); + if (!hiddenDiv.length) { + hiddenDiv = $('
        '); + $('body').append(hiddenDiv); + } + var text_area_selector = '.materialize-textarea'; + + function textareaAutoResize($textarea) { + // Set font properties of hiddenDiv + + var fontFamily = $textarea.css('font-family'); + var fontSize = $textarea.css('font-size'); + var lineHeight = $textarea.css('line-height'); + + if (fontSize) { hiddenDiv.css('font-size', fontSize); } + if (fontFamily) { hiddenDiv.css('font-family', fontFamily); } + if (lineHeight) { hiddenDiv.css('line-height', lineHeight); } + + if ($textarea.attr('wrap') === "off") { + hiddenDiv.css('overflow-wrap', "normal") + .css('white-space', "pre"); + } + + hiddenDiv.text($textarea.val() + '\n'); + var content = hiddenDiv.html().replace(/\n/g, '
        '); + hiddenDiv.html(content); + + + // When textarea is hidden, width goes crazy. + // Approximate with half of window size + + if ($textarea.is(':visible')) { + hiddenDiv.css('width', $textarea.width()); + } + else { + hiddenDiv.css('width', $(window).width()/2); + } + + $textarea.css('height', hiddenDiv.height()); + } + + $(text_area_selector).each(function () { + var $textarea = $(this); + if ($textarea.val().length) { + textareaAutoResize($textarea); + } + }); + + $('body').on('keyup keydown autoresize', text_area_selector, function () { + textareaAutoResize($(this)); + }); + + // File Input Path + $(document).on('change', '.file-field input[type="file"]', function () { + var file_field = $(this).closest('.file-field'); + var path_input = file_field.find('input.file-path'); + var files = $(this)[0].files; + var file_names = []; + for (var i = 0; i < files.length; i++) { + file_names.push(files[i].name); + } + path_input.val(file_names.join(", ")); + path_input.trigger('change'); + }); + + /**************** + * Range Input * + ****************/ + + var range_type = 'input[type=range]'; + var range_mousedown = false; + var left; + + $(range_type).each(function () { + var thumb = $(''); + $(this).after(thumb); + }); + + var range_wrapper = '.range-field'; + $(document).on('change', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + thumb.find('.value').html($(this).val()); + }); + + $(document).on('input mousedown touchstart', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + var width = $(this).outerWidth(); + + // If thumb indicator does not exist yet, create it + if (thumb.length <= 0) { + thumb = $(''); + $(this).after(thumb); + } + + // Set indicator value + thumb.find('.value').html($(this).val()); + + range_mousedown = true; + $(this).addClass('active'); + + if (!thumb.hasClass('active')) { + thumb.velocity({ height: "30px", width: "30px", top: "-20px", marginLeft: "-15px"}, { duration: 300, easing: 'easeOutExpo' }); + } + + if (e.type !== 'input') { + if(e.pageX === undefined || e.pageX === null){//mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + } + + thumb.find('.value').html($(this).val()); + }); + + $(document).on('mouseup touchend', range_wrapper, function() { + range_mousedown = false; + $(this).removeClass('active'); + }); + + $(document).on('mousemove touchmove', range_wrapper, function(e) { + var thumb = $(this).children('.thumb'); + var left; + if (range_mousedown) { + if (!thumb.hasClass('active')) { + thumb.velocity({ height: '30px', width: '30px', top: '-20px', marginLeft: '-15px'}, { duration: 300, easing: 'easeOutExpo' }); + } + if (e.pageX === undefined || e.pageX === null) { //mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + var width = $(this).outerWidth(); + + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + thumb.find('.value').html(thumb.siblings(range_type).val()); + } + }); + + $(document).on('mouseout touchleave', range_wrapper, function() { + if (!range_mousedown) { + + var thumb = $(this).children('.thumb'); + + if (thumb.hasClass('active')) { + thumb.velocity({ height: '0', width: '0', top: '10px', marginLeft: '-6px'}, { duration: 100 }); + } + thumb.removeClass('active'); + } + }); + + /************************** + * Auto complete plugin * + *************************/ + $.fn.autocomplete = function (options) { + // Defaults + var defaults = { + data: {} + }; + + options = $.extend(defaults, options); + + return this.each(function() { + var $input = $(this); + var data = options.data, + $inputDiv = $input.closest('.input-field'); // Div to append on + + // Check if data isn't empty + if (!$.isEmptyObject(data)) { + // Create autocomplete element + var $autocomplete = $(''); + + // Append autocomplete element + if ($inputDiv.length) { + $inputDiv.append($autocomplete); // Set ul in body + } else { + $input.after($autocomplete); + } + + var highlight = function(string, $el) { + var img = $el.find('img'); + var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""), + matchEnd = matchStart + string.length - 1, + beforeMatch = $el.text().slice(0, matchStart), + matchText = $el.text().slice(matchStart, matchEnd + 1), + afterMatch = $el.text().slice(matchEnd + 1); + $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + ""); + if (img.length) { + $el.prepend(img); + } + }; + + // Perform search + $input.on('keyup', function (e) { + // Capture Enter + if (e.which === 13) { + $autocomplete.find('li').first().click(); + return; + } + + var val = $input.val().toLowerCase(); + $autocomplete.empty(); + + // Check if the input isn't empty + if (val !== '') { + for(var key in data) { + if (data.hasOwnProperty(key) && + key.toLowerCase().indexOf(val) !== -1 && + key.toLowerCase() !== val) { + var autocompleteOption = $('
      • '); + if(!!data[key]) { + autocompleteOption.append(''+ key +''); + } else { + autocompleteOption.append(''+ key +''); + } + $autocomplete.append(autocompleteOption); + + highlight(val, autocompleteOption); + } + } + } + }); + + // Set input value + $autocomplete.on('click', 'li', function () { + $input.val($(this).text().trim()); + $input.trigger('change'); + $autocomplete.empty(); + }); + } + }); + }; + + }); // End of $(document).ready + + /******************* + * Select Plugin * + ******************/ + $.fn.material_select = function (callback) { + $(this).each(function(){ + var $select = $(this); + + if ($select.hasClass('browser-default')) { + return; // Continue to next (return false breaks out of entire loop) + } + + var multiple = $select.attr('multiple') ? true : false, + lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt + + if (lastID) { + $select.parent().find('span.caret').remove(); + $select.parent().find('input').remove(); + + $select.unwrap(); + $('ul#select-options-'+lastID).remove(); + } + + // If destroying the select, remove the selelct-id and reset it to it's uninitialized state. + if(callback === 'destroy') { + $select.data('select-id', null).removeClass('initialized'); + return; + } + + var uniqueID = Materialize.guid(); + $select.data('select-id', uniqueID); + var wrapper = $('
        '); + wrapper.addClass($select.attr('class')); + var options = $(''), + selectChildren = $select.children('option, optgroup'), + valuesSelected = [], + optionsHover = false; + + var label = $select.find('option:selected').html() || $select.find('option:first').html() || ""; + + // Function that renders and appends the option taking into + // account type and possible image icon. + var appendOptionWithIcon = function(select, option, type) { + // Add disabled attr if disabled + var disabledClass = (option.is(':disabled')) ? 'disabled ' : ''; + var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : ''; + + // add icons + var icon_url = option.data('icon'); + var classes = option.attr('class'); + if (!!icon_url) { + var classString = ''; + if (!!classes) classString = ' class="' + classes + '"'; + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
      • ' + option.html() + '
      • ')); + } else { + options.append($('
      • ' + option.html() + '
      • ')); + } + return true; + } + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
      • ' + option.html() + '
      • ')); + } else { + options.append($('
      • ' + option.html() + '
      • ')); + } + }; + + /* Create dropdown structure. */ + if (selectChildren.length) { + selectChildren.each(function() { + if ($(this).is('option')) { + // Direct descendant option. + if (multiple) { + appendOptionWithIcon($select, $(this), 'multiple'); + + } else { + appendOptionWithIcon($select, $(this)); + } + } else if ($(this).is('optgroup')) { + // Optgroup. + var selectOptions = $(this).children('option'); + options.append($('
      • ' + $(this).attr('label') + '
      • ')); + + selectOptions.each(function() { + appendOptionWithIcon($select, $(this), 'optgroup-option'); + }); + } + }); + } + + options.find('li:not(.optgroup)').each(function (i) { + $(this).click(function (e) { + // Check if option element is disabled + if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) { + var selected = true; + + if (multiple) { + $('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; }); + selected = toggleEntryFromArray(valuesSelected, $(this).index(), $select); + $newSelect.trigger('focus'); + } else { + options.find('li').removeClass('active'); + $(this).toggleClass('active'); + $newSelect.val($(this).text()); + } + + activateOption(options, $(this)); + $select.find('option').eq(i).prop('selected', selected); + // Trigger onchange() event + $select.trigger('change'); + if (typeof callback !== 'undefined') callback(); + } + + e.stopPropagation(); + }); + }); + + // Wrap Elements + $select.wrap(wrapper); + // Add Select Display Element + var dropdownIcon = $(''); + if ($select.is(':disabled')) + dropdownIcon.addClass('disabled'); + + // escape double quotes + var sanitizedLabelHtml = label.replace(/"/g, '"'); + + var $newSelect = $(''); + $select.before($newSelect); + $newSelect.before(dropdownIcon); + + $newSelect.after(options); + // Check if section element is disabled + if (!$select.is(':disabled')) { + $newSelect.dropdown({'hover': false, 'closeOnClick': false}); + } + + // Copy tabindex + if ($select.attr('tabindex')) { + $($newSelect[0]).attr('tabindex', $select.attr('tabindex')); + } + + $select.addClass('initialized'); + + $newSelect.on({ + 'focus': function (){ + if ($('ul.select-dropdown').not(options[0]).is(':visible')) { + $('input.select-dropdown').trigger('close'); + } + if (!options.is(':visible')) { + $(this).trigger('open', ['focus']); + var label = $(this).val(); + var selectedOption = options.find('li').filter(function() { + return $(this).text().toLowerCase() === label.toLowerCase(); + })[0]; + activateOption(options, selectedOption); + } + }, + 'click': function (e){ + e.stopPropagation(); + } + }); + + $newSelect.on('blur', function() { + if (!multiple) { + $(this).trigger('close'); + } + options.find('li.selected').removeClass('selected'); + }); + + options.hover(function() { + optionsHover = true; + }, function () { + optionsHover = false; + }); + + $(window).on({ + 'click': function () { + multiple && (optionsHover || $newSelect.trigger('close')); + } + }); + + // Add initial multiple selections. + if (multiple) { + $select.find("option:selected:not(:disabled)").each(function () { + var index = $(this).index(); + + toggleEntryFromArray(valuesSelected, index, $select); + options.find("li").eq(index).find(":checkbox").prop("checked", true); + }); + } + + // Make option as selected and scroll to selected position + var activateOption = function(collection, newOption) { + if (newOption) { + collection.find('li.selected').removeClass('selected'); + var option = $(newOption); + option.addClass('selected'); + options.scrollTo(option); + } + }; + + // Allow user to search by typing + // this array is cleared after 1 second + var filterQuery = [], + onKeyDown = function(e){ + // TAB - switch to another input + if(e.which == 9){ + $newSelect.trigger('close'); + return; + } + + // ARROW DOWN WHEN SELECT IS CLOSED - open select options + if(e.which == 40 && !options.is(':visible')){ + $newSelect.trigger('open'); + return; + } + + // ENTER WHEN SELECT IS CLOSED - submit form + if(e.which == 13 && !options.is(':visible')){ + return; + } + + e.preventDefault(); + + // CASE WHEN USER TYPE LETTERS + var letter = String.fromCharCode(e.which).toLowerCase(), + nonLetters = [9,13,27,38,40]; + if (letter && (nonLetters.indexOf(e.which) === -1)) { + filterQuery.push(letter); + + var string = filterQuery.join(''), + newOption = options.find('li').filter(function() { + return $(this).text().toLowerCase().indexOf(string) === 0; + })[0]; + + if (newOption) { + activateOption(options, newOption); + } + } + + // ENTER - select option and close when select options are opened + if (e.which == 13) { + var activeOption = options.find('li.selected:not(.disabled)')[0]; + if(activeOption){ + $(activeOption).trigger('click'); + if (!multiple) { + $newSelect.trigger('close'); + } + } + } + + // ARROW DOWN - move to next not disabled option + if (e.which == 40) { + if (options.find('li.selected').length) { + newOption = options.find('li.selected').next('li:not(.disabled)')[0]; + } else { + newOption = options.find('li:not(.disabled)')[0]; + } + activateOption(options, newOption); + } + + // ESC - close options + if (e.which == 27) { + $newSelect.trigger('close'); + } + + // ARROW UP - move to previous not disabled option + if (e.which == 38) { + newOption = options.find('li.selected').prev('li:not(.disabled)')[0]; + if(newOption) + activateOption(options, newOption); + } + + // Automaticaly clean filter query so user can search again by starting letters + setTimeout(function(){ filterQuery = []; }, 1000); + }; + + $newSelect.on('keydown', onKeyDown); + }); + + function toggleEntryFromArray(entriesArray, entryIndex, select) { + var index = entriesArray.indexOf(entryIndex), + notAdded = index === -1; + + if (notAdded) { + entriesArray.push(entryIndex); + } else { + entriesArray.splice(index, 1); + } + + select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active'); + + // use notAdded instead of true (to detect if the option is selected or not) + select.find('option').eq(entryIndex).prop('selected', notAdded); + setValueToInput(entriesArray, select); + + return notAdded; + } + + function setValueToInput(entriesArray, select) { + var value = ''; + + for (var i = 0, count = entriesArray.length; i < count; i++) { + var text = select.find('option').eq(entriesArray[i]).text(); + + i === 0 ? value += text : value += ', ' + text; + } + + if (value === '') { + value = select.find('option:disabled').eq(0).text(); + } + + select.siblings('input.select-dropdown').val(value); + } + }; + +}( jQuery )); +;(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + indicators: true, + height: 400, + transition: 500, + interval: 6000 + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each slider, we want to keep track of + // which slide is active and its associated content + var $this = $(this); + var $slider = $this.find('ul.slides').first(); + var $slides = $slider.find('> li'); + var $active_index = $slider.find('.active').index(); + var $active, $indicators, $interval; + if ($active_index != -1) { $active = $slides.eq($active_index); } + + // Transitions the caption depending on alignment + function captionTransition(caption, duration) { + if (caption.hasClass("center-align")) { + caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("right-align")) { + caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("left-align")) { + caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false}); + } + } + + // This function will transition the slide to any index of the next slide + function moveToSlide(index) { + // Wrap around indices. + if (index >= $slides.length) index = 0; + else if (index < 0) index = $slides.length -1; + + $active_index = $slider.find('.active').index(); + + // Only do if index changes + if ($active_index != index) { + $active = $slides.eq($active_index); + $caption = $active.find('.caption'); + + $active.removeClass('active'); + $active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad', + complete: function() { + $slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false}); + } }); + captionTransition($caption, options.transition); + + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).removeClass('active'); + } + + $slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).addClass('active'); + + + // Update indicators + if (options.indicators) { + $indicators.eq(index).addClass('active'); + } + } + } + + // Set height of slider + // If fullscreen, do nothing + if (!$this.hasClass('fullscreen')) { + if (options.indicators) { + // Add height if indicators are present + $this.height(options.height + 40); + } + else { + $this.height(options.height); + } + $slider.height(options.height); + } + + + // Set initial positions of captions + $slides.find('.caption').each(function () { + captionTransition($(this), 0); + }); + + // Move img src into background-image + $slides.find('img').each(function () { + var placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; + if ($(this).attr('src') !== placeholderBase64) { + $(this).css('background-image', 'url(' + $(this).attr('src') + ')' ); + $(this).attr('src', placeholderBase64); + } + }); + + // dynamically add indicators + if (options.indicators) { + $indicators = $('
          '); + $slides.each(function( index ) { + var $indicator = $('
        • '); + + // Handle clicks on indicators + $indicator.click(function () { + var $parent = $slider.parent(); + var curr_index = $parent.find($(this)).index(); + moveToSlide(curr_index); + + // reset interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + $indicators.append($indicator); + }); + $this.append($indicators); + $indicators = $this.find('ul.indicators').find('li.indicator-item'); + } + + if ($active) { + $active.show(); + } + else { + $slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + + $active_index = 0; + $active = $slides.eq($active_index); + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).addClass('active'); + } + } + + // Adjust height to current slide + $active.find('img').each(function() { + $active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + }); + + // auto scroll + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + + }, options.transition + options.interval + ); + + + // HammerJS, Swipe navigation + + // Touch Event + var panning = false; + var swipeLeft = false; + var swipeRight = false; + + $this.hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + + // reset interval + clearInterval($interval); + + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $curr_slide = $slider.find('.active'); + $curr_slide.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) { + swipeRight = true; + } + // Swipe Right + else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) { + swipeLeft = true; + } + + // Make Slide Behind active slide visible + var next_slide; + if (swipeLeft) { + next_slide = $curr_slide.next(); + if (next_slide.length === 0) { + next_slide = $slides.first(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + if (swipeRight) { + next_slide = $curr_slide.prev(); + if (next_slide.length === 0) { + next_slide = $slides.last(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + + } + + }).bind('panend', function(e) { + if (e.gesture.pointerType === "touch") { + + $curr_slide = $slider.find('.active'); + panning = false; + curr_index = $slider.find('.active').index(); + + if (!swipeRight && !swipeLeft || $slides.length <=1) { + // Return to original spot + $curr_slide.velocity({ translateX: 0 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else if (swipeLeft) { + moveToSlide(curr_index + 1); + $curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + else if (swipeRight) { + moveToSlide(curr_index - 1); + $curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + swipeLeft = false; + swipeRight = false; + + // Restart interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + } + }); + + $this.on('sliderPause', function() { + clearInterval($interval); + }); + + $this.on('sliderStart', function() { + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + + $this.on('sliderNext', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + }); + + $this.on('sliderPrev', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index - 1); + }); + + }); + + + + }, + pause : function() { + $(this).trigger('sliderPause'); + }, + start : function() { + $(this).trigger('sliderStart'); + }, + next : function() { + $(this).trigger('sliderNext'); + }, + prev : function() { + $(this).trigger('sliderPrev'); + } + }; + + + $.fn.slider = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' ); + } + }; // Plugin end +}( jQuery )); +;(function ($) { + $(document).ready(function() { + + $(document).on('click.card', '.card', function (e) { + if ($(this).find('> .card-reveal').length) { + if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) { + // Make Reveal animate down and display none + $(this).find('.card-reveal').velocity( + {translateY: 0}, { + duration: 225, + queue: false, + easing: 'easeInOutQuad', + complete: function() { $(this).css({ display: 'none'}); } + } + ); + } + else if ($(e.target).is($('.card .activator')) || + $(e.target).is($('.card .activator i')) ) { + $(e.target).closest('.card').css('overflow', 'hidden'); + $(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'}); + } + } + }); + + }); +}( jQuery ));;(function ($) { + var chipsHandleEvents = false; + var materialChipsDefaults = { + data: [], + placeholder: '', + secondaryPlaceholder: '', + }; + + $(document).ready(function() { + // Handle removal of static chips. + $(document).on('click', '.chip .close', function(e){ + var $chips = $(this).closest('.chips'); + if ($chips.attr('data-initialized')) { + return; + } + $(this).closest('.chip').remove(); + }); + }); + + $.fn.material_chip = function (options) { + var self = this; + this.$el = $(this); + this.$document = $(document); + this.SELS = { + CHIPS: '.chips', + CHIP: '.chip', + INPUT: 'input', + DELETE: '.material-icons', + SELECTED_CHIP: '.selected', + }; + + if ('data' === options) { + return this.$el.data('chips'); + } + + var curr_options = $.extend({}, materialChipsDefaults, options); + + + // Initialize + this.init = function() { + var i = 0; + var chips; + self.$el.each(function(){ + var $chips = $(this); + var chipId = Materialize.guid(); + + if (!curr_options.data || !(curr_options.data instanceof Array)) { + curr_options.data = []; + } + $chips.data('chips', curr_options.data); + $chips.attr('data-index', i); + $chips.attr('data-initialized', true); + + if (!$chips.hasClass(self.SELS.CHIPS)) { + $chips.addClass('chips'); + } + + self.chips($chips, chipId); + i++; + }); + }; + + this.handleEvents = function(){ + var SELS = self.SELS; + + self.$document.off('click.chips-focus', SELS.CHIPS).on('click.chips-focus', SELS.CHIPS, function(e){ + $(e.target).find(SELS.INPUT).focus(); + }); + + self.$document.off('click.chips-select', SELS.CHIP).on('click.chips-select', SELS.CHIP, function(e){ + $(SELS.CHIP).removeClass('selected'); + $(this).toggleClass('selected'); + }); + + self.$document.off('keydown.chips').on('keydown.chips', function(e){ + if ($(e.target).is('input, textarea')) { + return; + } + + // delete + var $chip = self.$document.find(SELS.CHIP + SELS.SELECTED_CHIP); + var $chips = $chip.closest(SELS.CHIPS); + var length = $chip.siblings(SELS.CHIP).length; + var index; + + if (!$chip.length) { + return; + } + + if (e.which === 8 || e.which === 46) { + e.preventDefault(); + + index = $chip.index(); + self.deleteChip(index, $chips); + + var selectIndex = null; + if ((index + 1) < length) { + selectIndex = index; + } else if (index === length || (index + 1) === length) { + selectIndex = length - 1; + } + + if (selectIndex < 0) selectIndex = null; + + if (null !== selectIndex) { + self.selectChip(selectIndex, $chips); + } + if (!length) $chips.find('input').focus(); + + // left + } else if (e.which === 37) { + index = $chip.index() - 1; + if (index < 0) { + return; + } + $(SELS.CHIP).removeClass('selected'); + self.selectChip(index, $chips); + + // right + } else if (e.which === 39) { + index = $chip.index() + 1; + $(SELS.CHIP).removeClass('selected'); + if (index > length) { + $chips.find('input').focus(); + return; + } + self.selectChip(index, $chips); + } + }); + + self.$document.off('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.addClass('focus'); + $currChips.siblings('label, .prefix').addClass('active'); + $(SELS.CHIP).removeClass('selected'); + }); + + self.$document.off('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.removeClass('focus'); + + // Remove active if empty + if (!$currChips.data('chips').length) { + $currChips.siblings('label').removeClass('active'); + } + $currChips.siblings('.prefix').removeClass('active'); + }); + + self.$document.off('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT).on('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var chipsLength = $chips.children(SELS.CHIP).length; + + // enter + if (13 === e.which) { + e.preventDefault(); + self.addChip({tag: $target.val()}, $chips); + $target.val(''); + return; + } + + // delete or left + if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) { + self.selectChip(chipsLength - 1, $chips); + $target.blur(); + return; + } + }); + + // Click on delete icon in chip. + self.$document.off('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE).on('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE, function(e) { + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var $chip = $target.closest(SELS.CHIP); + e.stopPropagation(); + self.deleteChip($chip.index(), $chips); + $chips.find('input').focus(); + }); + }; + + this.chips = function($chips, chipId) { + var html = ''; + $chips.data('chips').forEach(function(elem){ + html += self.renderChip(elem); + }); + html += ''; + $chips.html(html); + self.setPlaceholder($chips); + + // Set for attribute for label + var label = $chips.next('label'); + if (label.length) { + label.attr('for', chipId); + + if ($chips.data('chips').length) { + label.addClass('active'); + } + } + }; + + this.renderChip = function(elem) { + if (!elem.tag) return; + + var html = '
          ' + elem.tag; + if (elem.image) { + html += ' '; + } + html += 'close'; + html += '
          '; + return html; + }; + + this.setPlaceholder = function($chips) { + if ($chips.data('chips').length && curr_options.placeholder) { + $chips.find('input').prop('placeholder', curr_options.placeholder); + + } else if (!$chips.data('chips').length && curr_options.secondaryPlaceholder) { + $chips.find('input').prop('placeholder', curr_options.secondaryPlaceholder); + } + }; + + this.isValid = function($chips, elem) { + var chips = $chips.data('chips'); + var exists = false; + for (var i=0; i < chips.length; i++) { + if (chips[i].tag === elem.tag) { + exists = true; + return; + } + } + return '' !== elem.tag && !exists; + }; + + this.addChip = function(elem, $chips) { + if (!self.isValid($chips, elem)) { + return; + } + var chipHtml = self.renderChip(elem); + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + newData.push(oldData[i]); + } + newData.push(elem); + + $chips.data('chips', newData); + $(chipHtml).insertBefore($chips.find('input')); + $chips.trigger('chip.add', elem); + self.setPlaceholder($chips); + }; + + this.deleteChip = function(chipIndex, $chips) { + var chip = $chips.data('chips')[chipIndex]; + $chips.find('.chip').eq(chipIndex).remove(); + + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + if (i !== chipIndex) { + newData.push(oldData[i]); + } + } + + $chips.data('chips', newData); + $chips.trigger('chip.delete', chip); + self.setPlaceholder($chips); + }; + + this.selectChip = function(chipIndex, $chips) { + var $chip = $chips.find('.chip').eq(chipIndex); + if ($chip && false === $chip.hasClass('selected')) { + $chip.addClass('selected'); + $chips.trigger('chip.select', $chips.data('chips')[chipIndex]); + } + }; + + this.getChipsElement = function(index, $chips) { + return $chips.eq(index); + }; + + // init + this.init(); + + if (!chipsHandleEvents) { + this.handleEvents(); + chipsHandleEvents = true; + } + }; +}( jQuery ));;(function ($) { + $.fn.pushpin = function (options) { + // Defaults + var defaults = { + top: 0, + bottom: Infinity, + offset: 0 + }; + + // Remove pushpin event and classes + if (options === "remove") { + this.each(function () { + if (id = $(this).data('pushpin-id')) { + $(window).off('scroll.' + id); + $(this).removeData('pushpin-id').removeClass('pin-top pinned pin-bottom').removeAttr('style'); + } + }); + return false; + } + + options = $.extend(defaults, options); + + + $index = 0; + return this.each(function() { + var $uniqueId = Materialize.guid(), + $this = $(this), + $original_offset = $(this).offset().top; + + function removePinClasses(object) { + object.removeClass('pin-top'); + object.removeClass('pinned'); + object.removeClass('pin-bottom'); + } + + function updateElements(objects, scrolled) { + objects.each(function () { + // Add position fixed (because its between top and bottom) + if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) { + removePinClasses($(this)); + $(this).css('top', options.offset); + $(this).addClass('pinned'); + } + + // Add pin-top (when scrolled position is above top) + if (scrolled < options.top && !$(this).hasClass('pin-top')) { + removePinClasses($(this)); + $(this).css('top', 0); + $(this).addClass('pin-top'); + } + + // Add pin-bottom (when scrolled position is below bottom) + if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) { + removePinClasses($(this)); + $(this).addClass('pin-bottom'); + $(this).css('top', options.bottom - $original_offset); + } + }); + } + + $(this).data('pushpin-id', $uniqueId); + updateElements($this, $(window).scrollTop()); + $(window).on('scroll.' + $uniqueId, function () { + var $scrolled = $(window).scrollTop() + options.offset; + updateElements($this, $scrolled); + }); + + }); + + }; +}( jQuery ));;(function ($) { + $(document).ready(function() { + + // jQuery reverse + $.fn.reverse = [].reverse; + + // Hover behaviour: make sure this doesn't work on .click-to-toggle FABs! + $(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + openFABMenu($this); + }); + $(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + closeFABMenu($this); + }); + + // Toggle-on-click behaviour. + $(document).on('click.fabClickToggle', '.fixed-action-btn.click-to-toggle > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + if ($menu.hasClass('active')) { + closeFABMenu($menu); + } else { + openFABMenu($menu); + } + }); + + // Toolbar transition behaviour. + $(document).on('click.fabToolbar', '.fixed-action-btn.toolbar > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + FABtoToolbar($menu); + }); + + }); + + $.fn.extend({ + openFAB: function() { + openFABMenu($(this)); + }, + closeFAB: function() { + closeFABMenu($(this)); + }, + openToolbar: function() { + FABtoToolbar($(this)); + }, + closeToolbar: function() { + toolbarToFAB($(this)); + } + }); + + + var openFABMenu = function (btn) { + var $this = btn; + if ($this.hasClass('active') === false) { + + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.addClass('active'); + $this.find('ul .btn-floating').velocity( + { scaleY: ".4", scaleX: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 0 }); + + var time = 0; + $this.find('ul .btn-floating').reverse().each( function () { + $(this).velocity( + { opacity: "1", scaleX: "1", scaleY: "1", translateY: "0", translateX: '0'}, + { duration: 80, delay: time }); + time += 40; + }); + } + }; + + var closeFABMenu = function (btn) { + var $this = btn; + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.removeClass('active'); + var time = 0; + $this.find('ul .btn-floating').velocity("stop", true); + $this.find('ul .btn-floating').velocity( + { opacity: "0", scaleX: ".4", scaleY: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 80 } + ); + }; + + + /** + * Transform FAB into toolbar + * @param {Object} object jQuery object + */ + var FABtoToolbar = function(btn) { + if (btn.attr('data-open') === "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnRect = btn[0].getBoundingClientRect(); + var anchor = btn.find('> a').first(); + var menu = btn.find('> ul').first(); + var backdrop = $('
          '); + var fabColor = anchor.css('background-color'); + anchor.append(backdrop); + + offsetX = btnRect.left - (windowWidth / 2) + (btnRect.width / 2); + offsetY = windowHeight - btnRect.bottom; + scaleFactor = windowWidth / backdrop.width(); + btn.attr('data-origin-bottom', btnRect.bottom); + btn.attr('data-origin-left', btnRect.left); + btn.attr('data-origin-width', btnRect.width); + + // Set initial state + btn.addClass('active'); + btn.attr('data-open', true); + btn.css({ + 'text-align': 'center', + width: '100%', + bottom: 0, + left: 0, + transform: 'translateX(' + offsetX + 'px)', + transition: 'none' + }); + anchor.css({ + transform: 'translateY(' + -offsetY + 'px)', + transition: 'none' + }); + backdrop.css({ + 'background-color': fabColor + }); + + + setTimeout(function() { + btn.css({ + transform: '', + transition: 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s' + }); + anchor.css({ + overflow: 'visible', + transform: '', + transition: 'transform .2s' + }); + + setTimeout(function() { + btn.css({ + overflow: 'hidden', + 'background-color': fabColor + }); + backdrop.css({ + transform: 'scale(' + scaleFactor + ')', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + menu.find('> li > a').css({ + opacity: 1 + }); + + // Scroll to close. + $(window).on('scroll.fabToolbarClose', function() { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + }); + + $(document).on('click.fabToolbarClose', function(e) { + if (!$(e.target).closest(menu).length) { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + } + }); + }, 100); + }, 0); + }; + + /** + * Transform toolbar back into FAB + * @param {Object} object jQuery object + */ + var toolbarToFAB = function(btn) { + if (btn.attr('data-open') !== "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnWidth = btn.attr('data-origin-width'); + var btnBottom = btn.attr('data-origin-bottom'); + var btnLeft = btn.attr('data-origin-left'); + var anchor = btn.find('> .btn-floating').first(); + var menu = btn.find('> ul').first(); + var backdrop = btn.find('.fab-backdrop'); + var fabColor = anchor.css('background-color'); + + offsetX = btnLeft - (windowWidth / 2) + (btnWidth / 2); + offsetY = windowHeight - btnBottom; + scaleFactor = windowWidth / backdrop.width(); + + + // Hide backdrop + btn.removeClass('active'); + btn.attr('data-open', false); + btn.css({ + 'background-color': 'transparent', + transition: 'none' + }); + anchor.css({ + transition: 'none' + }); + backdrop.css({ + transform: 'scale(0)', + 'background-color': fabColor + }); + menu.find('> li > a').css({ + opacity: '' + }); + + setTimeout(function() { + backdrop.remove(); + + // Set initial state. + btn.css({ + 'text-align': '', + width: '', + bottom: '', + left: '', + overflow: '', + 'background-color': '', + transform: 'translate3d(' + -offsetX + 'px,0,0)' + }); + anchor.css({ + overflow: '', + transform: 'translate3d(0,' + offsetY + 'px,0)' + }); + + setTimeout(function() { + btn.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s' + }); + anchor.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + }, 20); + }, 200); + }; + + +}( jQuery )); +;(function ($) { + // Image transition function + Materialize.fadeInImage = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + element.css({opacity: 0}); + $(element).velocity({opacity: 1}, { + duration: 650, + queue: false, + easing: 'easeOutSine' + }); + $(element).velocity({opacity: 1}, { + duration: 1300, + queue: false, + easing: 'swing', + step: function(now, fx) { + fx.start = 100; + var grayscale_setting = now/100; + var brightness_setting = 150 - (100 - now)/1.75; + + if (brightness_setting < 100) { + brightness_setting = 100; + } + if (now >= 0) { + $(this).css({ + "-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)", + "filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)" + }); + } + } + }); + }; + + // Horizontal staggered list + Materialize.showStaggeredList = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + var time = 0; + element.find('li').velocity( + { translateX: "-100px"}, + { duration: 0 }); + + element.find('li').each(function() { + $(this).velocity( + { opacity: "1", translateX: "0"}, + { duration: 800, delay: time, easing: [60, 10] }); + time += 120; + }); + }; + + + $(document).ready(function() { + // Hardcoded .staggered-list scrollFire + // var staggeredListOptions = []; + // $('ul.staggered-list').each(function (i) { + + // var label = 'scrollFire-' + i; + // $(this).addClass(label); + // staggeredListOptions.push( + // {selector: 'ul.staggered-list.' + label, + // offset: 200, + // callback: 'showStaggeredList("ul.staggered-list.' + label + '")'}); + // }); + // scrollFire(staggeredListOptions); + + // HammerJS, Swipe navigation + + // Touch Event + var swipeLeft = false; + var swipeRight = false; + + + // Dismissible Collections + $('.dismissable').each(function() { + $(this).hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + var $this = $(this); + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $this.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) { + swipeLeft = true; + } + + // Swipe Right + if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) { + swipeRight = true; + } + } + }).bind('panend', function(e) { + // Reset if collection is moved back into original position + if (Math.abs(e.gesture.deltaX) < ($(this).innerWidth() / 2)) { + swipeRight = false; + swipeLeft = false; + } + + if (e.gesture.pointerType === "touch") { + var $this = $(this); + if (swipeLeft || swipeRight) { + var fullWidth; + if (swipeLeft) { fullWidth = $this.innerWidth(); } + else { fullWidth = -1 * $this.innerWidth(); } + + $this.velocity({ translateX: fullWidth, + }, {duration: 100, queue: false, easing: 'easeOutQuad', complete: + function() { + $this.css('border', 'none'); + $this.velocity({ height: 0, padding: 0, + }, {duration: 200, queue: false, easing: 'easeOutQuad', complete: + function() { $this.remove(); } + }); + } + }); + } + else { + $this.velocity({ translateX: 0, + }, {duration: 100, queue: false, easing: 'easeOutQuad'}); + } + swipeLeft = false; + swipeRight = false; + } + }); + + }); + + + // time = 0 + // // Vertical Staggered list + // $('ul.staggered-list.vertical li').velocity( + // { translateY: "100px"}, + // { duration: 0 }); + + // $('ul.staggered-list.vertical li').each(function() { + // $(this).velocity( + // { opacity: "1", translateY: "0"}, + // { duration: 800, delay: time, easing: [60, 25] }); + // time += 120; + // }); + + // // Fade in and Scale + // $('.fade-in.scale').velocity( + // { scaleX: .4, scaleY: .4, translateX: -600}, + // { duration: 0}); + // $('.fade-in').each(function() { + // $(this).velocity( + // { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0}, + // { duration: 800, easing: [60, 10] }); + // }); + }); +}( jQuery )); +;(function($) { + + // Input: Array of JSON objects {selector, offset, callback} + + Materialize.scrollFire = function(options) { + + var didScroll = false; + + window.addEventListener("scroll", function() { + didScroll = true; + }); + + // Rate limit to 100ms + setInterval(function() { + if(didScroll) { + didScroll = false; + + var windowScroll = window.pageYOffset + window.innerHeight; + + for (var i = 0 ; i < options.length; i++) { + // Get options from each line + var value = options[i]; + var selector = value.selector, + offset = value.offset, + callback = value.callback; + + var currentElement = document.querySelector(selector); + if ( currentElement !== null) { + var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset; + + if (windowScroll > (elementOffset + offset)) { + if (value.done !== true) { + if (typeof(callback) === 'function') { + callback.call(this, currentElement); + } else if (typeof(callback) === 'string') { + var callbackFunc = new Function(callback); + callbackFunc(currentElement); + } + value.done = true; + } + } + } + } + } + }, 100); + }; + +})(jQuery); +;/*! + * pickadate.js v3.5.0, 2014/04/13 + * By Amsul, http://amsul.ca + * Hosted on http://amsul.github.io/pickadate.js + * Licensed under MIT + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( 'picker', ['jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('jquery') ) + + // Browser globals. + else this.Picker = factory( jQuery ) + +}(function( $ ) { + +var $window = $( window ) +var $document = $( document ) +var $html = $( document.documentElement ) + + +/** + * The picker constructor that creates a blank picker. + */ +function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { + + // If there’s no element, return the picker constructor. + if ( !ELEMENT ) return PickerConstructor + + + var + IS_DEFAULT_THEME = false, + + + // The state of the picker. + STATE = { + id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) + }, + + + // Merge the defaults and options passed. + SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {}, + + + // Merge the default classes with the settings classes. + CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ), + + + // The element node wrapper into a jQuery object. + $ELEMENT = $( ELEMENT ), + + + // Pseudo picker constructor. + PickerInstance = function() { + return this.start() + }, + + + // The picker prototype. + P = PickerInstance.prototype = { + + constructor: PickerInstance, + + $node: $ELEMENT, + + + /** + * Initialize everything + */ + start: function() { + + // If it’s already started, do nothing. + if ( STATE && STATE.start ) return P + + + // Update the picker states. + STATE.methods = {} + STATE.start = true + STATE.open = false + STATE.type = ELEMENT.type + + + // Confirm focus state, convert into text input to remove UA stylings, + // and set as readonly to prevent keyboard popup. + ELEMENT.autofocus = ELEMENT == getActiveElement() + ELEMENT.readOnly = !SETTINGS.editable + ELEMENT.id = ELEMENT.id || STATE.id + if ( ELEMENT.type != 'text' ) { + ELEMENT.type = 'text' + } + + + // Create a new picker component with the settings. + P.component = new COMPONENT(P, SETTINGS) + + + // Create the picker root with a holder and then prepare it. + P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"') ) + prepareElementRoot() + + + // If there’s a format for the hidden input element, create the element. + if ( SETTINGS.formatSubmit ) { + prepareElementHidden() + } + + + // Prepare the input element. + prepareElement() + + + // Insert the root as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) + else $ELEMENT.after( P.$root ) + + + // Bind the default component and settings events. + P.on({ + start: P.component.onStart, + render: P.component.onRender, + stop: P.component.onStop, + open: P.component.onOpen, + close: P.component.onClose, + set: P.component.onSet + }).on({ + start: SETTINGS.onStart, + render: SETTINGS.onRender, + stop: SETTINGS.onStop, + open: SETTINGS.onOpen, + close: SETTINGS.onClose, + set: SETTINGS.onSet + }) + + + // Once we’re all set, check the theme in use. + IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] ) + + + // If the element has autofocus, open the picker. + if ( ELEMENT.autofocus ) { + P.open() + } + + + // Trigger queued the “start” and “render” events. + return P.trigger( 'start' ).trigger( 'render' ) + }, //start + + + /** + * Render a new picker + */ + render: function( entireComponent ) { + + // Insert a new component holder in the root or box. + if ( entireComponent ) P.$root.html( createWrappedComponent() ) + else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) + + // Trigger the queued “render” events. + return P.trigger( 'render' ) + }, //render + + + /** + * Destroy everything + */ + stop: function() { + + // If it’s already stopped, do nothing. + if ( !STATE.start ) return P + + // Then close the picker. + P.close() + + // Remove the hidden field. + if ( P._hidden ) { + P._hidden.parentNode.removeChild( P._hidden ) + } + + // Remove the root. + P.$root.remove() + + // Remove the input class, remove the stored data, and unbind + // the events (after a tick for IE - see `P.close`). + $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) + setTimeout( function() { + $ELEMENT.off( '.' + STATE.id ) + }, 0) + + // Restore the element state + ELEMENT.type = STATE.type + ELEMENT.readOnly = false + + // Trigger the queued “stop” events. + P.trigger( 'stop' ) + + // Reset the picker states. + STATE.methods = {} + STATE.start = false + + return P + }, //stop + + + /** + * Open up the picker + */ + open: function( dontGiveFocus ) { + + // If it’s already open, do nothing. + if ( STATE.open ) return P + + // Add the “active” class. + $ELEMENT.addClass( CLASSES.active ) + aria( ELEMENT, 'expanded', true ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So add the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Add the “opened” class to the picker root. + P.$root.addClass( CLASSES.opened ) + aria( P.$root[0], 'hidden', false ) + + }, 0 ) + + // If we have to give focus, bind the element and doc events. + if ( dontGiveFocus !== false ) { + + // Set it as open. + STATE.open = true + + // Prevent the page from scrolling. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', 'hidden' ). + css( 'padding-right', '+=' + getScrollbarWidth() ) + } + + // Pass focus to the root element’s jQuery object. + // * Workaround for iOS8 to bring the picker’s root into view. + P.$root.eq(0).focus() + + // Bind the document events. + $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { + + var target = event.target + + // If the target of the event is not the element, close the picker picker. + // * Don’t worry about clicks or focusins on the root because those don’t bubble up. + // Also, for Firefox, a click on an `option` element bubbles up directly + // to the doc. So make sure the target wasn't the doc. + // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling, + // which causes the picker to unexpectedly close when right-clicking it. So make + // sure the event wasn’t a right-click. + if ( target != ELEMENT && target != document && event.which != 3 ) { + + // If the target was the holder that covers the screen, + // keep the element focused to maintain tabindex. + P.close( target === P.$root.children()[0] ) + } + + }).on( 'keydown.' + STATE.id, function( event ) { + + var + // Get the keycode. + keycode = event.keyCode, + + // Translate that to a selection change. + keycodeToMove = P.component.key[ keycode ], + + // Grab the target. + target = event.target + + + // On escape, close the picker and give focus. + if ( keycode == 27 ) { + P.close( true ) + } + + + // Check if there is a key movement or “enter” keypress on the element. + else if ( target == P.$root[0] && ( keycodeToMove || keycode == 13 ) ) { + + // Prevent the default action to stop page movement. + event.preventDefault() + + // Trigger the key movement action. + if ( keycodeToMove ) { + PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] ) + } + + // On “enter”, if the highlighted item isn’t disabled, set the value and close. + else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) { + P.set( 'select', P.component.item.highlight ).close() + } + } + + + // If the target is within the root and “enter” is pressed, + // prevent the default action and trigger a click on the target instead. + else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { + event.preventDefault() + target.click() + } + }) + } + + // Trigger the queued “open” events. + return P.trigger( 'open' ) + }, //open + + + /** + * Close the picker + */ + close: function( giveFocus ) { + + // If we need to give focus, do it before changing states. + if ( giveFocus ) { + // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :| + // The focus is triggered *after* the close has completed - causing it + // to open again. So unbind and rebind the event at the next tick. + P.$root.off( 'focus.toOpen' ).eq(0).focus() + setTimeout( function() { + P.$root.on( 'focus.toOpen', handleFocusToOpenEvent ) + }, 0 ) + } + + // Remove the “active” class. + $ELEMENT.removeClass( CLASSES.active ) + aria( ELEMENT, 'expanded', false ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So remove the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Remove the “opened” and “focused” class from the picker root. + P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) + aria( P.$root[0], 'hidden', true ) + + }, 0 ) + + // If it’s already closed, do nothing more. + if ( !STATE.open ) return P + + // Set it as closed. + STATE.open = false + + // Allow the page to scroll. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', '' ). + css( 'padding-right', '-=' + getScrollbarWidth() ) + } + + // Unbind the document events. + $document.off( '.' + STATE.id ) + + // Trigger the queued “close” events. + return P.trigger( 'close' ) + }, //close + + + /** + * Clear the values + */ + clear: function( options ) { + return P.set( 'clear', null, options ) + }, //clear + + + /** + * Set something + */ + set: function( thing, value, options ) { + + var thingItem, thingValue, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + // Make sure we have usable options. + options = thingIsObject && $.isPlainObject( value ) ? value : options || {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = value + } + + // Go through the things of items to set. + for ( thingItem in thingObject ) { + + // Grab the value of the thing. + thingValue = thingObject[ thingItem ] + + // First, if the item exists and there’s a value, set it. + if ( thingItem in P.component.item ) { + if ( thingValue === undefined ) thingValue = null + P.component.set( thingItem, thingValue, options ) + } + + // Then, check to update the element value and broadcast a change. + if ( thingItem == 'select' || thingItem == 'clear' ) { + $ELEMENT. + val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ). + trigger( 'change' ) + } + } + + // Render a new picker. + P.render() + } + + // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`. + return options.muted ? P : P.trigger( 'set', thingObject ) + }, //set + + + /** + * Get something + */ + get: function( thing, format ) { + + // Make sure there’s something to get. + thing = thing || 'value' + + // If a picker state exists, return that. + if ( STATE[ thing ] != null ) { + return STATE[ thing ] + } + + // Return the submission value, if that. + if ( thing == 'valueSubmit' ) { + if ( P._hidden ) { + return P._hidden.value + } + thing = 'value' + } + + // Return the value, if that. + if ( thing == 'value' ) { + return ELEMENT.value + } + + // Check if a component item exists, return that. + if ( thing in P.component.item ) { + if ( typeof format == 'string' ) { + var thingValue = P.component.get( thing ) + return thingValue ? + PickerConstructor._.trigger( + P.component.formats.toString, + P.component, + [ format, thingValue ] + ) : '' + } + return P.component.get( thing ) + } + }, //get + + + + /** + * Bind events on the things. + */ + on: function( thing, method, internal ) { + + var thingName, thingMethod, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = method + } + + // Go through the things to bind to. + for ( thingName in thingObject ) { + + // Grab the method of the thing. + thingMethod = thingObject[ thingName ] + + // If it was an internal binding, prefix it. + if ( internal ) { + thingName = '_' + thingName + } + + // Make sure the thing methods collection exists. + STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] + + // Add the method to the relative method collection. + STATE.methods[ thingName ].push( thingMethod ) + } + } + + return P + }, //on + + + + /** + * Unbind events on the things. + */ + off: function() { + var i, thingName, + names = arguments; + for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { + thingName = names[i] + if ( thingName in STATE.methods ) { + delete STATE.methods[thingName] + } + } + return P + }, + + + /** + * Fire off method events. + */ + trigger: function( name, data ) { + var _trigger = function( name ) { + var methodList = STATE.methods[ name ] + if ( methodList ) { + methodList.map( function( method ) { + PickerConstructor._.trigger( method, P, [ data ] ) + }) + } + } + _trigger( '_' + name ) + _trigger( name ) + return P + } //trigger + } //PickerInstance.prototype + + + /** + * Wrap the picker holder components together. + */ + function createWrappedComponent() { + + // Create a picker wrapper holder + return PickerConstructor._.node( 'div', + + // Create a picker wrapper node + PickerConstructor._.node( 'div', + + // Create a picker frame + PickerConstructor._.node( 'div', + + // Create a picker box node + PickerConstructor._.node( 'div', + + // Create the components nodes. + P.component.nodes( STATE.open ), + + // The picker box class + CLASSES.box + ), + + // Picker wrap class + CLASSES.wrap + ), + + // Picker frame class + CLASSES.frame + ), + + // Picker holder class + CLASSES.holder + ) //endreturn + } //createWrappedComponent + + + + /** + * Prepare the input element with all bindings. + */ + function prepareElement() { + + $ELEMENT. + + // Store the picker data by component name. + data(NAME, P). + + // Add the “input” class name. + addClass(CLASSES.input). + + // Remove the tabindex. + attr('tabindex', -1). + + // If there’s a `data-value`, update the value of the element. + val( $ELEMENT.data('value') ? + P.get('select', SETTINGS.format) : + ELEMENT.value + ) + + + // Only bind keydown events if the element isn’t editable. + if ( !SETTINGS.editable ) { + + $ELEMENT. + + // On focus/click, focus onto the root to open it up. + on( 'focus.' + STATE.id + ' click.' + STATE.id, function( event ) { + event.preventDefault() + P.$root.eq(0).focus() + }). + + // Handle keyboard event based on the picker being opened or not. + on( 'keydown.' + STATE.id, handleKeydownEvent ) + } + + + // Update the aria attributes. + aria(ELEMENT, { + haspopup: true, + expanded: false, + readonly: false, + owns: ELEMENT.id + '_root' + }) + } + + + /** + * Prepare the root picker element with all bindings. + */ + function prepareElementRoot() { + + P.$root. + + on({ + + // For iOS8. + keydown: handleKeydownEvent, + + // When something within the root is focused, stop from bubbling + // to the doc and remove the “focused” state from the root. + focusin: function( event ) { + P.$root.removeClass( CLASSES.focused ) + event.stopPropagation() + }, + + // When something within the root holder is clicked, stop it + // from bubbling to the doc. + 'mousedown click': function( event ) { + + var target = event.target + + // Make sure the target isn’t the root holder so it can bubble up. + if ( target != P.$root.children()[ 0 ] ) { + + event.stopPropagation() + + // * For mousedown events, cancel the default action in order to + // prevent cases where focus is shifted onto external elements + // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). + // Also, for Firefox, don’t prevent action on the `option` element. + if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) { + + event.preventDefault() + + // Re-focus onto the root so that users can click away + // from elements focused within the picker. + P.$root.eq(0).focus() + } + } + } + }). + + // Add/remove the “target” class on focus and blur. + on({ + focus: function() { + $ELEMENT.addClass( CLASSES.target ) + }, + blur: function() { + $ELEMENT.removeClass( CLASSES.target ) + } + }). + + // Open the picker and adjust the root “focused” state + on( 'focus.toOpen', handleFocusToOpenEvent ). + + // If there’s a click on an actionable element, carry out the actions. + on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() { + + var $target = $( this ), + targetData = $target.data(), + targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ), + + // * For IE, non-focusable elements can be active elements as well + // (http://stackoverflow.com/a/2684561). + activeElement = getActiveElement() + activeElement = activeElement && ( activeElement.type || activeElement.href ) + + // If it’s disabled or nothing inside is actively focused, re-focus the element. + if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { + P.$root.eq(0).focus() + } + + // If something is superficially changed, update the `highlight` based on the `nav`. + if ( !targetDisabled && targetData.nav ) { + P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } ) + } + + // If something is picked, set `select` then close with focus. + else if ( !targetDisabled && 'pick' in targetData ) { + P.set( 'select', targetData.pick ) + } + + // If a “clear” button is pressed, empty the values and close with focus. + else if ( targetData.clear ) { + P.clear().close( true ) + } + + else if ( targetData.close ) { + P.close( true ) + } + + }) //P.$root + + aria( P.$root[0], 'hidden', true ) + } + + + /** + * Prepare the hidden input element along with all bindings. + */ + function prepareElementHidden() { + + var name + + if ( SETTINGS.hiddenName === true ) { + name = ELEMENT.name + ELEMENT.name = '' + } + else { + name = [ + typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', + typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' + ] + name = name[0] + ELEMENT.name + name[1] + } + + P._hidden = $( + '' + )[0] + + $ELEMENT. + + // If the value changes, update the hidden input with the correct format. + on('change.' + STATE.id, function() { + P._hidden.value = ELEMENT.value ? + P.get('select', SETTINGS.formatSubmit) : + '' + }) + + + // Insert the hidden input as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P._hidden ) + else $ELEMENT.after( P._hidden ) + } + + + // For iOS8. + function handleKeydownEvent( event ) { + + var keycode = event.keyCode, + + // Check if one of the delete keys was pressed. + isKeycodeDelete = /^(8|46)$/.test(keycode) + + // For some reason IE clears the input value on “escape”. + if ( keycode == 27 ) { + P.close() + return false + } + + // Check if `space` or `delete` was pressed or the picker is closed with a key movement. + if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { + + // Prevent it from moving the page and bubbling to doc. + event.preventDefault() + event.stopPropagation() + + // If `delete` was pressed, clear the values and close the picker. + // Otherwise open the picker. + if ( isKeycodeDelete ) { P.clear().close() } + else { P.open() } + } + } + + + // Separated for IE + function handleFocusToOpenEvent( event ) { + + // Stop the event from propagating to the doc. + event.stopPropagation() + + // If it’s a focus event, add the “focused” class to the root. + if ( event.type == 'focus' ) { + P.$root.addClass( CLASSES.focused ) + } + + // And then finally open the picker. + P.open() + } + + + // Return a new picker instance. + return new PickerInstance() +} //PickerConstructor + + + +/** + * The default classes and prefix to use for the HTML classes. + */ +PickerConstructor.klasses = function( prefix ) { + prefix = prefix || 'picker' + return { + + picker: prefix, + opened: prefix + '--opened', + focused: prefix + '--focused', + + input: prefix + '__input', + active: prefix + '__input--active', + target: prefix + '__input--target', + + holder: prefix + '__holder', + + frame: prefix + '__frame', + wrap: prefix + '__wrap', + + box: prefix + '__box' + } +} //PickerConstructor.klasses + + + +/** + * Check if the default theme is being used. + */ +function isUsingDefaultTheme( element ) { + + var theme, + prop = 'position' + + // For IE. + if ( element.currentStyle ) { + theme = element.currentStyle[prop] + } + + // For normal browsers. + else if ( window.getComputedStyle ) { + theme = getComputedStyle( element )[prop] + } + + return theme == 'fixed' +} + + + +/** + * Get the width of the browser’s scrollbar. + * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js + */ +function getScrollbarWidth() { + + if ( $html.height() <= $window.height() ) { + return 0 + } + + var $outer = $( '
          ' ). + appendTo( 'body' ) + + // Get the width without scrollbars. + var widthWithoutScroll = $outer[0].offsetWidth + + // Force adding scrollbars. + $outer.css( 'overflow', 'scroll' ) + + // Add the inner div. + var $inner = $( '
          ' ).appendTo( $outer ) + + // Get the width with scrollbars. + var widthWithScroll = $inner[0].offsetWidth + + // Remove the divs. + $outer.remove() + + // Return the difference between the widths. + return widthWithoutScroll - widthWithScroll +} + + + +/** + * PickerConstructor helper methods. + */ +PickerConstructor._ = { + + /** + * Create a group of nodes. Expects: + * ` + { + min: {Integer}, + max: {Integer}, + i: {Integer}, + node: {String}, + item: {Function} + } + * ` + */ + group: function( groupObject ) { + + var + // Scope for the looped object + loopObjectScope, + + // Create the nodes list + nodesList = '', + + // The counter starts from the `min` + counter = PickerConstructor._.trigger( groupObject.min, groupObject ) + + + // Loop from the `min` to `max`, incrementing by `i` + for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { + + // Trigger the `item` function within scope of the object + loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) + + // Splice the subgroup and create nodes out of the sub nodes + nodesList += PickerConstructor._.node( + groupObject.node, + loopObjectScope[ 0 ], // the node + loopObjectScope[ 1 ], // the classes + loopObjectScope[ 2 ] // the attributes + ) + } + + // Return the list of nodes + return nodesList + }, //group + + + /** + * Create a dom node string + */ + node: function( wrapper, item, klass, attribute ) { + + // If the item is false-y, just return an empty string + if ( !item ) return '' + + // If the item is an array, do a join + item = $.isArray( item ) ? item.join( '' ) : item + + // Check for the class + klass = klass ? ' class="' + klass + '"' : '' + + // Check for any attributes + attribute = attribute ? ' ' + attribute : '' + + // Return the wrapped item + return '<' + wrapper + klass + attribute + '>' + item + '' + }, //node + + + /** + * Lead numbers below 10 with a zero. + */ + lead: function( number ) { + return ( number < 10 ? '0': '' ) + number + }, + + + /** + * Trigger a function otherwise return the value. + */ + trigger: function( callback, scope, args ) { + return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback + }, + + + /** + * If the second character is a digit, length is 2 otherwise 1. + */ + digits: function( string ) { + return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 + }, + + + /** + * Tell if something is a date object. + */ + isDate: function( value ) { + return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) + }, + + + /** + * Tell if something is an integer. + */ + isInteger: function( value ) { + return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 + }, + + + /** + * Create ARIA attribute strings. + */ + ariaAttr: ariaAttr +} //PickerConstructor._ + + + +/** + * Extend the picker with a component and defaults. + */ +PickerConstructor.extend = function( name, Component ) { + + // Extend jQuery. + $.fn[ name ] = function( options, action ) { + + // Grab the component data. + var componentData = this.data( name ) + + // If the picker is requested, return the data object. + if ( options == 'picker' ) { + return componentData + } + + // If the component data exists and `options` is a string, carry out the action. + if ( componentData && typeof options == 'string' ) { + return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) + } + + // Otherwise go through each matched element and if the component + // doesn’t exist, create a new picker using `this` element + // and merging the defaults and options with a deep copy. + return this.each( function() { + var $this = $( this ) + if ( !$this.data( name ) ) { + new PickerConstructor( this, name, Component, options ) + } + }) + } + + // Set the defaults. + $.fn[ name ].defaults = Component.defaults +} //PickerConstructor.extend + + + +function aria(element, attribute, value) { + if ( $.isPlainObject(attribute) ) { + for ( var key in attribute ) { + ariaSet(element, key, attribute[key]) + } + } + else { + ariaSet(element, attribute, value) + } +} +function ariaSet(element, attribute, value) { + element.setAttribute( + (attribute == 'role' ? '' : 'aria-') + attribute, + value + ) +} +function ariaAttr(attribute, data) { + if ( !$.isPlainObject(attribute) ) { + attribute = { attribute: data } + } + data = '' + for ( var key in attribute ) { + var attr = (key == 'role' ? '' : 'aria-') + key, + attrVal = attribute[key] + data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' + } + return data +} + +// IE8 bug throws an error for activeElements within iframes. +function getActiveElement() { + try { + return document.activeElement + } catch ( err ) { } +} + + + +// Expose the picker constructor. +return PickerConstructor + + +})); + + +;/*! + * Date picker for pickadate.js v3.5.0 + * http://amsul.github.io/pickadate.js/date.htm + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( ['picker', 'jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('./picker.js'), require('jquery') ) + + // Browser globals. + else factory( Picker, jQuery ) + +}(function( Picker, $ ) { + + +/** + * Globals and constants + */ +var DAYS_IN_WEEK = 7, + WEEKS_IN_CALENDAR = 6, + _ = Picker._ + + + +/** + * The date picker constructor + */ +function DatePicker( picker, settings ) { + + var calendar = this, + element = picker.$node[ 0 ], + elementValue = element.value, + elementDataValue = picker.$node.data( 'value' ), + valueString = elementDataValue || elementValue, + formatString = elementDataValue ? settings.formatSubmit : settings.format, + isRTL = function() { + + return element.currentStyle ? + + // For IE. + element.currentStyle.direction == 'rtl' : + + // For normal browsers. + getComputedStyle( picker.$root[0] ).direction == 'rtl' + } + + calendar.settings = settings + calendar.$node = picker.$node + + // The queue of methods that will be used to build item objects. + calendar.queue = { + min: 'measure create', + max: 'measure create', + now: 'now create', + select: 'parse create validate', + highlight: 'parse navigate create validate', + view: 'parse create validate viewset', + disable: 'deactivate', + enable: 'activate' + } + + // The component's item object. + calendar.item = {} + + calendar.item.clear = null + calendar.item.disable = ( settings.disable || [] ).slice( 0 ) + calendar.item.enable = -(function( collectionDisabled ) { + return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 + })( calendar.item.disable ) + + calendar. + set( 'min', settings.min ). + set( 'max', settings.max ). + set( 'now' ) + + // When there’s a value, set the `select`, which in turn + // also sets the `highlight` and `view`. + if ( valueString ) { + calendar.set( 'select', valueString, { format: formatString }) + } + + // If there’s no value, default to highlighting “today”. + else { + calendar. + set( 'select', null ). + set( 'highlight', calendar.item.now ) + } + + + // The keycode to movement mapping. + calendar.key = { + 40: 7, // Down + 38: -7, // Up + 39: function() { return isRTL() ? -1 : 1 }, // Right + 37: function() { return isRTL() ? 1 : -1 }, // Left + go: function( timeChange ) { + var highlightedObject = calendar.item.highlight, + targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) + calendar.set( + 'highlight', + targetDate, + { interval: timeChange } + ) + this.render() + } + } + + + // Bind some picker events. + picker. + on( 'render', function() { + picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) + } + }) + picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) + } + }) + }, 1 ). + on( 'open', function() { + var includeToday = '' + if ( calendar.disabled( calendar.get('now') ) ) { + includeToday = ':not(.' + settings.klass.buttonToday + ')' + } + picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false ) + }, 1 ). + on( 'close', function() { + picker.$root.find( 'button, select' ).attr( 'disabled', true ) + }, 1 ) + +} //DatePicker + + +/** + * Set a datepicker item object. + */ +DatePicker.prototype.set = function( type, value, options ) { + + var calendar = this, + calendarItem = calendar.item + + // If the value is `null` just set it immediately. + if ( value === null ) { + if ( type == 'clear' ) type = 'select' + calendarItem[ type ] = value + return calendar + } + + // Otherwise go through the queue of methods, and invoke the functions. + // Update this as the time unit, and set the final value as this item. + // * In the case of `enable`, keep the queue but set `disable` instead. + // And in the case of `flip`, keep the queue but set `enable` instead. + calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { + value = calendar[ method ]( type, value, options ) + return value + }).pop() + + // Check if we need to cascade through more updates. + if ( type == 'select' ) { + calendar.set( 'highlight', calendarItem.select, options ) + } + else if ( type == 'highlight' ) { + calendar.set( 'view', calendarItem.highlight, options ) + } + else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { + if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) { + calendar.set( 'select', calendarItem.select, options ) + } + if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) { + calendar.set( 'highlight', calendarItem.highlight, options ) + } + } + + return calendar +} //DatePicker.prototype.set + + +/** + * Get a datepicker item object. + */ +DatePicker.prototype.get = function( type ) { + return this.item[ type ] +} //DatePicker.prototype.get + + +/** + * Create a picker date object. + */ +DatePicker.prototype.create = function( type, value, options ) { + + var isInfiniteValue, + calendar = this + + // If there’s no value, use the type as the value. + value = value === undefined ? type : value + + + // If it’s infinity, update the value. + if ( value == -Infinity || value == Infinity ) { + isInfiniteValue = value + } + + // If it’s an object, use the native date object. + else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { + value = value.obj + } + + // If it’s an array, convert it into a date and make sure + // that it’s a valid date – otherwise default to today. + else if ( $.isArray( value ) ) { + value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) + value = _.isDate( value ) ? value : calendar.create().obj + } + + // If it’s a number or date object, make a normalized date. + else if ( _.isInteger( value ) || _.isDate( value ) ) { + value = calendar.normalize( new Date( value ), options ) + } + + // If it’s a literal true or any other case, set it to now. + else /*if ( value === true )*/ { + value = calendar.now( type, value, options ) + } + + // Return the compiled object. + return { + year: isInfiniteValue || value.getFullYear(), + month: isInfiniteValue || value.getMonth(), + date: isInfiniteValue || value.getDate(), + day: isInfiniteValue || value.getDay(), + obj: isInfiniteValue || value, + pick: isInfiniteValue || value.getTime() + } +} //DatePicker.prototype.create + + +/** + * Create a range limit object using an array, date object, + * literal “true”, or integer relative to another time. + */ +DatePicker.prototype.createRange = function( from, to ) { + + var calendar = this, + createDate = function( date ) { + if ( date === true || $.isArray( date ) || _.isDate( date ) ) { + return calendar.create( date ) + } + return date + } + + // Create objects if possible. + if ( !_.isInteger( from ) ) { + from = createDate( from ) + } + if ( !_.isInteger( to ) ) { + to = createDate( to ) + } + + // Create relative dates. + if ( _.isInteger( from ) && $.isPlainObject( to ) ) { + from = [ to.year, to.month, to.date + from ]; + } + else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { + to = [ from.year, from.month, from.date + to ]; + } + + return { + from: createDate( from ), + to: createDate( to ) + } +} //DatePicker.prototype.createRange + + +/** + * Check if a date unit falls within a date range object. + */ +DatePicker.prototype.withinRange = function( range, dateUnit ) { + range = this.createRange(range.from, range.to) + return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick +} + + +/** + * Check if two date range objects overlap. + */ +DatePicker.prototype.overlapRanges = function( one, two ) { + + var calendar = this + + // Convert the ranges into comparable dates. + one = calendar.createRange( one.from, one.to ) + two = calendar.createRange( two.from, two.to ) + + return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || + calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) +} + + +/** + * Get the date today. + */ +DatePicker.prototype.now = function( type, value, options ) { + value = new Date() + if ( options && options.rel ) { + value.setDate( value.getDate() + options.rel ) + } + return this.normalize( value, options ) +} + + +/** + * Navigate to next/prev month. + */ +DatePicker.prototype.navigate = function( type, value, options ) { + + var targetDateObject, + targetYear, + targetMonth, + targetDate, + isTargetArray = $.isArray( value ), + isTargetObject = $.isPlainObject( value ), + viewsetObject = this.item.view/*, + safety = 100*/ + + + if ( isTargetArray || isTargetObject ) { + + if ( isTargetObject ) { + targetYear = value.year + targetMonth = value.month + targetDate = value.date + } + else { + targetYear = +value[0] + targetMonth = +value[1] + targetDate = +value[2] + } + + // If we’re navigating months but the view is in a different + // month, navigate to the view’s year and month. + if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { + targetYear = viewsetObject.year + targetMonth = viewsetObject.month + } + + // Figure out the expected target year and month. + targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) + targetYear = targetDateObject.getFullYear() + targetMonth = targetDateObject.getMonth() + + // If the month we’re going to doesn’t have enough days, + // keep decreasing the date until we reach the month’s last date. + while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) { + targetDate -= 1 + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.' + }*/ + } + + value = [ targetYear, targetMonth, targetDate ] + } + + return value +} //DatePicker.prototype.navigate + + +/** + * Normalize a date by setting the hours to midnight. + */ +DatePicker.prototype.normalize = function( value/*, options*/ ) { + value.setHours( 0, 0, 0, 0 ) + return value +} + + +/** + * Measure the range of dates. + */ +DatePicker.prototype.measure = function( type, value/*, options*/ ) { + + var calendar = this + + // If it’s anything false-y, remove the limits. + if ( !value ) { + value = type == 'min' ? -Infinity : Infinity + } + + // If it’s a string, parse it. + else if ( typeof value == 'string' ) { + value = calendar.parse( type, value ) + } + + // If it's an integer, get a date relative to today. + else if ( _.isInteger( value ) ) { + value = calendar.now( type, value, { rel: value } ) + } + + return value +} ///DatePicker.prototype.measure + + +/** + * Create a viewset object based on navigation. + */ +DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { + return this.create([ dateObject.year, dateObject.month, 1 ]) +} + + +/** + * Validate a date as enabled and shift if needed. + */ +DatePicker.prototype.validate = function( type, dateObject, options ) { + + var calendar = this, + + // Keep a reference to the original date. + originalDateObject = dateObject, + + // Make sure we have an interval. + interval = options && options.interval ? options.interval : 1, + + // Check if the calendar enabled dates are inverted. + isFlippedBase = calendar.item.enable === -1, + + // Check if we have any enabled dates after/before now. + hasEnabledBeforeTarget, hasEnabledAfterTarget, + + // The min & max limits. + minLimitObject = calendar.item.min, + maxLimitObject = calendar.item.max, + + // Check if we’ve reached the limit during shifting. + reachedMin, reachedMax, + + // Check if the calendar is inverted and at least one weekday is enabled. + hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) { + + // If there’s a date, check where it is relative to the target. + if ( $.isArray( value ) ) { + var dateTime = calendar.create( value ).pick + if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true + else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true + } + + // Return only integers for enabled weekdays. + return _.isInteger( value ) + }).length/*, + + safety = 100*/ + + + + // Cases to validate for: + // [1] Not inverted and date disabled. + // [2] Inverted and some dates enabled. + // [3] Not inverted and out of range. + // + // Cases to **not** validate for: + // • Navigating months. + // • Not inverted and date enabled. + // • Inverted and all dates disabled. + // • ..and anything else. + if ( !options || !options.nav ) if ( + /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) || + /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) || + /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) ) + ) { + + + // When inverted, flip the direction if there aren’t any enabled weekdays + // and there are no enabled dates in the direction of the interval. + if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) { + interval *= -1 + } + + + // Keep looping until we reach an enabled date. + while ( /*safety &&*/ calendar.disabled( dateObject ) ) { + + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.' + }*/ + + + // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval. + if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { + dateObject = originalDateObject + interval = interval > 0 ? 1 : -1 + } + + + // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. + if ( dateObject.pick <= minLimitObject.pick ) { + reachedMin = true + interval = 1 + dateObject = calendar.create([ + minLimitObject.year, + minLimitObject.month, + minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1) + ]) + } + else if ( dateObject.pick >= maxLimitObject.pick ) { + reachedMax = true + interval = -1 + dateObject = calendar.create([ + maxLimitObject.year, + maxLimitObject.month, + maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1) + ]) + } + + + // If we’ve reached both limits, just break out of the loop. + if ( reachedMin && reachedMax ) { + break + } + + + // Finally, create the shifted date using the interval and keep looping. + dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ]) + } + + } //endif + + + // Return the date object settled on. + return dateObject +} //DatePicker.prototype.validate + + +/** + * Check if a date is disabled. + */ +DatePicker.prototype.disabled = function( dateToVerify ) { + + var + calendar = this, + + // Filter through the disabled dates to check if this is one. + isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) { + + // If the date is a number, match the weekday with 0index and `firstDay` check. + if ( _.isInteger( dateToDisable ) ) { + return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7 + } + + // If it’s an array or a native JS date, create and match the exact date. + if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) { + return dateToVerify.pick === calendar.create( dateToDisable ).pick + } + + // If it’s an object, match a date within the “from” and “to” range. + if ( $.isPlainObject( dateToDisable ) ) { + return calendar.withinRange( dateToDisable, dateToVerify ) + } + }) + + // If this date matches a disabled date, confirm it’s not inverted. + isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { + return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || + $.isPlainObject( dateToDisable ) && dateToDisable.inverted + }).length + + // Check the calendar “enabled” flag and respectively flip the + // disabled state. Then also check if it’s beyond the min/max limits. + return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || + dateToVerify.pick < calendar.item.min.pick || + dateToVerify.pick > calendar.item.max.pick + +} //DatePicker.prototype.disabled + + +/** + * Parse a string into a usable type. + */ +DatePicker.prototype.parse = function( type, value, options ) { + + var calendar = this, + parsingObject = {} + + // If it’s already parsed, we’re good. + if ( !value || typeof value != 'string' ) { + return value + } + + // We need a `.format` to parse the value with. + if ( !( options && options.format ) ) { + options = options || {} + options.format = calendar.settings.format + } + + // Convert the format into an array and then map through it. + calendar.formats.toArray( options.format ).map( function( label ) { + + var + // Grab the formatting label. + formattingLabel = calendar.formats[ label ], + + // The format length is from the formatting label function or the + // label length without the escaping exclamation (!) mark. + formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length + + // If there's a format label, split the value up to the format length. + // Then add it to the parsing object with appropriate label. + if ( formattingLabel ) { + parsingObject[ label ] = value.substr( 0, formatLength ) + } + + // Update the value as the substring from format length to end. + value = value.substr( formatLength ) + }) + + // Compensate for month 0index. + return [ + parsingObject.yyyy || parsingObject.yy, + +( parsingObject.mm || parsingObject.m ) - 1, + parsingObject.dd || parsingObject.d + ] +} //DatePicker.prototype.parse + + +/** + * Various formats to display the object in. + */ +DatePicker.prototype.formats = (function() { + + // Return the length of the first word in a collection. + function getWordLengthFromCollection( string, collection, dateObject ) { + + // Grab the first word from the string. + var word = string.match( /\w+/ )[ 0 ] + + // If there's no month index, add it to the date object + if ( !dateObject.mm && !dateObject.m ) { + dateObject.m = collection.indexOf( word ) + 1 + } + + // Return the length of the word. + return word.length + } + + // Get the length of the first word in a string. + function getFirstWordLength( string ) { + return string.match( /\w+/ )[ 0 ].length + } + + return { + + d: function( string, dateObject ) { + + // If there's string, then get the digits length. + // Otherwise return the selected date. + return string ? _.digits( string ) : dateObject.date + }, + dd: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected date with a leading zero. + return string ? 2 : _.lead( dateObject.date ) + }, + ddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the short selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ] + }, + dddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the full selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ] + }, + m: function( string, dateObject ) { + + // If there's a string, then get the length of the digits + // Otherwise return the selected month with 0index compensation. + return string ? _.digits( string ) : dateObject.month + 1 + }, + mm: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected month with 0index and leading zero. + return string ? 2 : _.lead( dateObject.month + 1 ) + }, + mmm: function( string, dateObject ) { + + var collection = this.settings.monthsShort + + // If there's a string, get length of the relevant month from the short + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + mmmm: function( string, dateObject ) { + + var collection = this.settings.monthsFull + + // If there's a string, get length of the relevant month from the full + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + yy: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected year by slicing out the first 2 digits. + return string ? 2 : ( '' + dateObject.year ).slice( 2 ) + }, + yyyy: function( string, dateObject ) { + + // If there's a string, then the length is always 4. + // Otherwise return the selected year. + return string ? 4 : dateObject.year + }, + + // Create an array by splitting the formatting string passed. + toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) }, + + // Format an object into a string using the formatting options. + toString: function ( formatString, itemObject ) { + var calendar = this + return calendar.formats.toArray( formatString ).map( function( label ) { + return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) + }).join( '' ) + } + } +})() //DatePicker.prototype.formats + + + + +/** + * Check if two date units are the exact. + */ +DatePicker.prototype.isDateExact = function( one, two ) { + + var calendar = this + + // When we’re working with weekdays, do a direct comparison. + if ( + ( _.isInteger( one ) && _.isInteger( two ) ) || + ( typeof one == 'boolean' && typeof two == 'boolean' ) + ) { + return one === two + } + + // When we’re working with date representations, compare the “pick” value. + if ( + ( _.isDate( one ) || $.isArray( one ) ) && + ( _.isDate( two ) || $.isArray( two ) ) + ) { + return calendar.create( one ).pick === calendar.create( two ).pick + } + + // When we’re working with range objects, compare the “from” and “to”. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to ) + } + + return false +} + + +/** + * Check if two date units overlap. + */ +DatePicker.prototype.isDateOverlap = function( one, two ) { + + var calendar = this, + firstDay = calendar.settings.firstDay ? 1 : 0 + + // When we’re working with a weekday index, compare the days. + if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { + one = one % 7 + firstDay + return one === calendar.create( two ).day + 1 + } + if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { + two = two % 7 + firstDay + return two === calendar.create( one ).day + 1 + } + + // When we’re working with range objects, check if the ranges overlap. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.overlapRanges( one, two ) + } + + return false +} + + +/** + * Flip the “enabled” state. + */ +DatePicker.prototype.flipEnable = function(val) { + var itemObject = this.item + itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) +} + + +/** + * Mark a collection of dates as “disabled”. + */ +DatePicker.prototype.deactivate = function( type, datesToDisable ) { + + var calendar = this, + disabledItems = calendar.item.disable.slice(0) + + + // If we’re flipping, that’s all we need to do. + if ( datesToDisable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToDisable === false ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToDisable === true ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the dates to disable. + else { + + datesToDisable.map(function( unitToDisable ) { + + var matchFound + + // When we have disabled items, check for matches. + // If something is matched, immediately break out. + for ( var index = 0; index < disabledItems.length; index += 1 ) { + if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { + matchFound = true + break + } + } + + // If nothing was found, add the validated unit to the collection. + if ( !matchFound ) { + if ( + _.isInteger( unitToDisable ) || + _.isDate( unitToDisable ) || + $.isArray( unitToDisable ) || + ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) + ) { + disabledItems.push( unitToDisable ) + } + } + }) + } + + // Return the updated collection. + return disabledItems +} //DatePicker.prototype.deactivate + + +/** + * Mark a collection of dates as “enabled”. + */ +DatePicker.prototype.activate = function( type, datesToEnable ) { + + var calendar = this, + disabledItems = calendar.item.disable, + disabledItemsCount = disabledItems.length + + // If we’re flipping, that’s all we need to do. + if ( datesToEnable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToEnable === true ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToEnable === false ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the disabled dates. + else { + + datesToEnable.map(function( unitToEnable ) { + + var matchFound, + disabledUnit, + index, + isExactRange + + // Go through the disabled items and try to find a match. + for ( index = 0; index < disabledItemsCount; index += 1 ) { + + disabledUnit = disabledItems[index] + + // When an exact match is found, remove it from the collection. + if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { + matchFound = disabledItems[index] = null + isExactRange = true + break + } + + // When an overlapped match is found, add the “inverted” state to it. + else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { + if ( $.isPlainObject( unitToEnable ) ) { + unitToEnable.inverted = true + matchFound = unitToEnable + } + else if ( $.isArray( unitToEnable ) ) { + matchFound = unitToEnable + if ( !matchFound[3] ) matchFound.push( 'inverted' ) + } + else if ( _.isDate( unitToEnable ) ) { + matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] + } + break + } + } + + // If a match was found, remove a previous duplicate entry. + if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // In the event that we’re dealing with an exact range of dates, + // make sure there are no “inverted” dates because of it. + if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // If something is still matched, add it into the collection. + if ( matchFound ) { + disabledItems.push( matchFound ) + } + }) + } + + // Return the updated collection. + return disabledItems.filter(function( val ) { return val != null }) +} //DatePicker.prototype.activate + + +/** + * Create a string for the nodes in the picker. + */ +DatePicker.prototype.nodes = function( isOpen ) { + + var + calendar = this, + settings = calendar.settings, + calendarItem = calendar.item, + nowObject = calendarItem.now, + selectedObject = calendarItem.select, + highlightedObject = calendarItem.highlight, + viewsetObject = calendarItem.view, + disabledCollection = calendarItem.disable, + minLimitObject = calendarItem.min, + maxLimitObject = calendarItem.max, + + + // Create the calendar table head using a copy of weekday labels collection. + // * We do a copy so we don't mutate the original array. + tableHead = (function( collection, fullCollection ) { + + // If the first day should be Monday, move Sunday to the end. + if ( settings.firstDay ) { + collection.push( collection.shift() ) + fullCollection.push( fullCollection.shift() ) + } + + // Create and return the table head group. + return _.node( + 'thead', + _.node( + 'tr', + _.group({ + min: 0, + max: DAYS_IN_WEEK - 1, + i: 1, + node: 'th', + item: function( counter ) { + return [ + collection[ counter ], + settings.klass.weekdays, + 'scope=col title="' + fullCollection[ counter ] + '"' + ] + } + }) + ) + ) //endreturn + + // Materialize modified + })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysLetter ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead + + + // Create the nav for next/prev month. + createMonthNav = function( next ) { + + // Otherwise, return the created month tag. + return _.node( + 'div', + ' ', + settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + ( + + // If the focused month is outside the range, disabled the button. + ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) || + ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ? + ' ' + settings.klass.navDisabled : '' + ), + 'data-nav=' + ( next || -1 ) + ' ' + + _.ariaAttr({ + role: 'button', + controls: calendar.$node[0].id + '_table' + }) + ' ' + + 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"' + ) //endreturn + }, //createMonthNav + + + // Create the month label. + //Materialize modified + createMonthLabel = function(override) { + + var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull + + // Materialize modified + if (override == "short_months") { + monthsCollection = settings.monthsShort; + } + + // If there are months to select, add a dropdown menu. + if ( settings.selectMonths && override == undefined) { + + return _.node( 'select', + _.group({ + min: 0, + max: 11, + i: 1, + node: 'option', + item: function( loopedMonth ) { + + return [ + + // The looped month and no classes. + monthsCollection[ loopedMonth ], 0, + + // Set the value and selected index. + 'value=' + loopedMonth + + ( viewsetObject.month == loopedMonth ? ' selected' : '' ) + + ( + ( + ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) || + ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month ) + ) ? + ' disabled' : '' + ) + ] + } + }), + settings.klass.selectMonth + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelMonthSelect + '"' + ) + } + + // Materialize modified + if (override == "short_months") + if (selectedObject != null) + return _.node( 'div', monthsCollection[ selectedObject.month ] ); + else return _.node( 'div', monthsCollection[ viewsetObject.month ] ); + + // If there's a need for a month selector + return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month ) + }, //createMonthLabel + + + // Create the year label. + // Materialize modified + createYearLabel = function(override) { + + var focusedYear = viewsetObject.year, + + // If years selector is set to a literal "true", set it to 5. Otherwise + // divide in half to get half before and half after focused year. + numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) + + // If there are years to select, add a dropdown menu. + if ( numberYears ) { + + var + minYear = minLimitObject.year, + maxYear = maxLimitObject.year, + lowestYear = focusedYear - numberYears, + highestYear = focusedYear + numberYears + + // If the min year is greater than the lowest year, increase the highest year + // by the difference and set the lowest year to the min year. + if ( minYear > lowestYear ) { + highestYear += minYear - lowestYear + lowestYear = minYear + } + + // If the max year is less than the highest year, decrease the lowest year + // by the lower of the two: available and needed years. Then set the + // highest year to the max year. + if ( maxYear < highestYear ) { + + var availableYears = lowestYear - minYear, + neededYears = highestYear - maxYear + + lowestYear -= availableYears > neededYears ? neededYears : availableYears + highestYear = maxYear + } + + if ( settings.selectYears && override == undefined ) { + return _.node( 'select', + _.group({ + min: lowestYear, + max: highestYear, + i: 1, + node: 'option', + item: function( loopedYear ) { + return [ + + // The looped year and no classes. + loopedYear, 0, + + // Set the value and selected index. + 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' ) + ] + } + }), + settings.klass.selectYear + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelYearSelect + '"' + ) + } + } + + // Materialize modified + if (override == "raw") + return _.node( 'div', focusedYear ) + + // Otherwise just return the year focused + return _.node( 'div', focusedYear, settings.klass.year ) + } //createYearLabel + + + // Materialize modified + createDayLabel = function() { + if (selectedObject != null) + return _.node( 'div', selectedObject.date) + else return _.node( 'div', nowObject.date) + } + createWeekdayLabel = function() { + var display_day; + + if (selectedObject != null) + display_day = selectedObject.day; + else + display_day = nowObject.day; + var weekday = settings.weekdaysFull[ display_day ] + return weekday + } + + + // Create and return the entire calendar. +return _.node( + // Date presentation View + 'div', + _.node( + 'div', + createWeekdayLabel(), + "picker__weekday-display" + )+ + _.node( + // Div for short Month + 'div', + createMonthLabel("short_months"), + settings.klass.month_display + )+ + _.node( + // Div for Day + 'div', + createDayLabel() , + settings.klass.day_display + )+ + _.node( + // Div for Year + 'div', + createYearLabel("raw") , + settings.klass.year_display + ), + settings.klass.date_display + )+ + // Calendar container + _.node('div', + _.node('div', + ( settings.selectYears ? createMonthLabel() + createYearLabel() : createMonthLabel() + createYearLabel() ) + + createMonthNav() + createMonthNav( 1 ), + settings.klass.header + ) + _.node( + 'table', + tableHead + + _.node( + 'tbody', + _.group({ + min: 0, + max: WEEKS_IN_CALENDAR - 1, + i: 1, + node: 'tr', + item: function( rowCounter ) { + + // If Monday is the first day and the month starts on Sunday, shift the date back a week. + var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 + + return [ + _.group({ + min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index + max: function() { + return this.min + DAYS_IN_WEEK - 1 + }, + i: 1, + node: 'td', + item: function( targetDate ) { + + // Convert the time date from a relative date to a target date. + targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) + + var isSelected = selectedObject && selectedObject.pick == targetDate.pick, + isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, + isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick, + formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] ) + + return [ + _.node( + 'div', + targetDate.date, + (function( klasses ) { + + // Add the `infocus` or `outfocus` classes based on month in view. + klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) + + // Add the `today` class if needed. + if ( nowObject.pick == targetDate.pick ) { + klasses.push( settings.klass.now ) + } + + // Add the `selected` class if something's selected and the time matches. + if ( isSelected ) { + klasses.push( settings.klass.selected ) + } + + // Add the `highlighted` class if something's highlighted and the time matches. + if ( isHighlighted ) { + klasses.push( settings.klass.highlighted ) + } + + // Add the `disabled` class if something's disabled and the object matches. + if ( isDisabled ) { + klasses.push( settings.klass.disabled ) + } + + return klasses.join( ' ' ) + })([ settings.klass.day ]), + 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({ + role: 'gridcell', + label: formattedDate, + selected: isSelected && calendar.$node.val() === formattedDate ? true : null, + activedescendant: isHighlighted ? true : null, + disabled: isDisabled ? true : null + }) + ), + '', + _.ariaAttr({ role: 'presentation' }) + ] //endreturn + } + }) + ] //endreturn + } + }) + ), + settings.klass.table, + 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({ + role: 'grid', + controls: calendar.$node[0].id, + readonly: true + }) + ) + , settings.klass.calendar_container) // end calendar + + + + + // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”. + _.node( + 'div', + _.node( 'button', settings.today, "btn-flat picker__today", + 'type=button data-pick=' + nowObject.pick + + ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node( 'button', settings.clear, "btn-flat picker__clear", + 'type=button data-clear=1' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node('button', settings.close, "btn-flat picker__close", + 'type=button data-close=true ' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ), + settings.klass.footer + ) //endreturn +} //DatePicker.prototype.nodes + + + + +/** + * The date picker defaults. + */ +DatePicker.defaults = (function( prefix ) { + + return { + + // The title label to use for the month nav buttons + labelMonthNext: 'Next month', + labelMonthPrev: 'Previous month', + + // The title label to use for the dropdown selectors + labelMonthSelect: 'Select a month', + labelYearSelect: 'Select a year', + + // Months and weekdays + monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], + monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], + weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], + weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], + + // Materialize modified + weekdaysLetter: [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ], + + // Today and clear + today: 'Today', + clear: 'Clear', + close: 'Close', + + // The format to show on the `input` element + format: 'd mmmm, yyyy', + + // Classes + klass: { + + table: prefix + 'table', + + header: prefix + 'header', + + + // Materialize Added klasses + date_display: prefix + 'date-display', + day_display: prefix + 'day-display', + month_display: prefix + 'month-display', + year_display: prefix + 'year-display', + calendar_container: prefix + 'calendar-container', + // end + + + + navPrev: prefix + 'nav--prev', + navNext: prefix + 'nav--next', + navDisabled: prefix + 'nav--disabled', + + month: prefix + 'month', + year: prefix + 'year', + + selectMonth: prefix + 'select--month', + selectYear: prefix + 'select--year', + + weekdays: prefix + 'weekday', + + day: prefix + 'day', + disabled: prefix + 'day--disabled', + selected: prefix + 'day--selected', + highlighted: prefix + 'day--highlighted', + now: prefix + 'day--today', + infocus: prefix + 'day--infocus', + outfocus: prefix + 'day--outfocus', + + footer: prefix + 'footer', + + buttonClear: prefix + 'button--clear', + buttonToday: prefix + 'button--today', + buttonClose: prefix + 'button--close' + } + } +})( Picker.klasses().picker + '__' ) + + + + + +/** + * Extend the picker to add the date picker. + */ +Picker.extend( 'pickadate', DatePicker ) + + +})); + + +;(function ($) { + + $.fn.characterCounter = function(){ + return this.each(function(){ + var $input = $(this); + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + // character counter has already been added appended to the parent container + if ($counterElement.length) { + return; + } + + var itHasLengthAttribute = $input.attr('length') !== undefined; + + if(itHasLengthAttribute){ + $input.on('input', updateCounter); + $input.on('focus', updateCounter); + $input.on('blur', removeCounterElement); + + addCounterElement($input); + } + + }); + }; + + function updateCounter(){ + var maxLength = +$(this).attr('length'), + actualLength = +$(this).val().length, + isValidLength = actualLength <= maxLength; + + $(this).parent().find('span[class="character-counter"]') + .html( actualLength + '/' + maxLength); + + addInputStyle(isValidLength, $(this)); + } + + function addCounterElement($input) { + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + if ($counterElement.length) { + return; + } + + $counterElement = $('') + .addClass('character-counter') + .css('float','right') + .css('font-size','12px') + .css('height', 1); + + $input.parent().append($counterElement); + } + + function removeCounterElement(){ + $(this).parent().find('span[class="character-counter"]').html(''); + } + + function addInputStyle(isValidLength, $input){ + var inputHasInvalidClass = $input.hasClass('invalid'); + if (isValidLength && inputHasInvalidClass) { + $input.removeClass('invalid'); + } + else if(!isValidLength && !inputHasInvalidClass){ + $input.removeClass('valid'); + $input.addClass('invalid'); + } + } + + $(document).ready(function(){ + $('input, textarea').characterCounter(); + }); + +}( jQuery )); +;(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + time_constant: 200, // ms + dist: -100, // zoom scale TODO: make this more intuitive as an option + shift: 0, // spacing for center image + padding: 0, // Padding between non center items + full_width: false, // Change to full width styles + indicators: false, // Toggle indicators + no_wrap: false // Don't wrap around and cycle through items. + }; + options = $.extend(defaults, options); + + return this.each(function() { + + var images, offset, center, pressed, dim, count, + reference, referenceY, amplitude, target, velocity, + xform, frame, timestamp, ticker, dragged, vertical_dragged; + var $indicators = $('
            '); + + + // Initialize + var view = $(this); + var showIndicators = view.attr('data-indicators') || options.indicators; + + // Don't double initialize. + if (view.hasClass('initialized')) { + // Redraw carousel. + $(this).trigger('carouselNext', [0.000001]); + return true; + } + + + // Options + if (options.full_width) { + options.dist = 0; + var firstImage = view.find('.carousel-item img').first(); + if (firstImage.length) { + imageHeight = firstImage.on('load', function(){ + view.css('height', $(this).height()); + }); + } else { + imageHeight = view.find('.carousel-item').first().height(); + view.css('height', imageHeight); + } + + // Offset fixed items when indicators. + if (showIndicators) { + view.find('.carousel-fixed-item').addClass('with-indicators'); + } + } + + + view.addClass('initialized'); + pressed = false; + offset = target = 0; + images = []; + item_width = view.find('.carousel-item').first().innerWidth(); + dim = item_width * 2 + options.padding; + + view.find('.carousel-item').each(function (i) { + images.push($(this)[0]); + if (showIndicators) { + var $indicator = $('
          • '); + + // Add active to first by default. + if (i === 0) { + $indicator.addClass('active'); + } + + // Handle clicks on indicators. + $indicator.click(function () { + var index = $(this).index(); + cycleTo(index); + }); + $indicators.append($indicator); + } + }); + + if (showIndicators) { + view.append($indicators); + } + count = images.length; + + + function setupEvents() { + if (typeof window.ontouchstart !== 'undefined') { + view[0].addEventListener('touchstart', tap); + view[0].addEventListener('touchmove', drag); + view[0].addEventListener('touchend', release); + } + view[0].addEventListener('mousedown', tap); + view[0].addEventListener('mousemove', drag); + view[0].addEventListener('mouseup', release); + view[0].addEventListener('mouseleave', release); + view[0].addEventListener('click', click); + } + + function xpos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientX; + } + + // mouse event + return e.clientX; + } + + function ypos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientY; + } + + // mouse event + return e.clientY; + } + + function wrap(x) { + return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x; + } + + function scroll(x) { + var i, half, delta, dir, tween, el, alignment, xTranslation; + + offset = (typeof x === 'number') ? x : offset; + center = Math.floor((offset + dim / 2) / dim); + delta = offset - center * dim; + dir = (delta < 0) ? 1 : -1; + tween = -dir * delta * 2 / dim; + half = count >> 1; + + if (!options.full_width) { + alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) '; + alignment += 'translateY(' + (view[0].clientHeight - item_width) / 2 + 'px)'; + } else { + alignment = 'translateX(0)'; + } + + // Set indicator active + if (showIndicators) { + var diff = (center % count); + var activeIndicator = $indicators.find('.indicator-item.active'); + if (activeIndicator.index() !== diff) { + activeIndicator.removeClass('active'); + $indicators.find('.indicator-item').eq(diff).addClass('active'); + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween * i) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + for (i = 1; i <= half; ++i) { + // right side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 + tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center + i < count) { + el = images[wrap(center + i)]; + el.style[xform] = alignment + + ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + + // left side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 - tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center - i >= 0) { + el = images[wrap(center - i)]; + el.style[xform] = alignment + + ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + function track() { + var now, elapsed, delta, v; + + now = Date.now(); + elapsed = now - timestamp; + timestamp = now; + delta = offset - frame; + frame = offset; + + v = 1000 * delta / (1 + elapsed); + velocity = 0.8 * v + 0.2 * velocity; + } + + function autoScroll() { + var elapsed, delta; + + if (amplitude) { + elapsed = Date.now() - timestamp; + delta = amplitude * Math.exp(-elapsed / options.time_constant); + if (delta > 2 || delta < -2) { + scroll(target - delta); + requestAnimationFrame(autoScroll); + } else { + scroll(target); + } + } + } + + function click(e) { + // Disable clicks if carousel was dragged. + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + return false; + + } else if (!options.full_width) { + var clickedIndex = $(e.target).closest('.carousel-item').index(); + var diff = (center % count) - clickedIndex; + + // Disable clicks if carousel was shifted by click + if (diff !== 0) { + e.preventDefault(); + e.stopPropagation(); + } + cycleTo(clickedIndex); + } + } + + function cycleTo(n) { + var diff = (center % count) - n; + + // Account for wraparound. + if (!options.no_wrap) { + if (diff < 0) { + if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; } + + } else if (diff > 0) { + if (Math.abs(diff - count) < diff) { diff -= count; } + } + } + + // Call prev or next accordingly. + if (diff < 0) { + view.trigger('carouselNext', [Math.abs(diff)]); + + } else if (diff > 0) { + view.trigger('carouselPrev', [diff]); + } + } + + function tap(e) { + pressed = true; + dragged = false; + vertical_dragged = false; + reference = xpos(e); + referenceY = ypos(e); + + velocity = amplitude = 0; + frame = offset; + timestamp = Date.now(); + clearInterval(ticker); + ticker = setInterval(track, 100); + + } + + function drag(e) { + var x, delta, deltaY; + if (pressed) { + x = xpos(e); + y = ypos(e); + delta = reference - x; + deltaY = Math.abs(referenceY - y); + if (deltaY < 30 && !vertical_dragged) { + // If vertical scrolling don't allow dragging. + if (delta > 2 || delta < -2) { + dragged = true; + reference = x; + scroll(offset + delta); + } + + } else if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + + } else { + // Vertical scrolling. + vertical_dragged = true; + } + } + + if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + + function release(e) { + if (pressed) { + pressed = false; + } else { + return; + } + + clearInterval(ticker); + target = offset; + if (velocity > 10 || velocity < -10) { + amplitude = 0.9 * velocity; + target = offset + amplitude; + } + target = Math.round(target / dim) * dim; + + // No wrap of items. + if (options.no_wrap) { + if (target >= dim * (count - 1)) { + target = dim * (count - 1); + } else if (target < 0) { + target = 0; + } + } + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } + + xform = 'transform'; + ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { + var e = prefix + 'Transform'; + if (typeof document.body.style[e] !== 'undefined') { + xform = e; + return false; + } + return true; + }); + + + + window.onresize = scroll; + + setupEvents(); + scroll(offset); + + $(this).on('carouselNext', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset + dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselPrev', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset - dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselSet', function(e, n) { + if (n === undefined) { + n = 0; + } + cycleTo(n); + }); + + }); + + + + }, + next : function(n) { + $(this).trigger('carouselNext', [n]); + }, + prev : function(n) { + $(this).trigger('carouselPrev', [n]); + }, + set : function(n) { + $(this).trigger('carouselSet', [n]); + } + }; + + + $.fn.carousel = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' ); + } + }; // Plugin end +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/bin/materialize.min.js b/assets/libs/materialize/js/bin/materialize.min.js new file mode 100644 index 0000000..9493303 --- /dev/null +++ b/assets/libs/materialize/js/bin/materialize.min.js @@ -0,0 +1,10 @@ +/*! + * Materialize v0.97.8 (http://materializecss.com) + * Copyright 2014-2015 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +if("undefined"==typeof jQuery){var jQuery;jQuery="function"==typeof require?$=require("jquery"):$}jQuery.easing.jswing=jQuery.easing.swing,jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(a,b,c,d,e){return jQuery.easing[jQuery.easing.def](a,b,c,d,e)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return 0==b?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return 0==b?c:b==e?c+d:(b/=e/2)<1?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return(b/=e/2)<1?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),hb?-.5*(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g))+c:h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*(2*Math.PI)/g)*.5+d+c},easeInBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*(b/=e)*b*((f+1)*b-f)+c},easeOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*((b=b/e-1)*b*((f+1)*b+f)+1)+c},easeInOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),(b/=e/2)<1?d/2*(b*b*(((f*=1.525)+1)*b-f))+c:d/2*((b-=2)*b*(((f*=1.525)+1)*b+f)+2)+c},easeInBounce:function(a,b,c,d,e){return d-jQuery.easing.easeOutBounce(a,e-b,0,d,e)+c},easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?d*(7.5625*b*b)+c:2/2.75>b?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:2.5/2.75>b?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(a,b,c,d,e){return e/2>b?.5*jQuery.easing.easeInBounce(a,2*b,0,d,e)+c:.5*jQuery.easing.easeOutBounce(a,2*b-e,0,d,e)+.5*d+c}}),jQuery.extend(jQuery.easing,{easeInOutMaterial:function(a,b,c,d,e){return(b/=e/2)<1?d/2*b*b+c:d/4*((b-=2)*b*b+2)+c}}),jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(a){function b(a){var b=a.length,d=c.type(a);return"function"===d||c.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===d||0===b||"number"==typeof b&&b>0&&b-1 in a}if(!a.jQuery){var c=function(a,b){return new c.fn.init(a,b)};c.isWindow=function(a){return null!=a&&a==a.window},c.type=function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?e[g.call(a)]||"object":typeof a},c.isArray=Array.isArray||function(a){return"array"===c.type(a)},c.isPlainObject=function(a){var b;if(!a||"object"!==c.type(a)||a.nodeType||c.isWindow(a))return!1;try{if(a.constructor&&!f.call(a,"constructor")&&!f.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(d){return!1}for(b in a);return void 0===b||f.call(a,b)},c.each=function(a,c,d){var e,f=0,g=a.length,h=b(a);if(d){if(h)for(;g>f&&(e=c.apply(a[f],d),e!==!1);f++);else for(f in a)if(e=c.apply(a[f],d),e===!1)break}else if(h)for(;g>f&&(e=c.call(a[f],f,a[f]),e!==!1);f++);else for(f in a)if(e=c.call(a[f],f,a[f]),e===!1)break;return a},c.data=function(a,b,e){if(void 0===e){var f=a[c.expando],g=f&&d[f];if(void 0===b)return g;if(g&&b in g)return g[b]}else if(void 0!==b){var f=a[c.expando]||(a[c.expando]=++c.uuid);return d[f]=d[f]||{},d[f][b]=e,e}},c.removeData=function(a,b){var e=a[c.expando],f=e&&d[e];f&&c.each(b,function(a,b){delete f[b]})},c.extend=function(){var a,b,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;for("boolean"==typeof h&&(k=h,h=arguments[i]||{},i++),"object"!=typeof h&&"function"!==c.type(h)&&(h={}),i===j&&(h=this,i--);j>i;i++)if(null!=(f=arguments[i]))for(e in f)a=h[e],d=f[e],h!==d&&(k&&d&&(c.isPlainObject(d)||(b=c.isArray(d)))?(b?(b=!1,g=a&&c.isArray(a)?a:[]):g=a&&c.isPlainObject(a)?a:{},h[e]=c.extend(k,g,d)):void 0!==d&&(h[e]=d));return h},c.queue=function(a,d,e){function f(a,c){var d=c||[];return null!=a&&(b(Object(a))?!function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;)a[e++]=b[d++];if(c!==c)for(;void 0!==b[d];)a[e++]=b[d++];return a.length=e,a}(d,"string"==typeof a?[a]:a):[].push.call(d,a)),d}if(a){d=(d||"fx")+"queue";var g=c.data(a,d);return e?(!g||c.isArray(e)?g=c.data(a,d,f(e)):g.push(e),g):g||[]}},c.dequeue=function(a,b){c.each(a.nodeType?[a]:a,function(a,d){b=b||"fx";var e=c.queue(d,b),f=e.shift();"inprogress"===f&&(f=e.shift()),f&&("fx"===b&&e.unshift("inprogress"),f.call(d,function(){c.dequeue(d,b)}))})},c.fn=c.prototype={init:function(a){if(a.nodeType)return this[0]=a,this;throw new Error("Not a DOM node.")},offset:function(){var b=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:b.top+(a.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:b.left+(a.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function a(){for(var a=this.offsetParent||document;a&&"html"===!a.nodeType.toLowerCase&&"static"===a.style.position;)a=a.offsetParent;return a||document}var b=this[0],a=a.apply(b),d=this.offset(),e=/^(?:body|html)$/i.test(a.nodeName)?{top:0,left:0}:c(a).offset();return d.top-=parseFloat(b.style.marginTop)||0,d.left-=parseFloat(b.style.marginLeft)||0,a.style&&(e.top+=parseFloat(a.style.borderTopWidth)||0,e.left+=parseFloat(a.style.borderLeftWidth)||0),{top:d.top-e.top,left:d.left-e.left}}};var d={};c.expando="velocity"+(new Date).getTime(),c.uuid=0;for(var e={},f=e.hasOwnProperty,g=e.toString,h="Boolean Number String Function Array Date RegExp Object Error".split(" "),i=0;ie;++e){var f=j(c,a,d);if(0===f)return c;var g=i(c,a,d)-b;c-=g/f}return c}function l(){for(var b=0;t>b;++b)x[b]=i(b*u,a,d)}function m(b,c,e){var f,g,h=0;do g=c+(e-c)/2,f=i(g,a,d)-b,f>0?e=g:c=g;while(Math.abs(f)>r&&++h=q?k(b,h):0==i?h:m(b,c,c+u)}function o(){y=!0,(a!=c||d!=e)&&l()}var p=4,q=.001,r=1e-7,s=10,t=11,u=1/(t-1),v="Float32Array"in b;if(4!==arguments.length)return!1;for(var w=0;4>w;++w)if("number"!=typeof arguments[w]||isNaN(arguments[w])||!isFinite(arguments[w]))return!1;a=Math.min(a,1),d=Math.min(d,1),a=Math.max(a,0),d=Math.max(d,0);var x=v?new Float32Array(t):new Array(t),y=!1,z=function(b){return y||o(),a===c&&d===e?b:0===b?0:1===b?1:i(n(b),c,e)};z.getControlPoints=function(){return[{x:a,y:c},{x:d,y:e}]};var A="generateBezier("+[a,c,d,e]+")";return z.toString=function(){return A},z}function j(a,b){var c=a;return p.isString(a)?t.Easings[a]||(c=!1):c=p.isArray(a)&&1===a.length?h.apply(null,a):p.isArray(a)&&2===a.length?u.apply(null,a.concat([b])):p.isArray(a)&&4===a.length?i.apply(null,a):!1,c===!1&&(c=t.Easings[t.defaults.easing]?t.defaults.easing:s),c}function k(a){if(a){var b=(new Date).getTime(),c=t.State.calls.length;c>1e4&&(t.State.calls=e(t.State.calls));for(var f=0;c>f;f++)if(t.State.calls[f]){var h=t.State.calls[f],i=h[0],j=h[2],n=h[3],o=!!n,q=null;n||(n=t.State.calls[f][3]=b-16);for(var r=Math.min((b-n)/j.duration,1),s=0,u=i.length;u>s;s++){var w=i[s],y=w.element;if(g(y)){var z=!1;if(j.display!==d&&null!==j.display&&"none"!==j.display){if("flex"===j.display){var A=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];m.each(A,function(a,b){v.setPropertyValue(y,"display",b)})}v.setPropertyValue(y,"display",j.display)}j.visibility!==d&&"hidden"!==j.visibility&&v.setPropertyValue(y,"visibility",j.visibility);for(var B in w)if("element"!==B){var C,D=w[B],E=p.isString(D.easing)?t.Easings[D.easing]:D.easing;if(1===r)C=D.endValue;else{var F=D.endValue-D.startValue;if(C=D.startValue+F*E(r,j,F),!o&&C===D.currentValue)continue}if(D.currentValue=C,"tween"===B)q=C;else{if(v.Hooks.registered[B]){var G=v.Hooks.getRoot(B),H=g(y).rootPropertyValueCache[G];H&&(D.rootPropertyValue=H)}var I=v.setPropertyValue(y,B,D.currentValue+(0===parseFloat(C)?"":D.unitType),D.rootPropertyValue,D.scrollData);v.Hooks.registered[B]&&(g(y).rootPropertyValueCache[G]=v.Normalizations.registered[G]?v.Normalizations.registered[G]("extract",null,I[1]):I[1]),"transform"===I[0]&&(z=!0)}}j.mobileHA&&g(y).transformCache.translate3d===d&&(g(y).transformCache.translate3d="(0px, 0px, 0px)",z=!0),z&&v.flushTransformCache(y)}}j.display!==d&&"none"!==j.display&&(t.State.calls[f][2].display=!1),j.visibility!==d&&"hidden"!==j.visibility&&(t.State.calls[f][2].visibility=!1),j.progress&&j.progress.call(h[1],h[1],r,Math.max(0,n+j.duration-b),n,q),1===r&&l(f)}}t.State.isTicking&&x(k)}function l(a,b){if(!t.State.calls[a])return!1;for(var c=t.State.calls[a][0],e=t.State.calls[a][1],f=t.State.calls[a][2],h=t.State.calls[a][4],i=!1,j=0,k=c.length;k>j;j++){var l=c[j].element;if(b||f.loop||("none"===f.display&&v.setPropertyValue(l,"display",f.display),"hidden"===f.visibility&&v.setPropertyValue(l,"visibility",f.visibility)),f.loop!==!0&&(m.queue(l)[1]===d||!/\.velocityQueueEntryFlag/i.test(m.queue(l)[1]))&&g(l)){g(l).isAnimating=!1,g(l).rootPropertyValueCache={};var n=!1;m.each(v.Lists.transforms3D,function(a,b){var c=/^scale/.test(b)?1:0,e=g(l).transformCache[b];g(l).transformCache[b]!==d&&new RegExp("^\\("+c+"[^.]").test(e)&&(n=!0,delete g(l).transformCache[b])}),f.mobileHA&&(n=!0,delete g(l).transformCache.translate3d),n&&v.flushTransformCache(l),v.Values.removeClass(l,"velocity-animating")}if(!b&&f.complete&&!f.loop&&j===k-1)try{f.complete.call(e,e)}catch(o){setTimeout(function(){throw o},1)}h&&f.loop!==!0&&h(e),g(l)&&f.loop===!0&&!b&&(m.each(g(l).tweensContainer,function(a,b){/^rotate/.test(a)&&360===parseFloat(b.endValue)&&(b.endValue=0,b.startValue=360),/^backgroundPosition/.test(a)&&100===parseFloat(b.endValue)&&"%"===b.unitType&&(b.endValue=0,b.startValue=100)}),t(l,"reverse",{loop:!0,delay:f.delay})),f.queue!==!1&&m.dequeue(l,f.queue)}t.State.calls[a]=!1;for(var p=0,q=t.State.calls.length;q>p;p++)if(t.State.calls[p]!==!1){i=!0;break}i===!1&&(t.State.isTicking=!1,delete t.State.calls,t.State.calls=[])}var m,n=function(){if(c.documentMode)return c.documentMode;for(var a=7;a>4;a--){var b=c.createElement("div");if(b.innerHTML="",b.getElementsByTagName("span").length)return b=null,a}return d}(),o=function(){var a=0;return b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame||function(b){var c,d=(new Date).getTime();return c=Math.max(0,16-(d-a)),a=d+c,setTimeout(function(){b(d+c)},c)}}(),p={isString:function(a){return"string"==typeof a},isArray:Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},isFunction:function(a){return"[object Function]"===Object.prototype.toString.call(a)},isNode:function(a){return a&&a.nodeType},isNodeList:function(a){return"object"==typeof a&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(a))&&a.length!==d&&(0===a.length||"object"==typeof a[0]&&a[0].nodeType>0)},isWrapped:function(a){return a&&(a.jquery||b.Zepto&&b.Zepto.zepto.isZ(a))},isSVG:function(a){return b.SVGElement&&a instanceof b.SVGElement},isEmptyObject:function(a){for(var b in a)return!1;return!0}},q=!1;if(a.fn&&a.fn.jquery?(m=a,q=!0):m=b.Velocity.Utilities,8>=n&&!q)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=n)return void(jQuery.fn.velocity=jQuery.fn.animate);var r=400,s="swing",t={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:b.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:c.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:m,Redirects:{},Easings:{},Promise:b.Promise,defaults:{queue:"",duration:r,easing:s,begin:d,complete:d,progress:d,display:d,visibility:d,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(a){m.data(a,"velocity",{isSVG:p.isSVG(a),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};b.pageYOffset!==d?(t.State.scrollAnchor=b,t.State.scrollPropertyLeft="pageXOffset",t.State.scrollPropertyTop="pageYOffset"):(t.State.scrollAnchor=c.documentElement||c.body.parentNode||c.body,t.State.scrollPropertyLeft="scrollLeft",t.State.scrollPropertyTop="scrollTop");var u=function(){function a(a){return-a.tension*a.x-a.friction*a.v}function b(b,c,d){var e={x:b.x+d.dx*c,v:b.v+d.dv*c,tension:b.tension,friction:b.friction};return{dx:e.v,dv:a(e)}}function c(c,d){var e={dx:c.v,dv:a(c)},f=b(c,.5*d,e),g=b(c,.5*d,f),h=b(c,d,g),i=1/6*(e.dx+2*(f.dx+g.dx)+h.dx),j=1/6*(e.dv+2*(f.dv+g.dv)+h.dv);return c.x=c.x+i*d,c.v=c.v+j*d,c}return function d(a,b,e){var f,g,h,i={x:-1,v:0,tension:null,friction:null},j=[0],k=0,l=1e-4,m=.016;for(a=parseFloat(a)||500,b=parseFloat(b)||20,e=e||null,i.tension=a,i.friction=b,f=null!==e,f?(k=d(a,b),g=k/e*m):g=m;h=c(h||i,g),j.push(1+h.x),k+=16,Math.abs(h.x)>l&&Math.abs(h.v)>l;);return f?function(a){return j[a*(j.length-1)|0]}:k}}();t.Easings={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},spring:function(a){return 1-Math.cos(4.5*a*Math.PI)*Math.exp(6*-a)}},m.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(a,b){t.Easings[b[0]]=i.apply(null,b[1])});var v=t.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var a=0;a=n)switch(a){case"name":return"filter";case"extract":var d=c.toString().match(/alpha\(opacity=(.*)\)/i);return c=d?d[1]/100:1;case"inject":return b.style.zoom=1,parseFloat(c)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(c),10)+")"}else switch(a){case"name":return"opacity";case"extract":return c;case"inject":return c}}},register:function(){9>=n||t.State.isGingerbread||(v.Lists.transformsBase=v.Lists.transformsBase.concat(v.Lists.transforms3D));for(var a=0;ae&&(e=1),f=!/(\d)$/i.test(e);break;case"skew":f=!/(deg|\d)$/i.test(e);break;case"rotate":f=!/(deg|\d)$/i.test(e)}return f||(g(c).transformCache[b]="("+e+")"),g(c).transformCache[b]}}}();for(var a=0;a=n||3!==f.split(" ").length||(f+=" 1"),f;case"inject":return 8>=n?4===e.split(" ").length&&(e=e.split(/\s+/).slice(0,3).join(" ")):3===e.split(" ").length&&(e+=" 1"),(8>=n?"rgb":"rgba")+"("+e.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(a){return a.replace(/-(\w)/g,function(a,b){return b.toUpperCase()})},SVGAttribute:function(a){var b="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(n||t.State.isAndroid&&!t.State.isChrome)&&(b+="|transform"),new RegExp("^("+b+")$","i").test(a)},prefixCheck:function(a){if(t.State.prefixMatches[a])return[t.State.prefixMatches[a],!0];for(var b=["","Webkit","Moz","ms","O"],c=0,d=b.length;d>c;c++){var e;if(e=0===c?a:b[c]+a.replace(/^\w/,function(a){return a.toUpperCase()}),p.isString(t.State.prefixElement.style[e]))return t.State.prefixMatches[a]=e,[e,!0]}return[a,!1]}},Values:{hexToRgb:function(a){var b,c=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,d=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return a=a.replace(c,function(a,b,c,d){return b+b+c+c+d+d}),b=d.exec(a),b?[parseInt(b[1],16),parseInt(b[2],16),parseInt(b[3],16)]:[0,0,0]},isCSSNullValue:function(a){return 0==a||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(a)},getUnitType:function(a){return/^(rotate|skew)/i.test(a)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(a)?"":"px"},getDisplayType:function(a){var b=a&&a.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(b)?"inline":/^(li)$/i.test(b)?"list-item":/^(tr)$/i.test(b)?"table-row":/^(table)$/i.test(b)?"table":/^(tbody)$/i.test(b)?"table-row-group":"block"},addClass:function(a,b){a.classList?a.classList.add(b):a.className+=(a.className.length?" ":"")+b},removeClass:function(a,b){a.classList?a.classList.remove(b):a.className=a.className.toString().replace(new RegExp("(^|\\s)"+b.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(a,c,e,f){function h(a,c){function e(){j&&v.setPropertyValue(a,"display","none")}var i=0;if(8>=n)i=m.css(a,c);else{var j=!1;if(/^(width|height)$/.test(c)&&0===v.getPropertyValue(a,"display")&&(j=!0,v.setPropertyValue(a,"display",v.Values.getDisplayType(a))),!f){if("height"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var k=a.offsetHeight-(parseFloat(v.getPropertyValue(a,"borderTopWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderBottomWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingTop"))||0)-(parseFloat(v.getPropertyValue(a,"paddingBottom"))||0);return e(),k}if("width"===c&&"border-box"!==v.getPropertyValue(a,"boxSizing").toString().toLowerCase()){var l=a.offsetWidth-(parseFloat(v.getPropertyValue(a,"borderLeftWidth"))||0)-(parseFloat(v.getPropertyValue(a,"borderRightWidth"))||0)-(parseFloat(v.getPropertyValue(a,"paddingLeft"))||0)-(parseFloat(v.getPropertyValue(a,"paddingRight"))||0);return e(),l}}var o;o=g(a)===d?b.getComputedStyle(a,null):g(a).computedStyle?g(a).computedStyle:g(a).computedStyle=b.getComputedStyle(a,null),"borderColor"===c&&(c="borderTopColor"),i=9===n&&"filter"===c?o.getPropertyValue(c):o[c],(""===i||null===i)&&(i=a.style[c]),e()}if("auto"===i&&/^(top|right|bottom|left)$/i.test(c)){var p=h(a,"position");("fixed"===p||"absolute"===p&&/top|left/i.test(c))&&(i=m(a).position()[c]+"px")}return i}var i;if(v.Hooks.registered[c]){var j=c,k=v.Hooks.getRoot(j);e===d&&(e=v.getPropertyValue(a,v.Names.prefixCheck(k)[0])),v.Normalizations.registered[k]&&(e=v.Normalizations.registered[k]("extract",a,e)),i=v.Hooks.extractValue(j,e)}else if(v.Normalizations.registered[c]){var l,o;l=v.Normalizations.registered[c]("name",a),"transform"!==l&&(o=h(a,v.Names.prefixCheck(l)[0]),v.Values.isCSSNullValue(o)&&v.Hooks.templates[c]&&(o=v.Hooks.templates[c][1])),i=v.Normalizations.registered[c]("extract",a,o)}if(!/^[\d-]/.test(i))if(g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c))if(/^(height|width)$/i.test(c))try{i=a.getBBox()[c]}catch(p){i=0}else i=a.getAttribute(c);else i=h(a,v.Names.prefixCheck(c)[0]);return v.Values.isCSSNullValue(i)&&(i=0),t.debug>=2&&console.log("Get "+c+": "+i),i},setPropertyValue:function(a,c,d,e,f){var h=c;if("scroll"===c)f.container?f.container["scroll"+f.direction]=d:"Left"===f.direction?b.scrollTo(d,f.alternateValue):b.scrollTo(f.alternateValue,d);else if(v.Normalizations.registered[c]&&"transform"===v.Normalizations.registered[c]("name",a))v.Normalizations.registered[c]("inject",a,d),h="transform",d=g(a).transformCache[c];else{if(v.Hooks.registered[c]){var i=c,j=v.Hooks.getRoot(c);e=e||v.getPropertyValue(a,j),d=v.Hooks.injectValue(i,d,e),c=j}if(v.Normalizations.registered[c]&&(d=v.Normalizations.registered[c]("inject",a,d),c=v.Normalizations.registered[c]("name",a)),h=v.Names.prefixCheck(c)[0],8>=n)try{a.style[h]=d}catch(k){t.debug&&console.log("Browser does not support ["+d+"] for ["+h+"]")}else g(a)&&g(a).isSVG&&v.Names.SVGAttribute(c)?a.setAttribute(c,d):a.style[h]=d;t.debug>=2&&console.log("Set "+c+" ("+h+"): "+d)}return[h,d]},flushTransformCache:function(a){function b(b){return parseFloat(v.getPropertyValue(a,b))}var c="";if((n||t.State.isAndroid&&!t.State.isChrome)&&g(a).isSVG){var d={translate:[b("translateX"),b("translateY")],skewX:[b("skewX")],skewY:[b("skewY")],scale:1!==b("scale")?[b("scale"),b("scale")]:[b("scaleX"),b("scaleY")],rotate:[b("rotateZ"),0,0]};m.each(g(a).transformCache,function(a){/^translate/i.test(a)?a="translate":/^scale/i.test(a)?a="scale":/^rotate/i.test(a)&&(a="rotate"),d[a]&&(c+=a+"("+d[a].join(" ")+") ",delete d[a])})}else{var e,f;m.each(g(a).transformCache,function(b){return e=g(a).transformCache[b],"transformPerspective"===b?(f=e,!0):(9===n&&"rotateZ"===b&&(b="rotate"),void(c+=b+e+" "))}),f&&(c="perspective"+f+" "+c)}v.setPropertyValue(a,"transform",c)}};v.Hooks.register(),v.Normalizations.register(),t.hook=function(a,b,c){var e=d;return a=f(a),m.each(a,function(a,f){if(g(f)===d&&t.init(f),c===d)e===d&&(e=t.CSS.getPropertyValue(f,b));else{var h=t.CSS.setPropertyValue(f,b,c);"transform"===h[0]&&t.CSS.flushTransformCache(f),e=h}}),e};var w=function(){function a(){return h?B.promise||null:i}function e(){function a(a){function l(a,b){var c=d,e=d,g=d;return p.isArray(a)?(c=a[0],!p.isArray(a[1])&&/^[\d-]/.test(a[1])||p.isFunction(a[1])||v.RegEx.isHex.test(a[1])?g=a[1]:(p.isString(a[1])&&!v.RegEx.isHex.test(a[1])||p.isArray(a[1]))&&(e=b?a[1]:j(a[1],h.duration),a[2]!==d&&(g=a[2]))):c=a,b||(e=e||h.easing),p.isFunction(c)&&(c=c.call(f,y,x)),p.isFunction(g)&&(g=g.call(f,y,x)),[c||0,e,g]}function n(a,b){var c,d;return d=(b||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(a){return c=a,""}),c||(c=v.Values.getUnitType(a)),[d,c]}function r(){var a={myParent:f.parentNode||c.body,position:v.getPropertyValue(f,"position"),fontSize:v.getPropertyValue(f,"fontSize")},d=a.position===I.lastPosition&&a.myParent===I.lastParent,e=a.fontSize===I.lastFontSize;I.lastParent=a.myParent,I.lastPosition=a.position,I.lastFontSize=a.fontSize;var h=100,i={};if(e&&d)i.emToPx=I.lastEmToPx,i.percentToPxWidth=I.lastPercentToPxWidth,i.percentToPxHeight=I.lastPercentToPxHeight;else{var j=g(f).isSVG?c.createElementNS("http://www.w3.org/2000/svg","rect"):c.createElement("div");t.init(j),a.myParent.appendChild(j),m.each(["overflow","overflowX","overflowY"],function(a,b){t.CSS.setPropertyValue(j,b,"hidden")}),t.CSS.setPropertyValue(j,"position",a.position),t.CSS.setPropertyValue(j,"fontSize",a.fontSize),t.CSS.setPropertyValue(j,"boxSizing","content-box"),m.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(a,b){t.CSS.setPropertyValue(j,b,h+"%")}),t.CSS.setPropertyValue(j,"paddingLeft",h+"em"),i.percentToPxWidth=I.lastPercentToPxWidth=(parseFloat(v.getPropertyValue(j,"width",null,!0))||1)/h,i.percentToPxHeight=I.lastPercentToPxHeight=(parseFloat(v.getPropertyValue(j,"height",null,!0))||1)/h,i.emToPx=I.lastEmToPx=(parseFloat(v.getPropertyValue(j,"paddingLeft"))||1)/h,a.myParent.removeChild(j)}return null===I.remToPx&&(I.remToPx=parseFloat(v.getPropertyValue(c.body,"fontSize"))||16),null===I.vwToPx&&(I.vwToPx=parseFloat(b.innerWidth)/100,I.vhToPx=parseFloat(b.innerHeight)/100),i.remToPx=I.remToPx,i.vwToPx=I.vwToPx,i.vhToPx=I.vhToPx,t.debug>=1&&console.log("Unit ratios: "+JSON.stringify(i),f),i}if(h.begin&&0===y)try{h.begin.call(o,o)}catch(u){setTimeout(function(){throw u},1)}if("scroll"===C){var w,z,A,D=/^x$/i.test(h.axis)?"Left":"Top",E=parseFloat(h.offset)||0;h.container?p.isWrapped(h.container)||p.isNode(h.container)?(h.container=h.container[0]||h.container,w=h.container["scroll"+D],A=w+m(f).position()[D.toLowerCase()]+E):h.container=null:(w=t.State.scrollAnchor[t.State["scrollProperty"+D]],z=t.State.scrollAnchor[t.State["scrollProperty"+("Left"===D?"Top":"Left")]],A=m(f).offset()[D.toLowerCase()]+E),i={scroll:{rootPropertyValue:!1,startValue:w,currentValue:w,endValue:A,unitType:"",easing:h.easing,scrollData:{container:h.container,direction:D,alternateValue:z}},element:f},t.debug&&console.log("tweensContainer (scroll): ",i.scroll,f)}else if("reverse"===C){if(!g(f).tweensContainer)return void m.dequeue(f,h.queue);"none"===g(f).opts.display&&(g(f).opts.display="auto"),"hidden"===g(f).opts.visibility&&(g(f).opts.visibility="visible"),g(f).opts.loop=!1,g(f).opts.begin=null,g(f).opts.complete=null,s.easing||delete h.easing,s.duration||delete h.duration,h=m.extend({},g(f).opts,h);var F=m.extend(!0,{},g(f).tweensContainer);for(var G in F)if("element"!==G){var H=F[G].startValue;F[G].startValue=F[G].currentValue=F[G].endValue,F[G].endValue=H,p.isEmptyObject(s)||(F[G].easing=h.easing),t.debug&&console.log("reverse tweensContainer ("+G+"): "+JSON.stringify(F[G]),f)}i=F}else if("start"===C){var F;g(f).tweensContainer&&g(f).isAnimating===!0&&(F=g(f).tweensContainer),m.each(q,function(a,b){if(RegExp("^"+v.Lists.colors.join("$|^")+"$").test(a)){var c=l(b,!0),e=c[0],f=c[1],g=c[2];if(v.RegEx.isHex.test(e)){for(var h=["Red","Green","Blue"],i=v.Values.hexToRgb(e),j=g?v.Values.hexToRgb(g):d,k=0;kL;L++){var M={delay:E.delay,progress:E.progress};L===K-1&&(M.display=E.display,M.visibility=E.visibility,M.complete=E.complete),w(o,"reverse",M)}return a()}};t=m.extend(w,t),t.animate=w;var x=b.requestAnimationFrame||o;return t.State.isMobile||c.hidden===d||c.addEventListener("visibilitychange",function(){c.hidden?(x=function(a){return setTimeout(function(){a(!0)},16)},k()):x=b.requestAnimationFrame||o}),a.Velocity=t,a!==b&&(a.fn.velocity=w,a.fn.velocity.defaults=t.defaults),m.each(["Down","Up"],function(a,b){t.Redirects["slide"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j=i.begin,k=i.complete,l={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},n={};i.display===d&&(i.display="Down"===b?"inline"===t.CSS.Values.getDisplayType(a)?"inline-block":"block":"none"),i.begin=function(){j&&j.call(g,g);for(var c in l){n[c]=a.style[c];var d=t.CSS.getPropertyValue(a,c);l[c]="Down"===b?[d,0]:[0,d]}n.overflow=a.style.overflow,a.style.overflow="hidden"},i.complete=function(){for(var b in n)a.style[b]=n[b];k&&k.call(g,g),h&&h.resolver(g)},t(a,l,i)}}),m.each(["In","Out"],function(a,b){t.Redirects["fade"+b]=function(a,c,e,f,g,h){var i=m.extend({},c),j={opacity:"In"===b?1:0},k=i.complete;i.complete=e!==f-1?i.begin=null:function(){k&&k.call(g,g),h&&h.resolver(g)},i.display===d&&(i.display="In"===b?"auto":"none"),t(this,j,i)}}),t}(window.jQuery||window.Zepto||window,window,document)})),!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(k(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e-1}function r(a){return a.trim().split(/\s+/g)}function s(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function v(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g1&&!c.firstMultiple?c.firstMultiple=E(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=F(d);b.timeStamp=na(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=J(h,i),b.distance=I(h,i),C(c,b),b.offsetDirection=H(b.deltaX,b.deltaY),b.scale=g?L(g.pointers,d):1,b.rotation=g?K(g.pointers,d):0,D(c,b);var j=a.element;p(b.srcEvent.target,j)&&(j=b.srcEvent.target),b.target=j}function C(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===ya||f.eventType===Aa)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function D(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ba&&(i>xa||h.velocity===d)){var j=h.deltaX-b.deltaX,k=h.deltaY-b.deltaY,l=G(i,j,k);e=l.x,f=l.y,c=ma(l.x)>ma(l.y)?l.x:l.y,g=H(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function E(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:la(c/b),y:la(d/b)}}function G(a,b,c){return{x:b/a||0,y:c/a||0}}function H(a,b){return a===b?Ca:ma(a)>=ma(b)?a>0?Da:Ea:b>0?Fa:Ga}function I(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function J(a,b,c){c||(c=Ka);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function K(a,b){return J(b[1],b[0],La)-J(a[1],a[0],La)}function L(a,b){return I(b[0],b[1],La)/I(a[0],a[1],La)}function M(){this.evEl=Na,this.evWin=Oa,this.allow=!0,this.pressed=!1,y.apply(this,arguments)}function N(){this.evEl=Ra,this.evWin=Sa,y.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function O(){this.evTarget=Ua,this.evWin=Va,this.started=!1,y.apply(this,arguments)}function P(a,b){var c=t(a.touches),d=t(a.changedTouches);return b&(Aa|Ba)&&(c=u(c.concat(d),"identifier",!0)),[c,d]}function Q(){this.evTarget=Xa,this.targetIds={},y.apply(this,arguments)}function R(a,b){var c=t(a.touches),d=this.targetIds;if(b&(ya|za)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=t(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return p(a.target,i)}),b===ya)for(e=0;eh&&(b.push(a),h=b.length-1):e&(Aa|Ba)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Ta={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Ua="touchstart",Va="touchstart touchmove touchend touchcancel";j(O,y,{handler:function(a){var b=Ta[a.type];if(b===ya&&(this.started=!0),this.started){var c=P.call(this,a,b);b&(Aa|Ba)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}});var Wa={touchstart:ya,touchmove:za,touchend:Aa,touchcancel:Ba},Xa="touchstart touchmove touchend touchcancel";j(Q,y,{handler:function(a){var b=Wa[a.type],c=R.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:ta,srcEvent:a})}}),j(S,y,{handler:function(a,b,c){var d=c.pointerType==ta,e=c.pointerType==va;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Aa|Ba)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Ya=v(ja.style,"touchAction"),Za=Ya!==d,$a="compute",_a="auto",ab="manipulation",bb="none",cb="pan-x",db="pan-y";T.prototype={set:function(a){a==$a&&(a=this.compute()),Za&&(this.manager.element.style[Ya]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){l(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),U(a.join(" "))},preventDefaults:function(a){if(!Za){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=q(d,bb),f=q(d,db),g=q(d,cb);return e||f&&c&Ha||g&&c&Ia?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var eb=1,fb=2,gb=4,hb=8,ib=hb,jb=16,kb=32;V.prototype={defaults:{},set:function(a){return h(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=Y(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=Y(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=Y(a,this),-1===s(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=Y(a,this);var b=s(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(c.options.event+(b?W(d):""),a)}var c=this,d=this.state;hb>d&&b(!0),b(),d>=hb&&b(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=kb)},canEmit:function(){for(var a=0;af?Da:Ea,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ca:0>g?Fa:Ga,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return Z.prototype.attrTest.call(this,a)&&(this.state&fb||!(this.state&fb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),j(_,Z,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&fb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),j(aa,V,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[_a]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Aa|Ba)&&!f)this.reset();else if(a.eventType&ya)this.reset(),this._timer=e(function(){this.state=ib,this.tryEmit()},b.time,this);else if(a.eventType&Aa)return ib;return kb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===ib&&(a&&a.eventType&Aa?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=na(),this.manager.emit(this.options.event,this._input)))}}),j(ba,Z,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[bb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&fb)}}),j(ca,Z,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:Ha|Ia,pointers:1},getTouchAction:function(){return $.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Ha|Ia)?b=a.velocity:c&Ha?b=a.velocityX:c&Ia&&(b=a.velocityY),this._super.attrTest.call(this,a)&&c&a.direction&&a.distance>this.options.threshold&&ma(b)>this.options.velocity&&a.eventType&Aa},emit:function(a){var b=X(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),j(da,V,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[ab]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance=0&&!d;)d=a[c[f]+"RequestAnimationFrame"],e=a[c[f]+"CancelRequestAnimationFrame"];d&&e||(d=function(a){var c=+Date.now(),d=Math.max(b+16,c);return setTimeout(function(){a(b=d)},d-c)},e=clearTimeout),a.requestAnimationFrame=d,a.cancelAnimationFrame=e}(window),Materialize.guid=function(){function a(){return Math.floor(65536*(1+Math.random())).toString(16).substring(1)}return function(){return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()}}(),Materialize.escapeHash=function(a){return a.replace(/(:|\.|\[|\]|,|=)/g,"\\$1")},Materialize.elementOrParentIsFixed=function(a){var b=$(a),c=b.add(b.parents()),d=!1;return c.each(function(){return"fixed"===$(this).css("position")?(d=!0,!1):void 0}),d};var Vel;Vel=jQuery?jQuery.Velocity:$?$.Velocity:Velocity,function(a){a.fn.collapsible=function(b){var c={accordion:void 0,onOpen:void 0,onClose:void 0};return b=a.extend(c,b),this.each(function(){function c(b){j=i.find("> li > .collapsible-header"),b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}),j.not(b).removeClass("active").parent().removeClass("active"),j.not(b).parent().children(".collapsible-body").stop(!0,!1).each(function(){a(this).is(":visible")&&a(this).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height",""),f(a(this).siblings(".collapsible-header"))}})})}function d(b){b.hasClass("active")?b.parent().addClass("active"):b.parent().removeClass("active"),b.parent().hasClass("active")?b.siblings(".collapsible-body").stop(!0,!1).slideDown({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}}):b.siblings(".collapsible-body").stop(!0,!1).slideUp({duration:350,easing:"easeOutQuart",queue:!1,complete:function(){a(this).css("height","")}})}function e(a){b.accordion||"accordion"===k||void 0===k?c(a):d(a),f(a)}function f(a){a.hasClass("active")?"function"==typeof b.onOpen&&b.onOpen.call(this,a.parent()):"function"==typeof b.onClose&&b.onClose.call(this,a.parent())}function g(a){var b=h(a);return b.length>0}function h(a){return a.closest("li > .collapsible-header")}var i=a(this),j=a(this).find("> li > .collapsible-header"),k=i.data("collapsible");i.off("click.collapse","> li > .collapsible-header"),j.off("click.collapse"),i.on("click.collapse","> li > .collapsible-header",function(b){var c=a(b.target);g(c)&&(c=h(c)),c.toggleClass("active"),e(c)}),b.accordion||"accordion"===k||void 0===k?e(j.filter(".active").first()):j.filter(".active").each(function(){e(a(this))})})},a(document).ready(function(){a(".collapsible").collapsible()})}(jQuery),function(a){a.fn.scrollTo=function(b){return a(this).scrollTop(a(this).scrollTop()-a(this).offset().top+a(b).offset().top),this},a.fn.dropdown=function(b){var c={inDuration:300,outDuration:225,constrain_width:!0,hover:!1,gutter:0,belowOrigin:!1,alignment:"left",stopPropagation:!1};return"open"===b?(this.each(function(){a(this).trigger("open")}),!1):"close"===b?(this.each(function(){a(this).trigger("close")}),!1):void this.each(function(){function d(){void 0!==g.data("induration")&&(h.inDuration=g.data("induration")),void 0!==g.data("outduration")&&(h.outDuration=g.data("outduration")),void 0!==g.data("constrainwidth")&&(h.constrain_width=g.data("constrainwidth")),void 0!==g.data("hover")&&(h.hover=g.data("hover")),void 0!==g.data("gutter")&&(h.gutter=g.data("gutter")),void 0!==g.data("beloworigin")&&(h.belowOrigin=g.data("beloworigin")),void 0!==g.data("alignment")&&(h.alignment=g.data("alignment")),void 0!==g.data("stoppropagation")&&(h.stopPropagation=g.data("stoppropagation"))}function e(b){"focus"===b&&(i=!0),d(),j.addClass("active"),g.addClass("active"),h.constrain_width===!0?j.css("width",g.outerWidth()):j.css("white-space","nowrap");var c=window.innerHeight,e=g.innerHeight(),f=g.offset().left,k=g.offset().top-a(window).scrollTop(),l=h.alignment,m=0,n=0,o=0;h.belowOrigin===!0&&(o=e);var p=0,q=0,r=g.parent();if(r.is("body")||(r[0].scrollHeight>r[0].clientHeight&&(p=r[0].scrollTop),r[0].scrollWidth>r[0].clientWidth&&(q=r[0].scrollLeft)),f+j.innerWidth()>a(window).width()?l="right":f-j.innerWidth()+g.innerWidth()<0&&(l="left"),k+j.innerHeight()>c)if(k+e-j.innerHeight()<0){var s=c-k-o;j.css("max-height",s)}else o||(o+=e),o-=j.innerHeight();if("left"===l)m=h.gutter,n=g.position().left+m;else if("right"===l){var t=g.position().left+g.outerWidth()-j.outerWidth();m=-h.gutter,n=t+m}j.css({position:"absolute",top:g.position().top+o+p,left:n+q}),j.stop(!0,!0).css("opacity",0).slideDown({queue:!1,duration:h.inDuration,easing:"easeOutCubic",complete:function(){a(this).css("height","")}}).animate({opacity:1},{queue:!1,duration:h.inDuration,easing:"easeOutSine"})}function f(){i=!1,j.fadeOut(h.outDuration),j.removeClass("active"),g.removeClass("active"),setTimeout(function(){j.css("max-height","")},h.outDuration)}var g=a(this),h=a.extend({},c,b),i=!1,j=a("#"+g.attr("data-activates"));if(d(),g.after(j),h.hover){var k=!1;g.unbind("click."+g.attr("id")),g.on("mouseenter",function(a){k===!1&&(e(),k=!0)}),g.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-content").is(j)||(j.stop(!0,!0),f(),k=!1)}),j.on("mouseleave",function(b){var c=b.toElement||b.relatedTarget;a(c).closest(".dropdown-button").is(g)||(j.stop(!0,!0),f(),k=!1)})}else g.unbind("click."+g.attr("id")),g.bind("click."+g.attr("id"),function(b){i||(g[0]!=b.currentTarget||g.hasClass("active")||0!==a(b.target).closest(".dropdown-content").length?g.hasClass("active")&&(f(),a(document).unbind("click."+j.attr("id")+" touchstart."+j.attr("id"))):(b.preventDefault(),h.stopPropagation&&b.stopPropagation(),e("click")),j.hasClass("active")&&a(document).bind("click."+j.attr("id")+" touchstart."+j.attr("id"),function(b){j.is(b.target)||g.is(b.target)||g.find(b.target).length||(f(),a(document).unbind("click."+j.attr("id")+" touchstart."+j.attr("id")))}))});g.on("open",function(a,b){e(b)}),g.on("close",f)})},a(document).ready(function(){a(".dropdown-button").dropdown()})}(jQuery),function(a){var b=0,c=0,d=function(){return c++,"materialize-modal-overlay-"+c},e={init:function(c){var e={opacity:.5,in_duration:350,out_duration:250,ready:void 0,complete:void 0,dismissible:!0,starting_top:"4%",ending_top:"10%"};return c=a.extend(e,c),this.each(function(){var e=a(this),f=a(this).attr("id")||"#"+a(this).data("target"),g=function(){var d=e.data("overlay-id"),f=a("#"+d);e.removeClass("open"),a("body").css({overflow:"",width:""}),e.find(".modal-close").off("click.close"),a(document).off("keyup.modal"+d),f.velocity({opacity:0},{duration:c.out_duration,queue:!1,ease:"easeOutQuart"});var g={ +duration:c.out_duration,queue:!1,ease:"easeOutCubic",complete:function(){a(this).css({display:"none"}),"function"==typeof c.complete&&c.complete.call(this,e),f.remove(),b--}};e.hasClass("bottom-sheet")?e.velocity({bottom:"-100%",opacity:0},g):e.velocity({top:c.starting_top,opacity:0,scaleX:.7},g)},h=function(f){var h=a("body"),i=h.innerWidth();if(h.css("overflow","hidden"),h.width(i),!e.hasClass("open")){var j=d(),k=a('');lStack=++b,k.attr("id",j).css("z-index",1e3+2*lStack),e.data("overlay-id",j).css("z-index",1e3+2*lStack+1),e.addClass("open"),a("body").append(k),c.dismissible&&(k.click(function(){g()}),a(document).on("keyup.modal"+j,function(a){27===a.keyCode&&g()})),e.find(".modal-close").on("click.close",function(a){g()}),k.css({display:"block",opacity:0}),e.css({display:"block",opacity:0}),k.velocity({opacity:c.opacity},{duration:c.in_duration,queue:!1,ease:"easeOutCubic"}),e.data("associated-overlay",k[0]);var l={duration:c.in_duration,queue:!1,ease:"easeOutCubic",complete:function(){"function"==typeof c.ready&&c.ready.call(this,e,f)}};e.hasClass("bottom-sheet")?e.velocity({bottom:"0",opacity:1},l):(a.Velocity.hook(e,"scaleX",.7),e.css({top:c.starting_top}),e.velocity({top:c.ending_top,opacity:1,scaleX:"1"},l))}};a(document).off("click.modalTrigger",'a[href="#'+f+'"], [data-target="'+f+'"]'),a(this).off("openModal"),a(this).off("closeModal"),a(document).on("click.modalTrigger",'a[href="#'+f+'"], [data-target="'+f+'"]',function(b){c.starting_top=(a(this).offset().top-a(window).scrollTop())/1.15,h(a(this)),b.preventDefault()}),a(this).on("openModal",function(){a(this).attr("href")||"#"+a(this).data("target");h()}),a(this).on("closeModal",function(){g()})})},open:function(){a(this).trigger("openModal")},close:function(){a(this).trigger("closeModal")}};a.fn.modal=function(b){return e[b]?e[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.modal"):e.init.apply(this,arguments)}}(jQuery),function(a){a.fn.materialbox=function(){return this.each(function(){function b(){f=!1;var b=i.parent(".material-placeholder"),d=(window.innerWidth,window.innerHeight,i.data("width")),g=i.data("height");i.velocity("stop",!0),a("#materialbox-overlay").velocity("stop",!0),a(".materialbox-caption").velocity("stop",!0),a("#materialbox-overlay").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){e=!1,a(this).remove()}}),i.velocity({width:d,height:g,left:0,top:0},{duration:h,queue:!1,easing:"easeOutQuad"}),a(".materialbox-caption").velocity({opacity:0},{duration:h,queue:!1,easing:"easeOutQuad",complete:function(){b.css({height:"",width:"",position:"",top:"",left:""}),i.css({height:"",top:"",left:"",width:"","max-width":"",position:"","z-index":""}),i.removeClass("active"),f=!0,a(this).remove(),c&&c.css("overflow","")}})}if(!a(this).hasClass("initialized")){a(this).addClass("initialized");var c,d,e=!1,f=!0,g=275,h=200,i=a(this),j=a("
            ").addClass("material-placeholder");i.wrap(j),i.on("click",function(){var h=i.parent(".material-placeholder"),j=window.innerWidth,k=window.innerHeight,l=i.width(),m=i.height();if(f===!1)return b(),!1;if(e&&f===!0)return b(),!1;f=!1,i.addClass("active"),e=!0,h.css({width:h[0].getBoundingClientRect().width,height:h[0].getBoundingClientRect().height,position:"relative",top:0,left:0}),c=void 0,d=h[0].parentNode;for(;null!==d&&!a(d).is(document);){var n=a(d);"visible"!==n.css("overflow")&&(n.css("overflow","visible"),c=void 0===c?n:c.add(n)),d=d.parentNode}i.css({position:"absolute","z-index":1e3}).data("width",l).data("height",m);var o=a('
            ').css({opacity:0}).click(function(){f===!0&&b()});if(i.before(o),o.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"}),""!==i.data("caption")){var p=a('
            ');p.text(i.data("caption")),a("body").append(p),p.css({display:"inline"}),p.velocity({opacity:1},{duration:g,queue:!1,easing:"easeOutQuad"})}var q=0,r=l/j,s=m/k,t=0,u=0;r>s?(q=m/l,t=.9*j,u=.9*j*q):(q=l/m,t=.9*k*q,u=.9*k),i.hasClass("responsive-img")?i.velocity({"max-width":t,width:l},{duration:0,queue:!1,complete:function(){i.css({left:0,top:0}).velocity({height:u,width:t,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-t/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-u/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}}):i.css("left",0).css("top",0).velocity({height:u,width:t,left:a(document).scrollLeft()+j/2-i.parent(".material-placeholder").offset().left-t/2,top:a(document).scrollTop()+k/2-i.parent(".material-placeholder").offset().top-u/2},{duration:g,queue:!1,easing:"easeOutQuad",complete:function(){f=!0}})}),a(window).scroll(function(){e&&b()}),a(document).keyup(function(a){27===a.keyCode&&f===!0&&e&&b()})}})},a(document).ready(function(){a(".materialboxed").materialbox()})}(jQuery),function(a){a.fn.parallax=function(){var b=a(window).width();return this.each(function(c){function d(c){var d;d=601>b?e.height()>0?e.height():e.children("img").height():e.height()>0?e.height():500;var f=e.children("img").first(),g=f.height(),h=g-d,i=e.offset().top+d,j=e.offset().top,k=a(window).scrollTop(),l=window.innerHeight,m=k+l,n=(m-j)/(d+l),o=Math.round(h*n);c&&f.css("display","block"),i>k&&k+l>j&&f.css("transform","translate3D(-50%,"+o+"px, 0)")}var e=a(this);e.addClass("parallax"),e.children("img").one("load",function(){d(!0)}).each(function(){this.complete&&a(this).trigger("load")}),a(window).scroll(function(){b=a(window).width(),d(!1)}),a(window).resize(function(){b=a(window).width(),d(!1)})})}}(jQuery),function(a){var b={init:function(b){var c={onShow:null};return b=a.extend(c,b),this.each(function(){var c,d,e=a(this),f=(a(window).width(),e.find("li.tab a")),g=e.width(),h=Math.max(g,e[0].scrollWidth)/f.length,i=0,j=function(a){return g-a.position().left-a.outerWidth()-e.scrollLeft()},k=function(a){return a.position().left+e.scrollLeft()};c=a(f.filter('[href="'+location.hash+'"]')),0===c.length&&(c=a(this).find("li.tab a.active").first()),0===c.length&&(c=a(this).find("li.tab a").first()),c.addClass("active"),i=f.index(c),0>i&&(i=0),void 0!==c[0]&&(d=a(c[0].hash)),e.append('
            ');var l=e.find(".indicator");e.is(":visible")&&setTimeout(function(){l.css({right:j(c)}),l.css({left:k(c)})},0),a(window).resize(function(){g=e.width(),h=Math.max(g,e[0].scrollWidth)/f.length,0>i&&(i=0),0!==h&&0!==g&&(l.css({right:j(c)}),l.css({left:k(c)}))}),f.not(c).each(function(){a(Materialize.escapeHash(this.hash)).hide()}),e.on("click","a",function(m){if(a(this).parent().hasClass("disabled"))return void m.preventDefault();if(!a(this).attr("target")){g=e.width(),h=Math.max(g,e[0].scrollWidth)/f.length,c.removeClass("active"),void 0!==d&&d.hide(),c=a(this),d=a(Materialize.escapeHash(this.hash)),f=e.find("li.tab a");c.position();c.addClass("active");var n=i;i=f.index(a(this)),0>i&&(i=0),void 0!==d&&(d.show(),"function"==typeof b.onShow&&b.onShow.call(this,d)),i-n>=0?(l.velocity({right:j(c)},{duration:300,queue:!1,easing:"easeOutQuad"}),l.velocity({left:k(c)},{duration:300,queue:!1,easing:"easeOutQuad",delay:90})):(l.velocity({left:k(c)},{duration:300,queue:!1,easing:"easeOutQuad"}),l.velocity({right:j(c)},{duration:300,queue:!1,easing:"easeOutQuad",delay:90})),m.preventDefault()}})})},select_tab:function(a){this.find('a[href="#'+a+'"]').trigger("click")}};a.fn.tabs=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tabs"):b.init.apply(this,arguments)},a(document).ready(function(){a("ul.tabs").tabs()})}(jQuery),function(a){a.fn.tooltip=function(c){var d=5,e={delay:350,tooltip:"",position:"bottom",html:!1};return"remove"===c?(this.each(function(){a("#"+a(this).attr("data-tooltip-id")).remove(),a(this).off("mouseenter.tooltip mouseleave.tooltip")}),!1):(c=a.extend(e,c),this.each(function(){var e=Materialize.guid(),f=a(this);f.attr("data-tooltip-id")&&a("#"+f.attr("data-tooltip-id")).remove(),f.attr("data-tooltip-id",e);var g,h,i,j,k,l,m=function(){g=f.attr("data-html")?"true"===f.attr("data-html"):c.html,h=f.attr("data-delay"),h=void 0===h||""===h?c.delay:h,i=f.attr("data-position"),i=void 0===i||""===i?c.position:i,j=f.attr("data-tooltip"),j=void 0===j||""===j?c.tooltip:j};m();var n=function(){var b=a('
            ');return j=g?a("").html(j):a("").text(j),b.append(j).appendTo(a("body")).attr("id",e),l=a('
            '),l.appendTo(b),b};k=n(),f.off("mouseenter.tooltip mouseleave.tooltip");var o,p=!1;f.on({"mouseenter.tooltip":function(a){var c=function(){m(),p=!0,k.velocity("stop"),l.velocity("stop"),k.css({display:"block",left:"0px",top:"0px"});var a,c,e,g=f.outerWidth(),h=f.outerHeight(),j=k.outerHeight(),n=k.outerWidth(),o="0px",q="0px",r=8,s=8;"top"===i?(a=f.offset().top-j-d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="-10px",l.css({bottom:0,left:0,borderRadius:"14px 14px 0 0",transformOrigin:"50% 100%",marginTop:j,marginLeft:n/2-l.width()/2})):"left"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left-n-d,e=b(c,a,n,j),q="-10px",l.css({top:"-7px",right:0,width:"14px",height:"14px",borderRadius:"14px 0 0 14px",transformOrigin:"95% 50%",marginTop:j/2,marginLeft:n})):"right"===i?(a=f.offset().top+h/2-j/2,c=f.offset().left+g+d,e=b(c,a,n,j),q="+10px",l.css({top:"-7px",left:0,width:"14px",height:"14px",borderRadius:"0 14px 14px 0",transformOrigin:"5% 50%",marginTop:j/2,marginLeft:"0px"})):(a=f.offset().top+f.outerHeight()+d,c=f.offset().left+g/2-n/2,e=b(c,a,n,j),o="+10px",l.css({top:0,left:0,marginLeft:n/2-l.width()/2})),k.css({top:e.y,left:e.x}),r=Math.SQRT2*n/parseInt(l.css("width")),s=Math.SQRT2*j/parseInt(l.css("height")),k.velocity({marginTop:o,marginLeft:q},{duration:350,queue:!1}).velocity({opacity:1},{duration:300,delay:50,queue:!1}),l.css({display:"block"}).velocity({opacity:1},{duration:55,delay:0,queue:!1}).velocity({scaleX:r,scaleY:s},{duration:300,delay:0,queue:!1,easing:"easeInOutQuad"})};o=setTimeout(c,h)},"mouseleave.tooltip":function(){p=!1,clearTimeout(o),setTimeout(function(){p!==!0&&(k.velocity({opacity:0,marginTop:0,marginLeft:0},{duration:225,queue:!1}),l.velocity({opacity:0,scaleX:1,scaleY:1},{duration:225,queue:!1,complete:function(){l.css("display","none"),k.css("display","none"),p=!1}}))},225)}})}))};var b=function(b,c,d,e){var f=b,g=c;return 0>f?f=4:f+d>window.innerWidth&&(f-=f+d-window.innerWidth),0>g?g=4:g+e>window.innerHeight+a(window).scrollTop&&(g-=g+e-window.innerHeight),{x:f,y:g}};a(document).ready(function(){a(".tooltipped").tooltip()})}(jQuery),function(a){"use strict";function b(a){return null!==a&&a===a.window}function c(a){return b(a)?a:9===a.nodeType&&a.defaultView}function d(a){var b,d,e={top:0,left:0},f=a&&a.ownerDocument;return b=f.documentElement,"undefined"!=typeof a.getBoundingClientRect&&(e=a.getBoundingClientRect()),d=c(f),{top:e.top+d.pageYOffset-b.clientTop,left:e.left+d.pageXOffset-b.clientLeft}}function e(a){var b="";for(var c in a)a.hasOwnProperty(c)&&(b+=c+":"+a[c]+";");return b}function f(a){if(k.allowEvent(a)===!1)return null;for(var b=null,c=a.target||a.srcElement;null!==c.parentElement;){if(!(c instanceof SVGElement||-1===c.className.indexOf("waves-effect"))){b=c;break}if(c.classList.contains("waves-effect")){b=c;break}c=c.parentElement}return b}function g(b){var c=f(b);null!==c&&(j.show(b,c),"ontouchstart"in a&&(c.addEventListener("touchend",j.hide,!1),c.addEventListener("touchcancel",j.hide,!1)),c.addEventListener("mouseup",j.hide,!1),c.addEventListener("mouseleave",j.hide,!1))}var h=h||{},i=document.querySelectorAll.bind(document),j={duration:750,show:function(a,b){if(2===a.button)return!1;var c=b||this,f=document.createElement("div");f.className="waves-ripple",c.appendChild(f);var g=d(c),h=a.pageY-g.top,i=a.pageX-g.left,k="scale("+c.clientWidth/100*10+")";"touches"in a&&(h=a.touches[0].pageY-g.top,i=a.touches[0].pageX-g.left),f.setAttribute("data-hold",Date.now()),f.setAttribute("data-scale",k),f.setAttribute("data-x",i),f.setAttribute("data-y",h);var l={top:h+"px",left:i+"px"};f.className=f.className+" waves-notransition",f.setAttribute("style",e(l)),f.className=f.className.replace("waves-notransition",""),l["-webkit-transform"]=k,l["-moz-transform"]=k,l["-ms-transform"]=k,l["-o-transform"]=k,l.transform=k,l.opacity="1",l["-webkit-transition-duration"]=j.duration+"ms",l["-moz-transition-duration"]=j.duration+"ms",l["-o-transition-duration"]=j.duration+"ms",l["transition-duration"]=j.duration+"ms",l["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",l["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f.setAttribute("style",e(l))},hide:function(a){k.touchup(a);var b=this,c=(1.4*b.clientWidth,null),d=b.getElementsByClassName("waves-ripple");if(!(d.length>0))return!1;c=d[d.length-1];var f=c.getAttribute("data-x"),g=c.getAttribute("data-y"),h=c.getAttribute("data-scale"),i=Date.now()-Number(c.getAttribute("data-hold")),l=350-i;0>l&&(l=0),setTimeout(function(){var a={top:g+"px",left:f+"px",opacity:"0","-webkit-transition-duration":j.duration+"ms","-moz-transition-duration":j.duration+"ms","-o-transition-duration":j.duration+"ms","transition-duration":j.duration+"ms","-webkit-transform":h,"-moz-transform":h,"-ms-transform":h,"-o-transform":h,transform:h};c.setAttribute("style",e(a)),setTimeout(function(){try{b.removeChild(c)}catch(a){return!1}},j.duration)},l)},wrapInput:function(a){for(var b=0;b0&&(k.touches-=1)},500):"mousedown"===a.type&&k.touches>0&&(b=!1),b},touchup:function(a){k.allowEvent(a)}};h.displayEffect=function(b){b=b||{},"duration"in b&&(j.duration=b.duration),j.wrapInput(i(".waves-effect")),"ontouchstart"in a&&document.body.addEventListener("touchstart",g,!1),document.body.addEventListener("mousedown",g,!1)},h.attach=function(b){"input"===b.tagName.toLowerCase()&&(j.wrapInput([b]),b=b.parentElement),"ontouchstart"in a&&b.addEventListener("touchstart",g,!1),b.addEventListener("mousedown",g,!1)},a.Waves=h,document.addEventListener("DOMContentLoaded",function(){h.displayEffect()},!1)}(window),Materialize.toast=function(a,b,c,d){function e(a){var b=document.createElement("div");if(b.classList.add("toast"),c)for(var e=c.split(" "),f=0,g=e.length;g>f;f++)b.classList.add(e[f]);("object"==typeof HTMLElement?a instanceof HTMLElement:a&&"object"==typeof a&&null!==a&&1===a.nodeType&&"string"==typeof a.nodeName)?b.appendChild(a):a instanceof jQuery?b.appendChild(a[0]):b.innerHTML=a;var h=new Hammer(b,{prevent_default:!1});return h.on("pan",function(a){var c=a.deltaX,d=80;b.classList.contains("panning")||b.classList.add("panning");var e=1-Math.abs(c/d);0>e&&(e=0),Vel(b,{left:c,opacity:e},{duration:50,queue:!1,easing:"easeOutQuad"})}),h.on("panend",function(a){var c=a.deltaX,e=80;Math.abs(c)>e?Vel(b,{marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),b.parentNode.removeChild(b)}}):(b.classList.remove("panning"),Vel(b,{left:0,opacity:1},{duration:300,easing:"easeOutExpo",queue:!1}))}),b}c=c||"";var f=document.getElementById("toast-container");null===f&&(f=document.createElement("div"),f.id="toast-container",document.body.appendChild(f));var g=e(a);a&&f.appendChild(g),g.style.top="35px",g.style.opacity=0,Vel(g,{top:"0px",opacity:1},{duration:300,easing:"easeOutCubic",queue:!1});var h,i=b;null!=i&&(h=setInterval(function(){null===g.parentNode&&window.clearInterval(h),g.classList.contains("panning")||(i-=20),0>=i&&(Vel(g,{opacity:0,marginTop:"-40px"},{duration:375,easing:"easeOutExpo",queue:!1,complete:function(){"function"==typeof d&&d(),this[0].parentNode.removeChild(this[0])}}),window.clearInterval(h))},20))},function(a){var b={init:function(b){var c={menuWidth:300,edge:"left",closeOnClick:!1,draggable:!0};b=a.extend(c,b),a(this).each(function(){var c=a(this),d=a("#"+c.attr("data-activates"));300!=b.menuWidth&&d.css("width",b.menuWidth);var e;b.draggable?(e=a('
            ').attr("data-sidenav",c.attr("data-activates")),a("body").append(e)):e=a(),"left"==b.edge?(d.css("transform","translateX(-100%)"),e.css({left:0})):(d.addClass("right-aligned").css("transform","translateX(100%)"),e.css({right:0})),d.hasClass("fixed")&&window.innerWidth>992&&d.css("transform","translateX(0)"),d.hasClass("fixed")&&a(window).resize(function(){window.innerWidth>992?0!==a("#sidenav-overlay").length&&h?f(!0):d.css("transform","translateX(0%)"):h===!1&&("left"===b.edge?d.css("transform","translateX(-100%)"):d.css("transform","translateX(100%)"))}),b.closeOnClick===!0&&d.on("click.itemclick","a:not(.collapsible-header)",function(){f()});var f=function(c){g=!1,h=!1,a("body").css({overflow:"",width:""}),a("#sidenav-overlay").velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),"left"===b.edge?(e.css({width:"",right:"",left:"0"}),d.velocity({translateX:"-100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(d.removeAttr("style"),d.css("width",b.menuWidth))}})):(e.css({width:"",right:"0",left:""}),d.velocity({translateX:"100%"},{duration:200,queue:!1,easing:"easeOutCubic",complete:function(){c===!0&&(d.removeAttr("style"),d.css("width",b.menuWidth))}}))},g=!1,h=!1;b.draggable&&(e.on("click",function(){h&&f()}),e.hammer({prevent_default:!1}).bind("pan",function(c){if("touch"==c.gesture.pointerType){var e=(c.gesture.direction,c.gesture.center.x),g=(c.gesture.center.y,c.gesture.velocityX,a("body")),i=a("#sidenav-overlay"),j=g.innerWidth();if(g.css("overflow","hidden"),g.width(j),0===i.length&&(i=a('
            '),i.css("opacity",0).click(function(){f()}),a("body").append(i)),"left"===b.edge&&(e>b.menuWidth?e=b.menuWidth:0>e&&(e=0)),"left"===b.edge)e=b.menuWidth/2&&(h=!0),d.css("transform","translateX("+(e-b.menuWidth)+"px)");else{e=window.innerWidth-b.menuWidth/2&&(h=!1);var k=e-b.menuWidth/2;0>k&&(k=0),d.css("transform","translateX("+k+"px)")}var l;"left"===b.edge?(l=e/b.menuWidth,i.velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"})):(l=Math.abs((e-window.innerWidth)/b.menuWidth),i.velocity({opacity:l},{duration:10,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(c){if("touch"==c.gesture.pointerType){var f=a('
            '),i=c.gesture.velocityX,j=c.gesture.center.x,k=j-b.menuWidth,l=j-b.menuWidth/2;k>0&&(k=0),0>l&&(l=0),g=!1,"left"===b.edge?h&&.3>=i||-.5>i?(0!==k&&d.velocity({translateX:[0,k]},{duration:300,queue:!1,easing:"easeOutQuad"}),f.velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),e.css({width:"50%",right:0,left:""}),h=!0):(!h||i>.3)&&(a("body").css({overflow:"",width:""}),d.velocity({translateX:[-1*b.menuWidth-10,k]},{duration:200,queue:!1,easing:"easeOutQuad"}),f.velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),e.css({width:"10px",right:"",left:0})):h&&i>=-.3||i>.5?(0!==l&&d.velocity({translateX:[0,l]},{duration:300,queue:!1,easing:"easeOutQuad"}),f.velocity({opacity:1},{duration:50,queue:!1,easing:"easeOutQuad"}),e.css({width:"50%",right:"",left:0}),h=!0):(!h||-.3>i)&&(a("body").css({overflow:"",width:""}),d.velocity({translateX:[b.menuWidth+10,l]},{duration:200,queue:!1,easing:"easeOutQuad"}),f.velocity({opacity:0},{duration:200,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}}),e.css({width:"10px",right:0,left:""}))}})),c.click(function(){if(h===!0)h=!1,g=!1,f();else{var c=a("body"),i=a('
            '),j=c.innerWidth();c.css("overflow","hidden"),c.width(j),a("body").append(e),"left"===b.edge?(e.css({width:"50%",right:0,left:""}),d.velocity({translateX:[0,-1*b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"})):(e.css({width:"50%",right:"",left:0}),d.velocity({translateX:[0,b.menuWidth]},{duration:300,queue:!1,easing:"easeOutQuad"})),i.css("opacity",0).click(function(){h=!1,g=!1,f(),i.velocity({opacity:0},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){a(this).remove()}})}),a("body").append(i),i.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){h=!0,g=!1}})}return!1})})},destroy:function(){var b=a("#sidenav-overlay"),c=a('.drag-target[data-sidenav="'+a(this).attr("data-activates")+'"]');b.trigger("click"),c.remove(),a(this).off("click"),b.remove()},show:function(){this.trigger("click")},hide:function(){a("#sidenav-overlay").trigger("click")}};a.fn.sideNav=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.sideNav"):b.init.apply(this,arguments)}}(jQuery),function(a){function b(b,c,d,e){var f=a();return a.each(g,function(a,g){if(g.height()>0){var h=g.offset().top,i=g.offset().left,j=i+g.width(),k=h+g.height(),l=!(i>c||e>j||h>d||b>k);l&&f.push(g)}}),f}function c(c){++j;var d=f.scrollTop(),e=f.scrollLeft(),g=e+f.width(),i=d+f.height(),l=b(d+k.top+c||200,g+k.right,i+k.bottom,e+k.left);a.each(l,function(a,b){var c=b.data("scrollSpy:ticks");"number"!=typeof c&&b.triggerHandler("scrollSpy:enter"),b.data("scrollSpy:ticks",j)}),a.each(h,function(a,b){var c=b.data("scrollSpy:ticks");"number"==typeof c&&c!==j&&(b.triggerHandler("scrollSpy:exit"),b.data("scrollSpy:ticks",null))}),h=l}function d(){f.trigger("scrollSpy:winSize")}function e(a,b,c){var d,e,f,g=null,h=0;c||(c={});var i=function(){h=c.leading===!1?0:l(),g=null,f=a.apply(d,e),d=e=null};return function(){var j=l();h||c.leading!==!1||(h=j);var k=b-(j-h);return d=this,e=arguments,0>=k?(clearTimeout(g),g=null,h=j,f=a.apply(d,e),d=e=null):g||c.trailing===!1||(g=setTimeout(i,k)),f}}var f=a(window),g=[],h=[],i=!1,j=0,k={top:0,right:0,bottom:0,left:0},l=Date.now||function(){return(new Date).getTime()};a.scrollSpy=function(b,d){var h={throttle:100,scrollOffset:200};d=a.extend(h,d);var j=[];b=a(b),b.each(function(b,c){g.push(a(c)),a(c).data("scrollSpy:id",b),a('a[href="#'+a(c).attr("id")+'"]').click(function(b){b.preventDefault();var c=a(Materialize.escapeHash(this.hash)).offset().top+1;a("html, body").animate({scrollTop:c-d.scrollOffset},{duration:400,queue:!1,easing:"easeOutCubic"})})}),k.top=d.offsetTop||0,k.right=d.offsetRight||0,k.bottom=d.offsetBottom||0,k.left=d.offsetLeft||0;var l=e(function(){c(d.scrollOffset)},d.throttle||100),m=function(){a(document).ready(l)};return i||(f.on("scroll",m),f.on("resize",m),i=!0),setTimeout(m,0),b.on("scrollSpy:enter",function(){j=a.grep(j,function(a){return 0!=a.height()});var b=a(this);j[0]?(a('a[href="#'+j[0].attr("id")+'"]').removeClass("active"),b.data("scrollSpy:id")");e.html(g),b.is(":visible")?e.css("width",b.width()):e.css("width",a(window).width()/2),b.css("height",e.height())}Materialize.updateTextFields=function(){var b="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(b).each(function(b,c){a(c).val().length>0||c.autofocus||void 0!==a(this).attr("placeholder")||a(c)[0].validity.badInput===!0?a(this).siblings("label").addClass("active"):a(this).siblings("label").removeClass("active")})};var c="input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea";a(document).on("change",c,function(){(0!==a(this).val().length||void 0!==a(this).attr("placeholder"))&&a(this).siblings("label").addClass("active"),validate_field(a(this))}),a(document).ready(function(){Materialize.updateTextFields()}),a(document).on("reset",function(b){var d=a(b.target);d.is("form")&&(d.find(c).removeClass("valid").removeClass("invalid"),d.find(c).each(function(){""===a(this).attr("value")&&a(this).siblings("label").removeClass("active")}),d.find("select.initialized").each(function(){var a=d.find("option[selected]").text();d.siblings("input.select-dropdown").val(a)}))}),a(document).on("focus",c,function(){a(this).siblings("label, .prefix").addClass("active")}),a(document).on("blur",c,function(){var b=a(this),c=".prefix";0===b.val().length&&b[0].validity.badInput!==!0&&void 0===b.attr("placeholder")&&(c+=", label"),b.siblings(c).removeClass("active"),validate_field(b)}),window.validate_field=function(a){var b=void 0!==a.attr("length"),c=parseInt(a.attr("length")),d=a.val().length;0===a.val().length&&a[0].validity.badInput===!1?a.hasClass("validate")&&(a.removeClass("valid"),a.removeClass("invalid")):a.hasClass("validate")&&(a.is(":valid")&&b&&c>=d||a.is(":valid")&&!b?(a.removeClass("invalid"),a.addClass("valid")):(a.removeClass("valid"),a.addClass("invalid")))};var d="input[type=radio], input[type=checkbox]";a(document).on("keyup.radio",d,function(b){if(9===b.which){a(this).addClass("tabbed");var c=a(this);return void c.one("blur",function(b){a(this).removeClass("tabbed")})}});var e=a(".hiddendiv").first();e.length||(e=a('
            '),a("body").append(e));var f=".materialize-textarea";a(f).each(function(){var c=a(this);c.val().length&&b(c)}),a("body").on("keyup keydown autoresize",f,function(){b(a(this))}),a(document).on("change",'.file-field input[type="file"]',function(){for(var b=a(this).closest(".file-field"),c=b.find("input.file-path"),d=a(this)[0].files,e=[],f=0;f
            ');a(this).after(b)});var j=".range-field";a(document).on("change",h,function(b){var c=a(this).siblings(".thumb");c.find(".value").html(a(this).val())}),a(document).on("input mousedown touchstart",h,function(b){var c=a(this).siblings(".thumb"),d=a(this).outerWidth();c.length<=0&&(c=a(''),a(this).after(c)),c.find(".value").html(a(this).val()),i=!0,a(this).addClass("active"),c.hasClass("active")||c.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),"input"!==b.type&&(g=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left,0>g?g=0:g>d&&(g=d),c.addClass("active").css("left",g)),c.find(".value").html(a(this).val())}),a(document).on("mouseup touchend",j,function(){i=!1,a(this).removeClass("active")}),a(document).on("mousemove touchmove",j,function(b){var c,d=a(this).children(".thumb");if(i){d.hasClass("active")||d.velocity({height:"30px",width:"30px",top:"-20px",marginLeft:"-15px"},{duration:300,easing:"easeOutExpo"}),c=void 0===b.pageX||null===b.pageX?b.originalEvent.touches[0].pageX-a(this).offset().left:b.pageX-a(this).offset().left;var e=a(this).outerWidth();0>c?c=0:c>e&&(c=e),d.addClass("active").css("left",c),d.find(".value").html(d.siblings(h).val())}}),a(document).on("mouseout touchleave",j,function(){if(!i){var b=a(this).children(".thumb");b.hasClass("active")&&b.velocity({height:"0",width:"0",top:"10px",marginLeft:"-6px"},{duration:100}),b.removeClass("active")}}),a.fn.autocomplete=function(b){var c={data:{}};return b=a.extend(c,b),this.each(function(){var c=a(this),d=b.data,e=c.closest(".input-field");if(!a.isEmptyObject(d)){var f=a('');e.length?e.append(f):c.after(f);var g=function(a,b){var c=b.find("img"),d=b.text().toLowerCase().indexOf(""+a.toLowerCase()),e=d+a.length-1,f=b.text().slice(0,d),g=b.text().slice(d,e+1),h=b.text().slice(e+1);b.html(""+f+""+g+""+h+""),c.length&&b.prepend(c)};c.on("keyup",function(b){if(13===b.which)return void f.find("li").first().click();var e=c.val().toLowerCase();if(f.empty(),""!==e)for(var h in d)if(d.hasOwnProperty(h)&&-1!==h.toLowerCase().indexOf(e)&&h.toLowerCase()!==e){var i=a("
          • ");d[h]?i.append(''+h+""):i.append(""+h+""),f.append(i),g(e,i)}}),f.on("click","li",function(){c.val(a(this).text().trim()),c.trigger("change"),f.empty()})}})}}),a.fn.material_select=function(b){function c(a,b,c){var e=a.indexOf(b),f=-1===e;return f?a.push(b):a.splice(e,1),c.siblings("ul.dropdown-content").find("li").eq(b).toggleClass("active"),c.find("option").eq(b).prop("selected",f),d(a,c),f}function d(a,b){for(var c="",d=0,e=a.length;e>d;d++){var f=b.find("option").eq(a[d]).text();c+=0===d?f:", "+f}""===c&&(c=b.find("option:disabled").eq(0).text()),b.siblings("input.select-dropdown").val(c)}a(this).each(function(){var d=a(this);if(!d.hasClass("browser-default")){var e=d.attr("multiple")?!0:!1,f=d.data("select-id");if(f&&(d.parent().find("span.caret").remove(),d.parent().find("input").remove(),d.unwrap(),a("ul#select-options-"+f).remove()),"destroy"===b)return void d.data("select-id",null).removeClass("initialized");var g=Materialize.guid();d.data("select-id",g);var h=a('
            ');h.addClass(d.attr("class"));var i=a(''),j=d.children("option, optgroup"),k=[],l=!1,m=d.find("option:selected").html()||d.find("option:first").html()||"",n=function(b,c,d){var e=c.is(":disabled")?"disabled ":"",f="optgroup-option"===d?"optgroup-option ":"",g=c.data("icon"),h=c.attr("class");if(g){var j="";return h&&(j=' class="'+h+'"'),"multiple"===d?i.append(a('
          • "+c.html()+"
          • ")):i.append(a('
          • "+c.html()+"
          • ")),!0}"multiple"===d?i.append(a('
          • "+c.html()+"
          • ")):i.append(a('
          • '+c.html()+"
          • "))};j.length&&j.each(function(){if(a(this).is("option"))e?n(d,a(this),"multiple"):n(d,a(this));else if(a(this).is("optgroup")){var b=a(this).children("option");i.append(a('
          • '+a(this).attr("label")+"
          • ")),b.each(function(){n(d,a(this),"optgroup-option")})}}),i.find("li:not(.optgroup)").each(function(f){a(this).click(function(g){if(!a(this).hasClass("disabled")&&!a(this).hasClass("optgroup")){ +var h=!0;e?(a('input[type="checkbox"]',this).prop("checked",function(a,b){return!b}),h=c(k,a(this).index(),d),q.trigger("focus")):(i.find("li").removeClass("active"),a(this).toggleClass("active"),q.val(a(this).text())),r(i,a(this)),d.find("option").eq(f).prop("selected",h),d.trigger("change"),"undefined"!=typeof b&&b()}g.stopPropagation()})}),d.wrap(h);var o=a('');d.is(":disabled")&&o.addClass("disabled");var p=m.replace(/"/g,"""),q=a('');d.before(q),q.before(o),q.after(i),d.is(":disabled")||q.dropdown({hover:!1,closeOnClick:!1}),d.attr("tabindex")&&a(q[0]).attr("tabindex",d.attr("tabindex")),d.addClass("initialized"),q.on({focus:function(){if(a("ul.select-dropdown").not(i[0]).is(":visible")&&a("input.select-dropdown").trigger("close"),!i.is(":visible")){a(this).trigger("open",["focus"]);var b=a(this).val(),c=i.find("li").filter(function(){return a(this).text().toLowerCase()===b.toLowerCase()})[0];r(i,c)}},click:function(a){a.stopPropagation()}}),q.on("blur",function(){e||a(this).trigger("close"),i.find("li.selected").removeClass("selected")}),i.hover(function(){l=!0},function(){l=!1}),a(window).on({click:function(){e&&(l||q.trigger("close"))}}),e&&d.find("option:selected:not(:disabled)").each(function(){var b=a(this).index();c(k,b,d),i.find("li").eq(b).find(":checkbox").prop("checked",!0)});var r=function(b,c){if(c){b.find("li.selected").removeClass("selected");var d=a(c);d.addClass("selected"),i.scrollTo(d)}},s=[],t=function(b){if(9==b.which)return void q.trigger("close");if(40==b.which&&!i.is(":visible"))return void q.trigger("open");if(13!=b.which||i.is(":visible")){b.preventDefault();var c=String.fromCharCode(b.which).toLowerCase(),d=[9,13,27,38,40];if(c&&-1===d.indexOf(b.which)){s.push(c);var f=s.join(""),g=i.find("li").filter(function(){return 0===a(this).text().toLowerCase().indexOf(f)})[0];g&&r(i,g)}if(13==b.which){var h=i.find("li.selected:not(.disabled)")[0];h&&(a(h).trigger("click"),e||q.trigger("close"))}40==b.which&&(g=i.find("li.selected").length?i.find("li.selected").next("li:not(.disabled)")[0]:i.find("li:not(.disabled)")[0],r(i,g)),27==b.which&&q.trigger("close"),38==b.which&&(g=i.find("li.selected").prev("li:not(.disabled)")[0],g&&r(i,g)),setTimeout(function(){s=[]},1e3)}};q.on("keydown",t)}})}}(jQuery),function(a){var b={init:function(b){var c={indicators:!0,height:400,transition:500,interval:6e3};return b=a.extend(c,b),this.each(function(){function c(a,b){a.hasClass("center-align")?a.velocity({opacity:0,translateY:-100},{duration:b,queue:!1}):a.hasClass("right-align")?a.velocity({opacity:0,translateX:100},{duration:b,queue:!1}):a.hasClass("left-align")&&a.velocity({opacity:0,translateX:-100},{duration:b,queue:!1})}function d(a){a>=j.length?a=0:0>a&&(a=j.length-1),k=i.find(".active").index(),k!=a&&(e=j.eq(k),$caption=e.find(".caption"),e.removeClass("active"),e.velocity({opacity:0},{duration:b.transition,queue:!1,easing:"easeOutQuad",complete:function(){j.not(".active").velocity({opacity:0,translateX:0,translateY:0},{duration:0,queue:!1})}}),c($caption,b.transition),b.indicators&&f.eq(k).removeClass("active"),j.eq(a).velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,delay:b.transition,queue:!1,easing:"easeOutQuad"}),j.eq(a).addClass("active"),b.indicators&&f.eq(a).addClass("active"))}var e,f,g,h=a(this),i=h.find("ul.slides").first(),j=i.find("> li"),k=i.find(".active").index();-1!=k&&(e=j.eq(k)),h.hasClass("fullscreen")||(b.indicators?h.height(b.height+40):h.height(b.height),i.height(b.height)),j.find(".caption").each(function(){c(a(this),0)}),j.find("img").each(function(){var b="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";a(this).attr("src")!==b&&(a(this).css("background-image","url("+a(this).attr("src")+")"),a(this).attr("src",b))}),b.indicators&&(f=a('
              '),j.each(function(c){var e=a('
            • ');e.click(function(){var c=i.parent(),e=c.find(a(this)).index();d(e),clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),f.append(e)}),h.append(f),f=h.find("ul.indicators").find("li.indicator-item")),e?e.show():(j.first().addClass("active").velocity({opacity:1},{duration:b.transition,queue:!1,easing:"easeOutQuad"}),k=0,e=j.eq(k),b.indicators&&f.eq(k).addClass("active")),e.find("img").each(function(){e.find(".caption").velocity({opacity:1,translateX:0,translateY:0},{duration:b.transition,queue:!1,easing:"easeOutQuad"})}),g=setInterval(function(){k=i.find(".active").index(),d(k+1)},b.transition+b.interval);var l=!1,m=!1,n=!1;h.hammer({prevent_default:!1}).bind("pan",function(a){if("touch"===a.gesture.pointerType){clearInterval(g);var b=a.gesture.direction,c=a.gesture.deltaX,d=a.gesture.velocityX;$curr_slide=i.find(".active"),$curr_slide.velocity({translateX:c},{duration:50,queue:!1,easing:"easeOutQuad"}),4===b&&(c>h.innerWidth()/2||-.65>d)?n=!0:2===b&&(c<-1*h.innerWidth()/2||d>.65)&&(m=!0);var e;m&&(e=$curr_slide.next(),0===e.length&&(e=j.first()),e.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"})),n&&(e=$curr_slide.prev(),0===e.length&&(e=j.last()),e.velocity({opacity:1},{duration:300,queue:!1,easing:"easeOutQuad"}))}}).bind("panend",function(a){"touch"===a.gesture.pointerType&&($curr_slide=i.find(".active"),l=!1,curr_index=i.find(".active").index(),!n&&!m||j.length<=1?$curr_slide.velocity({translateX:0},{duration:300,queue:!1,easing:"easeOutQuad"}):m?(d(curr_index+1),$curr_slide.velocity({translateX:-1*h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})):n&&(d(curr_index-1),$curr_slide.velocity({translateX:h.innerWidth()},{duration:300,queue:!1,easing:"easeOutQuad",complete:function(){$curr_slide.velocity({opacity:0,translateX:0},{duration:0,queue:!1})}})),m=!1,n=!1,clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval))}),h.on("sliderPause",function(){clearInterval(g)}),h.on("sliderStart",function(){clearInterval(g),g=setInterval(function(){k=i.find(".active").index(),j.length==k+1?k=0:k+=1,d(k)},b.transition+b.interval)}),h.on("sliderNext",function(){k=i.find(".active").index(),d(k+1)}),h.on("sliderPrev",function(){k=i.find(".active").index(),d(k-1)})})},pause:function(){a(this).trigger("sliderPause")},start:function(){a(this).trigger("sliderStart")},next:function(){a(this).trigger("sliderNext")},prev:function(){a(this).trigger("sliderPrev")}};a.fn.slider=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.tooltip"):b.init.apply(this,arguments)}}(jQuery),function(a){a(document).ready(function(){a(document).on("click.card",".card",function(b){a(this).find("> .card-reveal").length&&(a(b.target).is(a(".card-reveal .card-title"))||a(b.target).is(a(".card-reveal .card-title i"))?a(this).find(".card-reveal").velocity({translateY:0},{duration:225,queue:!1,easing:"easeInOutQuad",complete:function(){a(this).css({display:"none"})}}):(a(b.target).is(a(".card .activator"))||a(b.target).is(a(".card .activator i")))&&(a(b.target).closest(".card").css("overflow","hidden"),a(this).find(".card-reveal").css({display:"block"}).velocity("stop",!1).velocity({translateY:"-100%"},{duration:300,queue:!1,easing:"easeInOutQuad"})))})})}(jQuery),function(a){var b=!1,c={data:[],placeholder:"",secondaryPlaceholder:""};a(document).ready(function(){a(document).on("click",".chip .close",function(b){var c=a(this).closest(".chips");c.attr("data-initialized")||a(this).closest(".chip").remove()})}),a.fn.material_chip=function(d){var e=this;if(this.$el=a(this),this.$document=a(document),this.SELS={CHIPS:".chips",CHIP:".chip",INPUT:"input",DELETE:".material-icons",SELECTED_CHIP:".selected"},"data"===d)return this.$el.data("chips");var f=a.extend({},c,d);this.init=function(){var b=0;e.$el.each(function(){var c=a(this),d=Materialize.guid();f.data&&f.data instanceof Array||(f.data=[]),c.data("chips",f.data),c.attr("data-index",b),c.attr("data-initialized",!0),c.hasClass(e.SELS.CHIPS)||c.addClass("chips"),e.chips(c,d),b++})},this.handleEvents=function(){var b=e.SELS;e.$document.off("click.chips-focus",b.CHIPS).on("click.chips-focus",b.CHIPS,function(c){a(c.target).find(b.INPUT).focus()}),e.$document.off("click.chips-select",b.CHIP).on("click.chips-select",b.CHIP,function(c){a(b.CHIP).removeClass("selected"),a(this).toggleClass("selected")}),e.$document.off("keydown.chips").on("keydown.chips",function(c){if(!a(c.target).is("input, textarea")){var d,f=e.$document.find(b.CHIP+b.SELECTED_CHIP),g=f.closest(b.CHIPS),h=f.siblings(b.CHIP).length;if(f.length)if(8===c.which||46===c.which){c.preventDefault(),d=f.index(),e.deleteChip(d,g);var i=null;h>d+1?i=d:(d===h||d+1===h)&&(i=h-1),0>i&&(i=null),null!==i&&e.selectChip(i,g),h||g.find("input").focus()}else if(37===c.which){if(d=f.index()-1,0>d)return;a(b.CHIP).removeClass("selected"),e.selectChip(d,g)}else if(39===c.which){if(d=f.index()+1,a(b.CHIP).removeClass("selected"),d>h)return void g.find("input").focus();e.selectChip(d,g)}}}),e.$document.off("focusin.chips",b.CHIPS+" "+b.INPUT).on("focusin.chips",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target).closest(b.CHIPS);d.addClass("focus"),d.siblings("label, .prefix").addClass("active"),a(b.CHIP).removeClass("selected")}),e.$document.off("focusout.chips",b.CHIPS+" "+b.INPUT).on("focusout.chips",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target).closest(b.CHIPS);d.removeClass("focus"),d.data("chips").length||d.siblings("label").removeClass("active"),d.siblings(".prefix").removeClass("active")}),e.$document.off("keydown.chips-add",b.CHIPS+" "+b.INPUT).on("keydown.chips-add",b.CHIPS+" "+b.INPUT,function(c){var d=a(c.target),f=d.closest(b.CHIPS),g=f.children(b.CHIP).length;return 13===c.which?(c.preventDefault(),e.addChip({tag:d.val()},f),void d.val("")):8!==c.keyCode&&37!==c.keyCode||""!==d.val()||!g?void 0:(e.selectChip(g-1,f),void d.blur())}),e.$document.off("click.chips-delete",b.CHIPS+" "+b.DELETE).on("click.chips-delete",b.CHIPS+" "+b.DELETE,function(c){var d=a(c.target),f=d.closest(b.CHIPS),g=d.closest(b.CHIP);c.stopPropagation(),e.deleteChip(g.index(),f),f.find("input").focus()})},this.chips=function(a,b){var c="";a.data("chips").forEach(function(a){c+=e.renderChip(a)}),c+='',a.html(c),e.setPlaceholder(a);var d=a.next("label");d.length&&(d.attr("for",b),a.data("chips").length&&d.addClass("active"))},this.renderChip=function(a){if(a.tag){var b='
              '+a.tag;return a.image&&(b+=' '),b+='close',b+="
              "}},this.setPlaceholder=function(a){a.data("chips").length&&f.placeholder?a.find("input").prop("placeholder",f.placeholder):!a.data("chips").length&&f.secondaryPlaceholder&&a.find("input").prop("placeholder",f.secondaryPlaceholder)},this.isValid=function(a,b){for(var c=a.data("chips"),d=!1,e=0;e=e&&!a(this).hasClass("pinned")&&(c(a(this)),a(this).css("top",b.offset),a(this).addClass("pinned")),eb.bottom&&!a(this).hasClass("pin-bottom")&&(c(a(this)),a(this).addClass("pin-bottom"),a(this).css("top",b.bottom-g))})}var e=Materialize.guid(),f=a(this),g=a(this).offset().top;a(this).data("pushpin-id",e),d(f,a(window).scrollTop()),a(window).on("scroll."+e,function(){var c=a(window).scrollTop()+b.offset;d(f,c)})}))}}(jQuery),function(a){a(document).ready(function(){a.fn.reverse=[].reverse,a(document).on("mouseenter.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle):not(.toolbar)",function(c){var d=a(this);b(d)}),a(document).on("mouseleave.fixedActionBtn",".fixed-action-btn:not(.click-to-toggle):not(.toolbar)",function(b){var d=a(this);c(d)}),a(document).on("click.fabClickToggle",".fixed-action-btn.click-to-toggle > a",function(d){var e=a(this),f=e.parent();f.hasClass("active")?c(f):b(f)}),a(document).on("click.fabToolbar",".fixed-action-btn.toolbar > a",function(b){var c=a(this),e=c.parent();d(e)})}),a.fn.extend({openFAB:function(){b(a(this))},closeFAB:function(){c(a(this))},openToolbar:function(){d(a(this))},closeToolbar:function(){e(a(this))}});var b=function(b){var c=b;if(c.hasClass("active")===!1){var d,e,f=c.hasClass("horizontal");f===!0?e=40:d=40,c.addClass("active"),c.find("ul .btn-floating").velocity({scaleY:".4",scaleX:".4",translateY:d+"px",translateX:e+"px"},{duration:0});var g=0;c.find("ul .btn-floating").reverse().each(function(){a(this).velocity({opacity:"1",scaleX:"1",scaleY:"1",translateY:"0",translateX:"0"},{duration:80,delay:g}),g+=40})}},c=function(a){var b,c,d=a,e=d.hasClass("horizontal");e===!0?c=40:b=40,d.removeClass("active");d.find("ul .btn-floating").velocity("stop",!0),d.find("ul .btn-floating").velocity({opacity:"0",scaleX:".4",scaleY:".4",translateY:b+"px",translateX:c+"px"},{duration:80})},d=function(b){if("true"!==b.attr("data-open")){var c,d,f,g=window.innerWidth,h=window.innerHeight,i=b[0].getBoundingClientRect(),j=b.find("> a").first(),k=b.find("> ul").first(),l=a('
              '),m=j.css("background-color");j.append(l),c=i.left-g/2+i.width/2,d=h-i.bottom,f=g/l.width(),b.attr("data-origin-bottom",i.bottom),b.attr("data-origin-left",i.left),b.attr("data-origin-width",i.width),b.addClass("active"),b.attr("data-open",!0),b.css({"text-align":"center",width:"100%",bottom:0,left:0,transform:"translateX("+c+"px)",transition:"none"}),j.css({transform:"translateY("+-d+"px)",transition:"none"}),l.css({"background-color":m}),setTimeout(function(){b.css({transform:"",transition:"transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s"}),j.css({overflow:"visible",transform:"",transition:"transform .2s"}),setTimeout(function(){b.css({overflow:"hidden","background-color":m}),l.css({transform:"scale("+f+")",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"}),k.find("> li > a").css({opacity:1}),a(window).on("scroll.fabToolbarClose",function(){e(b),a(window).off("scroll.fabToolbarClose"),a(document).off("click.fabToolbarClose")}),a(document).on("click.fabToolbarClose",function(c){a(c.target).closest(k).length||(e(b),a(window).off("scroll.fabToolbarClose"),a(document).off("click.fabToolbarClose"))})},100)},0)}},e=function(a){if("true"===a.attr("data-open")){var b,c,d,e=window.innerWidth,f=window.innerHeight,g=a.attr("data-origin-width"),h=a.attr("data-origin-bottom"),i=a.attr("data-origin-left"),j=a.find("> .btn-floating").first(),k=a.find("> ul").first(),l=a.find(".fab-backdrop"),m=j.css("background-color");b=i-e/2+g/2,c=f-h,d=e/l.width(),a.removeClass("active"),a.attr("data-open",!1),a.css({"background-color":"transparent",transition:"none"}),j.css({transition:"none"}),l.css({transform:"scale(0)","background-color":m}),k.find("> li > a").css({opacity:""}),setTimeout(function(){l.remove(),a.css({"text-align":"",width:"",bottom:"",left:"",overflow:"","background-color":"",transform:"translate3d("+-b+"px,0,0)"}),j.css({overflow:"",transform:"translate3d(0,"+c+"px,0)"}),setTimeout(function(){a.css({transform:"translate3d(0,0,0)",transition:"transform .2s"}),j.css({transform:"translate3d(0,0,0)",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"})},20)},200)}}}(jQuery),function(a){Materialize.fadeInImage=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}c.css({opacity:0}),a(c).velocity({opacity:1},{duration:650,queue:!1,easing:"easeOutSine"}),a(c).velocity({opacity:1},{duration:1300,queue:!1,easing:"swing",step:function(b,c){c.start=100;var d=b/100,e=150-(100-b)/1.75;100>e&&(e=100),b>=0&&a(this).css({"-webkit-filter":"grayscale("+d+")brightness("+e+"%)",filter:"grayscale("+d+")brightness("+e+"%)"})}})},Materialize.showStaggeredList=function(b){var c;if("string"==typeof b)c=a(b);else{if("object"!=typeof b)return;c=b}var d=0;c.find("li").velocity({translateX:"-100px"},{duration:0}),c.find("li").each(function(){a(this).velocity({opacity:"1",translateX:"0"},{duration:800,delay:d,easing:[60,10]}),d+=120})},a(document).ready(function(){var b=!1,c=!1;a(".dismissable").each(function(){a(this).hammer({prevent_default:!1}).bind("pan",function(d){if("touch"===d.gesture.pointerType){var e=a(this),f=d.gesture.direction,g=d.gesture.deltaX,h=d.gesture.velocityX;e.velocity({translateX:g},{duration:50,queue:!1,easing:"easeOutQuad"}),4===f&&(g>e.innerWidth()/2||-.75>h)&&(b=!0),2===f&&(g<-1*e.innerWidth()/2||h>.75)&&(c=!0)}}).bind("panend",function(d){if(Math.abs(d.gesture.deltaX)j+g&&e.done!==!0){if("function"==typeof h)h.call(this,i);else if("string"==typeof h){var k=new Function(h);k(i)}e.done=!0}}}}},100)}}(jQuery),function(a){"function"==typeof define&&define.amd?define("picker",["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):this.Picker=a(jQuery)}(function(a){function b(f,g,i,l){function m(){return b._.node("div",b._.node("div",b._.node("div",b._.node("div",y.component.nodes(t.open),v.box),v.wrap),v.frame),v.holder)}function n(){w.data(g,y).addClass(v.input).attr("tabindex",-1).val(w.data("value")?y.get("select",u.format):f.value),u.editable||w.on("focus."+t.id+" click."+t.id,function(a){a.preventDefault(),y.$root.eq(0).focus()}).on("keydown."+t.id,q),e(f,{haspopup:!0,expanded:!1,readonly:!1,owns:f.id+"_root"})}function o(){y.$root.on({keydown:q,focusin:function(a){y.$root.removeClass(v.focused),a.stopPropagation()},"mousedown click":function(b){var c=b.target;c!=y.$root.children()[0]&&(b.stopPropagation(),"mousedown"!=b.type||a(c).is("input, select, textarea, button, option")||(b.preventDefault(),y.$root.eq(0).focus()))}}).on({focus:function(){w.addClass(v.target)},blur:function(){w.removeClass(v.target)}}).on("focus.toOpen",r).on("click","[data-pick], [data-nav], [data-clear], [data-close]",function(){var b=a(this),c=b.data(),d=b.hasClass(v.navDisabled)||b.hasClass(v.disabled),e=h();e=e&&(e.type||e.href),(d||e&&!a.contains(y.$root[0],e))&&y.$root.eq(0).focus(),!d&&c.nav?y.set("highlight",y.component.item.highlight,{nav:c.nav}):!d&&"pick"in c?y.set("select",c.pick):c.clear?y.clear().close(!0):c.close&&y.close(!0)}),e(y.$root[0],"hidden",!0)}function p(){var b;u.hiddenName===!0?(b=f.name,f.name=""):(b=["string"==typeof u.hiddenPrefix?u.hiddenPrefix:"","string"==typeof u.hiddenSuffix?u.hiddenSuffix:"_submit"],b=b[0]+f.name+b[1]),y._hidden=a('")[0],w.on("change."+t.id,function(){y._hidden.value=f.value?y.get("select",u.formatSubmit):""}),u.container?a(u.container).append(y._hidden):w.after(y._hidden)}function q(a){var b=a.keyCode,c=/^(8|46)$/.test(b);return 27==b?(y.close(),!1):void((32==b||c||!t.open&&y.component.key[b])&&(a.preventDefault(),a.stopPropagation(),c?y.clear().close():y.open()))}function r(a){a.stopPropagation(),"focus"==a.type&&y.$root.addClass(v.focused),y.open()}if(!f)return b;var s=!1,t={id:f.id||"P"+Math.abs(~~(Math.random()*new Date))},u=i?a.extend(!0,{},i.defaults,l):l||{},v=a.extend({},b.klasses(),u.klass),w=a(f),x=function(){return this.start()},y=x.prototype={constructor:x,$node:w,start:function(){return t&&t.start?y:(t.methods={},t.start=!0,t.open=!1,t.type=f.type,f.autofocus=f==h(),f.readOnly=!u.editable,f.id=f.id||t.id,"text"!=f.type&&(f.type="text"),y.component=new i(y,u),y.$root=a(b._.node("div",m(),v.picker,'id="'+f.id+'_root" tabindex="0"')),o(),u.formatSubmit&&p(),n(),u.container?a(u.container).append(y.$root):w.after(y.$root),y.on({start:y.component.onStart,render:y.component.onRender,stop:y.component.onStop,open:y.component.onOpen,close:y.component.onClose,set:y.component.onSet}).on({start:u.onStart,render:u.onRender,stop:u.onStop,open:u.onOpen,close:u.onClose,set:u.onSet}),s=c(y.$root.children()[0]),f.autofocus&&y.open(),y.trigger("start").trigger("render"))},render:function(a){return a?y.$root.html(m()):y.$root.find("."+v.box).html(y.component.nodes(t.open)),y.trigger("render")},stop:function(){return t.start?(y.close(),y._hidden&&y._hidden.parentNode.removeChild(y._hidden),y.$root.remove(),w.removeClass(v.input).removeData(g),setTimeout(function(){w.off("."+t.id)},0),f.type=t.type,f.readOnly=!1,y.trigger("stop"),t.methods={},t.start=!1,y):y},open:function(c){return t.open?y:(w.addClass(v.active),e(f,"expanded",!0),setTimeout(function(){y.$root.addClass(v.opened),e(y.$root[0],"hidden",!1)},0),c!==!1&&(t.open=!0,s&&k.css("overflow","hidden").css("padding-right","+="+d()),y.$root.eq(0).focus(),j.on("click."+t.id+" focusin."+t.id,function(a){var b=a.target;b!=f&&b!=document&&3!=a.which&&y.close(b===y.$root.children()[0])}).on("keydown."+t.id,function(c){var d=c.keyCode,e=y.component.key[d],f=c.target;27==d?y.close(!0):f!=y.$root[0]||!e&&13!=d?a.contains(y.$root[0],f)&&13==d&&(c.preventDefault(),f.click()):(c.preventDefault(),e?b._.trigger(y.component.key.go,y,[b._.trigger(e)]):y.$root.find("."+v.highlighted).hasClass(v.disabled)||y.set("select",y.component.item.highlight).close())})),y.trigger("open"))},close:function(a){return a&&(y.$root.off("focus.toOpen").eq(0).focus(),setTimeout(function(){y.$root.on("focus.toOpen",r)},0)),w.removeClass(v.active),e(f,"expanded",!1),setTimeout(function(){y.$root.removeClass(v.opened+" "+v.focused),e(y.$root[0],"hidden",!0)},0),t.open?(t.open=!1,s&&k.css("overflow","").css("padding-right","-="+d()),j.off("."+t.id),y.trigger("close")):y},clear:function(a){return y.set("clear",null,a)},set:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(d=g&&a.isPlainObject(c)?c:d||{},b){g||(h[b]=c);for(e in h)f=h[e],e in y.component.item&&(void 0===f&&(f=null),y.component.set(e,f,d)),("select"==e||"clear"==e)&&w.val("clear"==e?"":y.get(e,u.format)).trigger("change");y.render()}return d.muted?y:y.trigger("set",h)},get:function(a,c){if(a=a||"value",null!=t[a])return t[a];if("valueSubmit"==a){if(y._hidden)return y._hidden.value;a="value"}if("value"==a)return f.value;if(a in y.component.item){if("string"==typeof c){var d=y.component.get(a);return d?b._.trigger(y.component.formats.toString,y.component,[c,d]):""}return y.component.get(a)}},on:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(b){g||(h[b]=c);for(e in h)f=h[e],d&&(e="_"+e),t.methods[e]=t.methods[e]||[],t.methods[e].push(f)}return y},off:function(){var a,b,c=arguments;for(a=0,namesCount=c.length;a').appendTo("body"),c=b[0].offsetWidth;b.css("overflow","scroll");var d=a('
              ').appendTo(b),e=d[0].offsetWidth;return b.remove(),c-e}function e(b,c,d){if(a.isPlainObject(c))for(var e in c)f(b,e,c[e]);else f(b,c,d)}function f(a,b,c){a.setAttribute(("role"==b?"":"aria-")+b,c)}function g(b,c){a.isPlainObject(b)||(b={attribute:c}),c="";for(var d in b){var e=("role"==d?"":"aria-")+d,f=b[d];c+=null==f?"":e+'="'+b[d]+'"'}return c}function h(){try{return document.activeElement}catch(a){}}var i=a(window),j=a(document),k=a(document.documentElement);return b.klasses=function(a){return a=a||"picker",{picker:a,opened:a+"--opened",focused:a+"--focused",input:a+"__input",active:a+"__input--active",target:a+"__input--target",holder:a+"__holder",frame:a+"__frame",wrap:a+"__wrap",box:a+"__box"}},b._={group:function(a){for(var c,d="",e=b._.trigger(a.min,a);e<=b._.trigger(a.max,a,[e]);e+=a.i)c=b._.trigger(a.item,a,[e]),d+=b._.node(a.node,c[0],c[1],c[2]);return d},node:function(b,c,d,e){return c?(c=a.isArray(c)?c.join(""):c,d=d?' class="'+d+'"':"",e=e?" "+e:"","<"+b+d+e+">"+c+""):""},lead:function(a){return(10>a?"0":"")+a},trigger:function(a,b,c){return"function"==typeof a?a.apply(b,c||[]):a},digits:function(a){return/\d/.test(a[1])?2:1},isDate:function(a){return{}.toString.call(a).indexOf("Date")>-1&&this.isInteger(a.getDate())},isInteger:function(a){return{}.toString.call(a).indexOf("Number")>-1&&a%1===0},ariaAttr:g},b.extend=function(c,d){a.fn[c]=function(e,f){var g=this.data(c);return"picker"==e?g:g&&"string"==typeof e?b._.trigger(g[e],g,[f]):this.each(function(){var f=a(this);f.data(c)||new b(this,c,d,e)})},a.fn[c].defaults=d.defaults},b}),function(a){"function"==typeof define&&define.amd?define(["picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0],e=d.value,f=a.$node.data("value"),g=f||e,h=f?b.formatSubmit:b.format,i=function(){return d.currentStyle?"rtl"==d.currentStyle.direction:"rtl"==getComputedStyle(a.$root[0]).direction};c.settings=b,c.$node=a.$node,c.queue={min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse navigate create validate",view:"parse create validate viewset",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return a[0]===!0?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),g?c.set("select",g,{format:h}):c.set("select",null).set("highlight",c.item.now),c.key={40:7,38:-7,39:function(){return i()?-1:1},37:function(){return i()?1:-1},go:function(a){var b=c.item.highlight,d=new Date(b.year,b.month,b.date+a);c.set("highlight",d,{interval:a}),this.render()}},a.on("render",function(){a.$root.find("."+b.klass.selectMonth).on("change",function(){var c=this.value;c&&(a.set("highlight",[a.get("view").year,c,a.get("highlight").date]),a.$root.find("."+b.klass.selectMonth).trigger("focus"))}),a.$root.find("."+b.klass.selectYear).on("change",function(){var c=this.value;c&&(a.set("highlight",[c,a.get("view").month,a.get("highlight").date]),a.$root.find("."+b.klass.selectYear).trigger("focus"))})},1).on("open",function(){var d="";c.disabled(c.get("now"))&&(d=":not(."+b.klass.buttonToday+")"),a.$root.find("button"+d+", select").attr("disabled",!1)},1).on("close",function(){a.$root.find("button, select").attr("disabled",!0)},1)}var d=7,e=6,f=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",e.select,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",e.highlight,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,d){var e,g=this;return c=void 0===c?a:c,c==-(1/0)||c==1/0?e=c:b.isPlainObject(c)&&f.isInteger(c.pick)?c=c.obj:b.isArray(c)?(c=new Date(c[0],c[1],c[2]),c=f.isDate(c)?c:g.create().obj):c=f.isInteger(c)||f.isDate(c)?g.normalize(new Date(c),d):g.now(a,c,d),{year:e||c.getFullYear(),month:e||c.getMonth(),date:e||c.getDate(),day:e||c.getDay(),obj:e||c,pick:e||c.getTime()}},c.prototype.createRange=function(a,c){var d=this,e=function(a){return a===!0||b.isArray(a)||f.isDate(a)?d.create(a):a};return f.isInteger(a)||(a=e(a)),f.isInteger(c)||(c=e(c)),f.isInteger(a)&&b.isPlainObject(c)?a=[c.year,c.month,c.date+a]:f.isInteger(c)&&b.isPlainObject(a)&&(c=[a.year,a.month,a.date+c]),{from:e(a),to:e(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b,c){return b=new Date,c&&c.rel&&b.setDate(b.getDate()+c.rel),this.normalize(b,c)},c.prototype.navigate=function(a,c,d){var e,f,g,h,i=b.isArray(c),j=b.isPlainObject(c),k=this.item.view;if(i||j){for(j?(f=c.year,g=c.month,h=c.date):(f=+c[0],g=+c[1],h=+c[2]),d&&d.nav&&k&&k.month!==g&&(f=k.year,g=k.month),e=new Date(f,g+(d&&d.nav?d.nav:0),1),f=e.getFullYear(),g=e.getMonth();new Date(f,g,h).getMonth()!==g;)h-=1;c=[f,g,h]}return c},c.prototype.normalize=function(a){return a.setHours(0,0,0,0),a},c.prototype.measure=function(a,b){var c=this;return b?"string"==typeof b?b=c.parse(a,b):f.isInteger(b)&&(b=c.now(a,b,{rel:b})):b="min"==a?-(1/0):1/0,b},c.prototype.viewset=function(a,b){return this.create([b.year,b.month,1])},c.prototype.validate=function(a,c,d){var e,g,h,i,j=this,k=c,l=d&&d.interval?d.interval:1,m=-1===j.item.enable,n=j.item.min,o=j.item.max,p=m&&j.item.disable.filter(function(a){if(b.isArray(a)){var d=j.create(a).pick;dc.pick&&(g=!0)}return f.isInteger(a)}).length;if((!d||!d.nav)&&(!m&&j.disabled(c)||m&&j.disabled(c)&&(p||e||g)||!m&&(c.pick<=n.pick||c.pick>=o.pick)))for(m&&!p&&(!g&&l>0||!e&&0>l)&&(l*=-1);j.disabled(c)&&(Math.abs(l)>1&&(c.monthk.month)&&(c=k,l=l>0?1:-1),c.pick<=n.pick?(h=!0,l=1,c=j.create([n.year,n.month,n.date+(c.pick===n.pick?0:-1)])):c.pick>=o.pick&&(i=!0,l=-1,c=j.create([o.year,o.month,o.date+(c.pick===o.pick?0:1)])),!h||!i);)c=j.create([c.year,c.month,c.date+l]);return c},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return f.isInteger(d)?a.day===(c.settings.firstDay?d:d-1)%7:b.isArray(d)||f.isDate(d)?a.pick===c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0; +});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[3]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pickc.item.max.pick},c.prototype.parse=function(a,b,c){var d=this,e={};return b&&"string"==typeof b?(c&&c.format||(c=c||{},c.format=d.settings.format),d.formats.toArray(c.format).map(function(a){var c=d.formats[a],g=c?f.trigger(c,d,[b,e]):a.replace(/^!/,"").length;c&&(e[a]=b.substr(0,g)),b=b.substr(g)}),[e.yyyy||e.yy,+(e.mm||e.m)-1,e.dd||e.d]):b},c.prototype.formats=function(){function a(a,b,c){var d=a.match(/\w+/)[0];return c.mm||c.m||(c.m=b.indexOf(d)+1),d.length}function b(a){return a.match(/\w+/)[0].length}return{d:function(a,b){return a?f.digits(a):b.date},dd:function(a,b){return a?2:f.lead(b.date)},ddd:function(a,c){return a?b(a):this.settings.weekdaysShort[c.day]},dddd:function(a,c){return a?b(a):this.settings.weekdaysFull[c.day]},m:function(a,b){return a?f.digits(a):b.month+1},mm:function(a,b){return a?2:f.lead(b.month+1)},mmm:function(b,c){var d=this.settings.monthsShort;return b?a(b,d,c):d[c.month]},mmmm:function(b,c){var d=this.settings.monthsFull;return b?a(b,d,c):d[c.month]},yy:function(a,b){return a?2:(""+b.year).slice(2)},yyyy:function(a,b){return a?4:b.year},toArray:function(a){return a.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return f.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}}}(),c.prototype.isDateExact=function(a,c){var d=this;return f.isInteger(a)&&f.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(f.isDate(a)||b.isArray(a))&&(f.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:b.isPlainObject(a)&&b.isPlainObject(c)?d.isDateExact(a.from,c.from)&&d.isDateExact(a.to,c.to):!1},c.prototype.isDateOverlap=function(a,c){var d=this,e=d.settings.firstDay?1:0;return f.isInteger(a)&&(f.isDate(c)||b.isArray(c))?(a=a%7+e,a===d.create(c).day+1):f.isInteger(c)&&(f.isDate(a)||b.isArray(a))?(c=c%7+e,c===d.create(a).day+1):b.isPlainObject(a)&&b.isPlainObject(c)?d.overlapRanges(a,c):!1},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,e=d.item.disable.slice(0);return"flip"==c?d.flipEnable():c===!1?(d.flipEnable(1),e=[]):c===!0?(d.flipEnable(-1),e=[]):c.map(function(a){for(var c,g=0;gi;i+=1){if(h=e[i],d.isDateExact(h,a)){c=e[i]=null,j=!0;break}if(d.isDateOverlap(h,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[3]||c.push("inverted")):f.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;g>i;i+=1)if(d.isDateExact(e[i],a)){e[i]=null;break}if(j)for(i=0;g>i;i+=1)if(d.isDateOverlap(e[i],a)){e[i]=null;break}c&&e.push(c)}),e.filter(function(a){return null!=a})},c.prototype.nodes=function(a){var b=this,c=b.settings,g=b.item,h=g.now,i=g.select,j=g.highlight,k=g.view,l=g.disable,m=g.min,n=g.max,o=function(a,b){return c.firstDay&&(a.push(a.shift()),b.push(b.shift())),f.node("thead",f.node("tr",f.group({min:0,max:d-1,i:1,node:"th",item:function(d){return[a[d],c.klass.weekdays,'scope=col title="'+b[d]+'"']}})))}((c.showWeekdaysFull?c.weekdaysFull:c.weekdaysLetter).slice(0),c.weekdaysFull.slice(0)),p=function(a){return f.node("div"," ",c.klass["nav"+(a?"Next":"Prev")]+(a&&k.year>=n.year&&k.month>=n.month||!a&&k.year<=m.year&&k.month<=m.month?" "+c.klass.navDisabled:""),"data-nav="+(a||-1)+" "+f.ariaAttr({role:"button",controls:b.$node[0].id+"_table"})+' title="'+(a?c.labelMonthNext:c.labelMonthPrev)+'"')},q=function(d){var e=c.showMonthsShort?c.monthsShort:c.monthsFull;return"short_months"==d&&(e=c.monthsShort),c.selectMonths&&void 0==d?f.node("select",f.group({min:0,max:11,i:1,node:"option",item:function(a){return[e[a],0,"value="+a+(k.month==a?" selected":"")+(k.year==m.year&&an.month?" disabled":"")]}}),c.klass.selectMonth+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelMonthSelect+'"'):"short_months"==d?null!=i?f.node("div",e[i.month]):f.node("div",e[k.month]):f.node("div",e[k.month],c.klass.month)},r=function(d){var e=k.year,g=c.selectYears===!0?5:~~(c.selectYears/2);if(g){var h=m.year,i=n.year,j=e-g,l=e+g;if(h>j&&(l+=h-j,j=h),l>i){var o=j-h,p=l-i;j-=o>p?p:o,l=i}if(c.selectYears&&void 0==d)return f.node("select",f.group({min:j,max:l,i:1,node:"option",item:function(a){return[a,0,"value="+a+(e==a?" selected":"")]}}),c.klass.selectYear+" browser-default",(a?"":"disabled")+" "+f.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelYearSelect+'"')}return"raw"==d?f.node("div",e):f.node("div",e,c.klass.year)};return createDayLabel=function(){return null!=i?f.node("div",i.date):f.node("div",h.date)},createWeekdayLabel=function(){var a;a=null!=i?i.day:h.day;var b=c.weekdaysFull[a];return b},f.node("div",f.node("div",createWeekdayLabel(),"picker__weekday-display")+f.node("div",q("short_months"),c.klass.month_display)+f.node("div",createDayLabel(),c.klass.day_display)+f.node("div",r("raw"),c.klass.year_display),c.klass.date_display)+f.node("div",f.node("div",(c.selectYears?q()+r():q()+r())+p()+p(1),c.klass.header)+f.node("table",o+f.node("tbody",f.group({min:0,max:e-1,i:1,node:"tr",item:function(a){var e=c.firstDay&&0===b.create([k.year,k.month,1]).day?-7:0;return[f.group({min:d*a-k.day+e+1,max:function(){return this.min+d-1},i:1,node:"td",item:function(a){a=b.create([k.year,k.month,a+(c.firstDay?1:0)]);var d=i&&i.pick==a.pick,e=j&&j.pick==a.pick,g=l&&b.disabled(a)||a.pickn.pick,o=f.trigger(b.formats.toString,b,[c.format,a]);return[f.node("div",a.date,function(b){return b.push(k.month==a.month?c.klass.infocus:c.klass.outfocus),h.pick==a.pick&&b.push(c.klass.now),d&&b.push(c.klass.selected),e&&b.push(c.klass.highlighted),g&&b.push(c.klass.disabled),b.join(" ")}([c.klass.day]),"data-pick="+a.pick+" "+f.ariaAttr({role:"gridcell",label:o,selected:d&&b.$node.val()===o?!0:null,activedescendant:e?!0:null,disabled:g?!0:null})),"",f.ariaAttr({role:"presentation"})]}})]}})),c.klass.table,'id="'+b.$node[0].id+'_table" '+f.ariaAttr({role:"grid",controls:b.$node[0].id,readonly:!0})),c.klass.calendar_container)+f.node("div",f.node("button",c.today,"btn-flat picker__today","type=button data-pick="+h.pick+(a&&!b.disabled(h)?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.clear,"btn-flat picker__clear","type=button data-clear=1"+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id}))+f.node("button",c.close,"btn-flat picker__close","type=button data-close=true "+(a?"":" disabled")+" "+f.ariaAttr({controls:b.$node[0].id})),c.klass.footer)},c.defaults=function(a){return{labelMonthNext:"Next month",labelMonthPrev:"Previous month",labelMonthSelect:"Select a month",labelYearSelect:"Select a year",monthsFull:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdaysFull:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysLetter:["S","M","T","W","T","F","S"],today:"Today",clear:"Clear",close:"Close",format:"d mmmm, yyyy",klass:{table:a+"table",header:a+"header",date_display:a+"date-display",day_display:a+"day-display",month_display:a+"month-display",year_display:a+"year-display",calendar_container:a+"calendar-container",navPrev:a+"nav--prev",navNext:a+"nav--next",navDisabled:a+"nav--disabled",month:a+"month",year:a+"year",selectMonth:a+"select--month",selectYear:a+"select--year",weekdays:a+"weekday",day:a+"day",disabled:a+"day--disabled",selected:a+"day--selected",highlighted:a+"day--highlighted",now:a+"day--today",infocus:a+"day--infocus",outfocus:a+"day--outfocus",footer:a+"footer",buttonClear:a+"button--clear",buttonToday:a+"button--today",buttonClose:a+"button--close"}}}(a.klasses().picker+"__"),a.extend("pickadate",c)}),function(a){function b(){var b=+a(this).attr("length"),c=+a(this).val().length,d=b>=c;a(this).parent().find('span[class="character-counter"]').html(c+"/"+b),e(d,a(this))}function c(b){var c=b.parent().find('span[class="character-counter"]');c.length||(c=a("").addClass("character-counter").css("float","right").css("font-size","12px").css("height",1),b.parent().append(c))}function d(){a(this).parent().find('span[class="character-counter"]').html("")}function e(a,b){var c=b.hasClass("invalid");a&&c?b.removeClass("invalid"):a||c||(b.removeClass("valid"),b.addClass("invalid"))}a.fn.characterCounter=function(){return this.each(function(){var e=a(this),f=e.parent().find('span[class="character-counter"]');if(!f.length){var g=void 0!==e.attr("length");g&&(e.on("input",b),e.on("focus",b),e.on("blur",d),c(e))}})},a(document).ready(function(){a("input, textarea").characterCounter()})}(jQuery),function(a){var b={init:function(b){var c={time_constant:200,dist:-100,shift:0,padding:0,full_width:!1,indicators:!1,no_wrap:!1};return b=a.extend(c,b),this.each(function(){function c(){"undefined"!=typeof window.ontouchstart&&(H[0].addEventListener("touchstart",l),H[0].addEventListener("touchmove",m),H[0].addEventListener("touchend",n)),H[0].addEventListener("mousedown",l),H[0].addEventListener("mousemove",m),H[0].addEventListener("mouseup",n),H[0].addEventListener("mouseleave",n),H[0].addEventListener("click",j)}function d(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientX:a.clientX}function e(a){return a.targetTouches&&a.targetTouches.length>=1?a.targetTouches[0].clientY:a.clientY}function f(a){return a>=t?a%t:0>a?f(t+a%t):a}function g(a){var c,d,e,g,h,i,j;if(p="number"==typeof a?a:p,q=Math.floor((p+s/2)/s),e=p-q*s,g=0>e?1:-1,h=-g*e*2/s,d=t>>1,b.full_width?j="translateX(0)":(j="translateX("+(H[0].clientWidth-item_width)/2+"px) ",j+="translateY("+(H[0].clientHeight-item_width)/2+"px)"),I){var k=q%t,l=G.find(".indicator-item.active");l.index()!==k&&(l.removeClass("active"),G.find(".indicator-item").eq(k).addClass("active"))}for((!b.no_wrap||q>=0&&t>q)&&(i=o[f(q)],i.style[A]=j+" translateX("+-e/2+"px) translateX("+g*b.shift*h*c+"px) translateZ("+b.dist*h+"px)",i.style.zIndex=0,b.full_width?tweenedOpacity=1:tweenedOpacity=1-.2*h,i.style.opacity=tweenedOpacity,i.style.display="block"),c=1;d>=c;++c)b.full_width?(zTranslation=b.dist,tweenedOpacity=c===d&&0>e?1-h:1):(zTranslation=b.dist*(2*c+h*g),tweenedOpacity=1-.2*(2*c+h*g)),(!b.no_wrap||t>q+c)&&(i=o[f(q+c)],i.style[A]=j+" translateX("+(b.shift+(s*c-e)/2)+"px) translateZ("+zTranslation+"px)",i.style.zIndex=-c,i.style.opacity=tweenedOpacity,i.style.display="block"),b.full_width?(zTranslation=b.dist,tweenedOpacity=c===d&&e>0?1-h:1):(zTranslation=b.dist*(2*c-h*g),tweenedOpacity=1-.2*(2*c-h*g)),(!b.no_wrap||q-c>=0)&&(i=o[f(q-c)],i.style[A]=j+" translateX("+(-b.shift+(-s*c-e)/2)+"px) translateZ("+zTranslation+"px)",i.style.zIndex=-c,i.style.opacity=tweenedOpacity,i.style.display="block");(!b.no_wrap||q>=0&&t>q)&&(i=o[f(q)],i.style[A]=j+" translateX("+-e/2+"px) translateX("+g*b.shift*h+"px) translateZ("+b.dist*h+"px)",i.style.zIndex=0,b.full_width?tweenedOpacity=1:tweenedOpacity=1-.2*h,i.style.opacity=tweenedOpacity,i.style.display="block")}function h(){var a,b,c,d;a=Date.now(),b=a-C,C=a,c=p-B,B=p,d=1e3*c/(1+b),z=.8*d+.2*z}function i(){var a,c;w&&(a=Date.now()-C,c=w*Math.exp(-a/b.time_constant),c>2||-2>c?(g(x-c),requestAnimationFrame(i)):g(x))}function j(c){if(E)return c.preventDefault(),c.stopPropagation(),!1;if(!b.full_width){var d=a(c.target).closest(".carousel-item").index(),e=q%t-d;0!==e&&(c.preventDefault(),c.stopPropagation()),k(d)}}function k(a){var c=q%t-a;b.no_wrap||(0>c?Math.abs(c+t)0&&Math.abs(c-t)c?H.trigger("carouselNext",[Math.abs(c)]):c>0&&H.trigger("carouselPrev",[c])}function l(a){r=!0,E=!1,F=!1,u=d(a),v=e(a),z=w=0,B=p,C=Date.now(),clearInterval(D),D=setInterval(h,100)}function m(a){var b,c,f;if(r)if(b=d(a),y=e(a),c=u-b,f=Math.abs(v-y),30>f&&!F)(c>2||-2>c)&&(E=!0,u=b,g(p+c));else{if(E)return a.preventDefault(),a.stopPropagation(),!1;F=!0}return E?(a.preventDefault(),a.stopPropagation(),!1):void 0}function n(a){return r?(r=!1,clearInterval(D),x=p,(z>10||-10>z)&&(w=.9*z,x=p+w),x=Math.round(x/s)*s,b.no_wrap&&(x>=s*(t-1)?x=s*(t-1):0>x&&(x=0)),w=x-p,C=Date.now(),requestAnimationFrame(i),E&&(a.preventDefault(),a.stopPropagation()),!1):void 0}var o,p,q,r,s,t,u,v,w,x,z,A,B,C,D,E,F,G=a('
                '),H=a(this),I=H.attr("data-indicators")||b.indicators;if(H.hasClass("initialized"))return a(this).trigger("carouselNext",[1e-6]),!0;if(b.full_width){b.dist=0;var J=H.find(".carousel-item img").first();J.length?imageHeight=J.on("load",function(){H.css("height",a(this).height())}):(imageHeight=H.find(".carousel-item").first().height(),H.css("height",imageHeight)),I&&H.find(".carousel-fixed-item").addClass("with-indicators")}H.addClass("initialized"),r=!1,p=x=0,o=[],item_width=H.find(".carousel-item").first().innerWidth(),s=2*item_width+b.padding,H.find(".carousel-item").each(function(b){if(o.push(a(this)[0]),I){var c=a('
              • ');0===b&&c.addClass("active"),c.click(function(){var b=a(this).index();k(b)}),G.append(c)}}),I&&H.append(G),t=o.length,A="transform",["webkit","Moz","O","ms"].every(function(a){var b=a+"Transform";return"undefined"!=typeof document.body.style[b]?(A=b,!1):!0}),window.onresize=g,c(),g(p),a(this).on("carouselNext",function(a,b){void 0===b&&(b=1),x=p+s*b,p!==x&&(w=x-p,C=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselPrev",function(a,b){void 0===b&&(b=1),x=p-s*b,p!==x&&(w=x-p,C=Date.now(),requestAnimationFrame(i))}),a(this).on("carouselSet",function(a,b){void 0===b&&(b=0),k(b)})})},next:function(b){a(this).trigger("carouselNext",[b])},prev:function(b){a(this).trigger("carouselPrev",[b])},set:function(b){a(this).trigger("carouselSet",[b])}};a.fn.carousel=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method "+c+" does not exist on jQuery.carousel"):b.init.apply(this,arguments)}}(jQuery); \ No newline at end of file diff --git a/assets/libs/materialize/js/buttons.js b/assets/libs/materialize/js/buttons.js new file mode 100644 index 0000000..b15a04c --- /dev/null +++ b/assets/libs/materialize/js/buttons.js @@ -0,0 +1,267 @@ +(function ($) { + $(document).ready(function() { + + // jQuery reverse + $.fn.reverse = [].reverse; + + // Hover behaviour: make sure this doesn't work on .click-to-toggle FABs! + $(document).on('mouseenter.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + openFABMenu($this); + }); + $(document).on('mouseleave.fixedActionBtn', '.fixed-action-btn:not(.click-to-toggle):not(.toolbar)', function(e) { + var $this = $(this); + closeFABMenu($this); + }); + + // Toggle-on-click behaviour. + $(document).on('click.fabClickToggle', '.fixed-action-btn.click-to-toggle > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + if ($menu.hasClass('active')) { + closeFABMenu($menu); + } else { + openFABMenu($menu); + } + }); + + // Toolbar transition behaviour. + $(document).on('click.fabToolbar', '.fixed-action-btn.toolbar > a', function(e) { + var $this = $(this); + var $menu = $this.parent(); + FABtoToolbar($menu); + }); + + }); + + $.fn.extend({ + openFAB: function() { + openFABMenu($(this)); + }, + closeFAB: function() { + closeFABMenu($(this)); + }, + openToolbar: function() { + FABtoToolbar($(this)); + }, + closeToolbar: function() { + toolbarToFAB($(this)); + } + }); + + + var openFABMenu = function (btn) { + var $this = btn; + if ($this.hasClass('active') === false) { + + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.addClass('active'); + $this.find('ul .btn-floating').velocity( + { scaleY: ".4", scaleX: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 0 }); + + var time = 0; + $this.find('ul .btn-floating').reverse().each( function () { + $(this).velocity( + { opacity: "1", scaleX: "1", scaleY: "1", translateY: "0", translateX: '0'}, + { duration: 80, delay: time }); + time += 40; + }); + } + }; + + var closeFABMenu = function (btn) { + var $this = btn; + // Get direction option + var horizontal = $this.hasClass('horizontal'); + var offsetY, offsetX; + + if (horizontal === true) { + offsetX = 40; + } else { + offsetY = 40; + } + + $this.removeClass('active'); + var time = 0; + $this.find('ul .btn-floating').velocity("stop", true); + $this.find('ul .btn-floating').velocity( + { opacity: "0", scaleX: ".4", scaleY: ".4", translateY: offsetY + 'px', translateX: offsetX + 'px'}, + { duration: 80 } + ); + }; + + + /** + * Transform FAB into toolbar + * @param {Object} object jQuery object + */ + var FABtoToolbar = function(btn) { + if (btn.attr('data-open') === "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnRect = btn[0].getBoundingClientRect(); + var anchor = btn.find('> a').first(); + var menu = btn.find('> ul').first(); + var backdrop = $('
                '); + var fabColor = anchor.css('background-color'); + anchor.append(backdrop); + + offsetX = btnRect.left - (windowWidth / 2) + (btnRect.width / 2); + offsetY = windowHeight - btnRect.bottom; + scaleFactor = windowWidth / backdrop.width(); + btn.attr('data-origin-bottom', btnRect.bottom); + btn.attr('data-origin-left', btnRect.left); + btn.attr('data-origin-width', btnRect.width); + + // Set initial state + btn.addClass('active'); + btn.attr('data-open', true); + btn.css({ + 'text-align': 'center', + width: '100%', + bottom: 0, + left: 0, + transform: 'translateX(' + offsetX + 'px)', + transition: 'none' + }); + anchor.css({ + transform: 'translateY(' + -offsetY + 'px)', + transition: 'none' + }); + backdrop.css({ + 'background-color': fabColor + }); + + + setTimeout(function() { + btn.css({ + transform: '', + transition: 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s' + }); + anchor.css({ + overflow: 'visible', + transform: '', + transition: 'transform .2s' + }); + + setTimeout(function() { + btn.css({ + overflow: 'hidden', + 'background-color': fabColor + }); + backdrop.css({ + transform: 'scale(' + scaleFactor + ')', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + menu.find('> li > a').css({ + opacity: 1 + }); + + // Scroll to close. + $(window).on('scroll.fabToolbarClose', function() { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + }); + + $(document).on('click.fabToolbarClose', function(e) { + if (!$(e.target).closest(menu).length) { + toolbarToFAB(btn); + $(window).off('scroll.fabToolbarClose'); + $(document).off('click.fabToolbarClose'); + } + }); + }, 100); + }, 0); + }; + + /** + * Transform toolbar back into FAB + * @param {Object} object jQuery object + */ + var toolbarToFAB = function(btn) { + if (btn.attr('data-open') !== "true") { + return; + } + + var offsetX, offsetY, scaleFactor; + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var btnWidth = btn.attr('data-origin-width'); + var btnBottom = btn.attr('data-origin-bottom'); + var btnLeft = btn.attr('data-origin-left'); + var anchor = btn.find('> .btn-floating').first(); + var menu = btn.find('> ul').first(); + var backdrop = btn.find('.fab-backdrop'); + var fabColor = anchor.css('background-color'); + + offsetX = btnLeft - (windowWidth / 2) + (btnWidth / 2); + offsetY = windowHeight - btnBottom; + scaleFactor = windowWidth / backdrop.width(); + + + // Hide backdrop + btn.removeClass('active'); + btn.attr('data-open', false); + btn.css({ + 'background-color': 'transparent', + transition: 'none' + }); + anchor.css({ + transition: 'none' + }); + backdrop.css({ + transform: 'scale(0)', + 'background-color': fabColor + }); + menu.find('> li > a').css({ + opacity: '' + }); + + setTimeout(function() { + backdrop.remove(); + + // Set initial state. + btn.css({ + 'text-align': '', + width: '', + bottom: '', + left: '', + overflow: '', + 'background-color': '', + transform: 'translate3d(' + -offsetX + 'px,0,0)' + }); + anchor.css({ + overflow: '', + transform: 'translate3d(0,' + offsetY + 'px,0)' + }); + + setTimeout(function() { + btn.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s' + }); + anchor.css({ + transform: 'translate3d(0,0,0)', + transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' + }); + }, 20); + }, 200); + }; + + +}( jQuery )); diff --git a/assets/libs/materialize/js/cards.js b/assets/libs/materialize/js/cards.js new file mode 100644 index 0000000..ccd6610 --- /dev/null +++ b/assets/libs/materialize/js/cards.js @@ -0,0 +1,26 @@ +(function ($) { + $(document).ready(function() { + + $(document).on('click.card', '.card', function (e) { + if ($(this).find('> .card-reveal').length) { + if ($(e.target).is($('.card-reveal .card-title')) || $(e.target).is($('.card-reveal .card-title i'))) { + // Make Reveal animate down and display none + $(this).find('.card-reveal').velocity( + {translateY: 0}, { + duration: 225, + queue: false, + easing: 'easeInOutQuad', + complete: function() { $(this).css({ display: 'none'}); } + } + ); + } + else if ($(e.target).is($('.card .activator')) || + $(e.target).is($('.card .activator i')) ) { + $(e.target).closest('.card').css('overflow', 'hidden'); + $(this).find('.card-reveal').css({ display: 'block'}).velocity("stop", false).velocity({translateY: '-100%'}, {duration: 300, queue: false, easing: 'easeInOutQuad'}); + } + } + }); + + }); +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/carousel.js b/assets/libs/materialize/js/carousel.js new file mode 100644 index 0000000..88bda29 --- /dev/null +++ b/assets/libs/materialize/js/carousel.js @@ -0,0 +1,454 @@ +(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + time_constant: 200, // ms + dist: -100, // zoom scale TODO: make this more intuitive as an option + shift: 0, // spacing for center image + padding: 0, // Padding between non center items + full_width: false, // Change to full width styles + indicators: false, // Toggle indicators + no_wrap: false // Don't wrap around and cycle through items. + }; + options = $.extend(defaults, options); + + return this.each(function() { + + var images, offset, center, pressed, dim, count, + reference, referenceY, amplitude, target, velocity, + xform, frame, timestamp, ticker, dragged, vertical_dragged; + var $indicators = $('
                  '); + + + // Initialize + var view = $(this); + var showIndicators = view.attr('data-indicators') || options.indicators; + + // Don't double initialize. + if (view.hasClass('initialized')) { + // Redraw carousel. + $(this).trigger('carouselNext', [0.000001]); + return true; + } + + + // Options + if (options.full_width) { + options.dist = 0; + var firstImage = view.find('.carousel-item img').first(); + if (firstImage.length) { + imageHeight = firstImage.on('load', function(){ + view.css('height', $(this).height()); + }); + } else { + imageHeight = view.find('.carousel-item').first().height(); + view.css('height', imageHeight); + } + + // Offset fixed items when indicators. + if (showIndicators) { + view.find('.carousel-fixed-item').addClass('with-indicators'); + } + } + + + view.addClass('initialized'); + pressed = false; + offset = target = 0; + images = []; + item_width = view.find('.carousel-item').first().innerWidth(); + dim = item_width * 2 + options.padding; + + view.find('.carousel-item').each(function (i) { + images.push($(this)[0]); + if (showIndicators) { + var $indicator = $('
                • '); + + // Add active to first by default. + if (i === 0) { + $indicator.addClass('active'); + } + + // Handle clicks on indicators. + $indicator.click(function () { + var index = $(this).index(); + cycleTo(index); + }); + $indicators.append($indicator); + } + }); + + if (showIndicators) { + view.append($indicators); + } + count = images.length; + + + function setupEvents() { + if (typeof window.ontouchstart !== 'undefined') { + view[0].addEventListener('touchstart', tap); + view[0].addEventListener('touchmove', drag); + view[0].addEventListener('touchend', release); + } + view[0].addEventListener('mousedown', tap); + view[0].addEventListener('mousemove', drag); + view[0].addEventListener('mouseup', release); + view[0].addEventListener('mouseleave', release); + view[0].addEventListener('click', click); + } + + function xpos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientX; + } + + // mouse event + return e.clientX; + } + + function ypos(e) { + // touch event + if (e.targetTouches && (e.targetTouches.length >= 1)) { + return e.targetTouches[0].clientY; + } + + // mouse event + return e.clientY; + } + + function wrap(x) { + return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x; + } + + function scroll(x) { + var i, half, delta, dir, tween, el, alignment, xTranslation; + + offset = (typeof x === 'number') ? x : offset; + center = Math.floor((offset + dim / 2) / dim); + delta = offset - center * dim; + dir = (delta < 0) ? 1 : -1; + tween = -dir * delta * 2 / dim; + half = count >> 1; + + if (!options.full_width) { + alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) '; + alignment += 'translateY(' + (view[0].clientHeight - item_width) / 2 + 'px)'; + } else { + alignment = 'translateX(0)'; + } + + // Set indicator active + if (showIndicators) { + var diff = (center % count); + var activeIndicator = $indicators.find('.indicator-item.active'); + if (activeIndicator.index() !== diff) { + activeIndicator.removeClass('active'); + $indicators.find('.indicator-item').eq(diff).addClass('active'); + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween * i) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + for (i = 1; i <= half; ++i) { + // right side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 + tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center + i < count) { + el = images[wrap(center + i)]; + el.style[xform] = alignment + + ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + + + // left side + if (options.full_width) { + zTranslation = options.dist; + tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1; + } else { + zTranslation = options.dist * (i * 2 - tween * dir); + tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir); + } + // Don't show wrapped items. + if (!options.no_wrap || center - i >= 0) { + el = images[wrap(center - i)]; + el.style[xform] = alignment + + ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' + + ' translateZ(' + zTranslation + 'px)'; + el.style.zIndex = -i; + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + // center + // Don't show wrapped items. + if (!options.no_wrap || (center >= 0 && center < count)) { + el = images[wrap(center)]; + el.style[xform] = alignment + + ' translateX(' + (-delta / 2) + 'px)' + + ' translateX(' + (dir * options.shift * tween) + 'px)' + + ' translateZ(' + (options.dist * tween) + 'px)'; + el.style.zIndex = 0; + if (options.full_width) { tweenedOpacity = 1; } + else { tweenedOpacity = 1 - 0.2 * tween; } + el.style.opacity = tweenedOpacity; + el.style.display = 'block'; + } + } + + function track() { + var now, elapsed, delta, v; + + now = Date.now(); + elapsed = now - timestamp; + timestamp = now; + delta = offset - frame; + frame = offset; + + v = 1000 * delta / (1 + elapsed); + velocity = 0.8 * v + 0.2 * velocity; + } + + function autoScroll() { + var elapsed, delta; + + if (amplitude) { + elapsed = Date.now() - timestamp; + delta = amplitude * Math.exp(-elapsed / options.time_constant); + if (delta > 2 || delta < -2) { + scroll(target - delta); + requestAnimationFrame(autoScroll); + } else { + scroll(target); + } + } + } + + function click(e) { + // Disable clicks if carousel was dragged. + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + return false; + + } else if (!options.full_width) { + var clickedIndex = $(e.target).closest('.carousel-item').index(); + var diff = (center % count) - clickedIndex; + + // Disable clicks if carousel was shifted by click + if (diff !== 0) { + e.preventDefault(); + e.stopPropagation(); + } + cycleTo(clickedIndex); + } + } + + function cycleTo(n) { + var diff = (center % count) - n; + + // Account for wraparound. + if (!options.no_wrap) { + if (diff < 0) { + if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; } + + } else if (diff > 0) { + if (Math.abs(diff - count) < diff) { diff -= count; } + } + } + + // Call prev or next accordingly. + if (diff < 0) { + view.trigger('carouselNext', [Math.abs(diff)]); + + } else if (diff > 0) { + view.trigger('carouselPrev', [diff]); + } + } + + function tap(e) { + pressed = true; + dragged = false; + vertical_dragged = false; + reference = xpos(e); + referenceY = ypos(e); + + velocity = amplitude = 0; + frame = offset; + timestamp = Date.now(); + clearInterval(ticker); + ticker = setInterval(track, 100); + + } + + function drag(e) { + var x, delta, deltaY; + if (pressed) { + x = xpos(e); + y = ypos(e); + delta = reference - x; + deltaY = Math.abs(referenceY - y); + if (deltaY < 30 && !vertical_dragged) { + // If vertical scrolling don't allow dragging. + if (delta > 2 || delta < -2) { + dragged = true; + reference = x; + scroll(offset + delta); + } + + } else if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + + } else { + // Vertical scrolling. + vertical_dragged = true; + } + } + + if (dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + + function release(e) { + if (pressed) { + pressed = false; + } else { + return; + } + + clearInterval(ticker); + target = offset; + if (velocity > 10 || velocity < -10) { + amplitude = 0.9 * velocity; + target = offset + amplitude; + } + target = Math.round(target / dim) * dim; + + // No wrap of items. + if (options.no_wrap) { + if (target >= dim * (count - 1)) { + target = dim * (count - 1); + } else if (target < 0) { + target = 0; + } + } + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + + if (dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } + + xform = 'transform'; + ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { + var e = prefix + 'Transform'; + if (typeof document.body.style[e] !== 'undefined') { + xform = e; + return false; + } + return true; + }); + + + + window.onresize = scroll; + + setupEvents(); + scroll(offset); + + $(this).on('carouselNext', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset + dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselPrev', function(e, n) { + if (n === undefined) { + n = 1; + } + target = offset - dim * n; + if (offset !== target) { + amplitude = target - offset; + timestamp = Date.now(); + requestAnimationFrame(autoScroll); + } + }); + + $(this).on('carouselSet', function(e, n) { + if (n === undefined) { + n = 0; + } + cycleTo(n); + }); + + }); + + + + }, + next : function(n) { + $(this).trigger('carouselNext', [n]); + }, + prev : function(n) { + $(this).trigger('carouselPrev', [n]); + }, + set : function(n) { + $(this).trigger('carouselSet', [n]); + } + }; + + + $.fn.carousel = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' ); + } + }; // Plugin end +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/character_counter.js b/assets/libs/materialize/js/character_counter.js new file mode 100644 index 0000000..3cce87f --- /dev/null +++ b/assets/libs/materialize/js/character_counter.js @@ -0,0 +1,72 @@ +(function ($) { + + $.fn.characterCounter = function(){ + return this.each(function(){ + var $input = $(this); + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + // character counter has already been added appended to the parent container + if ($counterElement.length) { + return; + } + + var itHasLengthAttribute = $input.attr('length') !== undefined; + + if(itHasLengthAttribute){ + $input.on('input', updateCounter); + $input.on('focus', updateCounter); + $input.on('blur', removeCounterElement); + + addCounterElement($input); + } + + }); + }; + + function updateCounter(){ + var maxLength = +$(this).attr('length'), + actualLength = +$(this).val().length, + isValidLength = actualLength <= maxLength; + + $(this).parent().find('span[class="character-counter"]') + .html( actualLength + '/' + maxLength); + + addInputStyle(isValidLength, $(this)); + } + + function addCounterElement($input) { + var $counterElement = $input.parent().find('span[class="character-counter"]'); + + if ($counterElement.length) { + return; + } + + $counterElement = $('') + .addClass('character-counter') + .css('float','right') + .css('font-size','12px') + .css('height', 1); + + $input.parent().append($counterElement); + } + + function removeCounterElement(){ + $(this).parent().find('span[class="character-counter"]').html(''); + } + + function addInputStyle(isValidLength, $input){ + var inputHasInvalidClass = $input.hasClass('invalid'); + if (isValidLength && inputHasInvalidClass) { + $input.removeClass('invalid'); + } + else if(!isValidLength && !inputHasInvalidClass){ + $input.removeClass('valid'); + $input.addClass('invalid'); + } + } + + $(document).ready(function(){ + $('input, textarea').characterCounter(); + }); + +}( jQuery )); diff --git a/assets/libs/materialize/js/chips.js b/assets/libs/materialize/js/chips.js new file mode 100644 index 0000000..f9ad7f1 --- /dev/null +++ b/assets/libs/materialize/js/chips.js @@ -0,0 +1,289 @@ +(function ($) { + var chipsHandleEvents = false; + var materialChipsDefaults = { + data: [], + placeholder: '', + secondaryPlaceholder: '', + }; + + $(document).ready(function() { + // Handle removal of static chips. + $(document).on('click', '.chip .close', function(e){ + var $chips = $(this).closest('.chips'); + if ($chips.attr('data-initialized')) { + return; + } + $(this).closest('.chip').remove(); + }); + }); + + $.fn.material_chip = function (options) { + var self = this; + this.$el = $(this); + this.$document = $(document); + this.SELS = { + CHIPS: '.chips', + CHIP: '.chip', + INPUT: 'input', + DELETE: '.material-icons', + SELECTED_CHIP: '.selected', + }; + + if ('data' === options) { + return this.$el.data('chips'); + } + + var curr_options = $.extend({}, materialChipsDefaults, options); + + + // Initialize + this.init = function() { + var i = 0; + var chips; + self.$el.each(function(){ + var $chips = $(this); + var chipId = Materialize.guid(); + + if (!curr_options.data || !(curr_options.data instanceof Array)) { + curr_options.data = []; + } + $chips.data('chips', curr_options.data); + $chips.attr('data-index', i); + $chips.attr('data-initialized', true); + + if (!$chips.hasClass(self.SELS.CHIPS)) { + $chips.addClass('chips'); + } + + self.chips($chips, chipId); + i++; + }); + }; + + this.handleEvents = function(){ + var SELS = self.SELS; + + self.$document.off('click.chips-focus', SELS.CHIPS).on('click.chips-focus', SELS.CHIPS, function(e){ + $(e.target).find(SELS.INPUT).focus(); + }); + + self.$document.off('click.chips-select', SELS.CHIP).on('click.chips-select', SELS.CHIP, function(e){ + $(SELS.CHIP).removeClass('selected'); + $(this).toggleClass('selected'); + }); + + self.$document.off('keydown.chips').on('keydown.chips', function(e){ + if ($(e.target).is('input, textarea')) { + return; + } + + // delete + var $chip = self.$document.find(SELS.CHIP + SELS.SELECTED_CHIP); + var $chips = $chip.closest(SELS.CHIPS); + var length = $chip.siblings(SELS.CHIP).length; + var index; + + if (!$chip.length) { + return; + } + + if (e.which === 8 || e.which === 46) { + e.preventDefault(); + + index = $chip.index(); + self.deleteChip(index, $chips); + + var selectIndex = null; + if ((index + 1) < length) { + selectIndex = index; + } else if (index === length || (index + 1) === length) { + selectIndex = length - 1; + } + + if (selectIndex < 0) selectIndex = null; + + if (null !== selectIndex) { + self.selectChip(selectIndex, $chips); + } + if (!length) $chips.find('input').focus(); + + // left + } else if (e.which === 37) { + index = $chip.index() - 1; + if (index < 0) { + return; + } + $(SELS.CHIP).removeClass('selected'); + self.selectChip(index, $chips); + + // right + } else if (e.which === 39) { + index = $chip.index() + 1; + $(SELS.CHIP).removeClass('selected'); + if (index > length) { + $chips.find('input').focus(); + return; + } + self.selectChip(index, $chips); + } + }); + + self.$document.off('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusin.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.addClass('focus'); + $currChips.siblings('label, .prefix').addClass('active'); + $(SELS.CHIP).removeClass('selected'); + }); + + self.$document.off('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT).on('focusout.chips', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $currChips = $(e.target).closest(SELS.CHIPS); + $currChips.removeClass('focus'); + + // Remove active if empty + if (!$currChips.data('chips').length) { + $currChips.siblings('label').removeClass('active'); + } + $currChips.siblings('.prefix').removeClass('active'); + }); + + self.$document.off('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT).on('keydown.chips-add', SELS.CHIPS + ' ' + SELS.INPUT, function(e){ + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var chipsLength = $chips.children(SELS.CHIP).length; + + // enter + if (13 === e.which) { + e.preventDefault(); + self.addChip({tag: $target.val()}, $chips); + $target.val(''); + return; + } + + // delete or left + if ((8 === e.keyCode || 37 === e.keyCode) && '' === $target.val() && chipsLength) { + self.selectChip(chipsLength - 1, $chips); + $target.blur(); + return; + } + }); + + // Click on delete icon in chip. + self.$document.off('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE).on('click.chips-delete', SELS.CHIPS + ' ' + SELS.DELETE, function(e) { + var $target = $(e.target); + var $chips = $target.closest(SELS.CHIPS); + var $chip = $target.closest(SELS.CHIP); + e.stopPropagation(); + self.deleteChip($chip.index(), $chips); + $chips.find('input').focus(); + }); + }; + + this.chips = function($chips, chipId) { + var html = ''; + $chips.data('chips').forEach(function(elem){ + html += self.renderChip(elem); + }); + html += ''; + $chips.html(html); + self.setPlaceholder($chips); + + // Set for attribute for label + var label = $chips.next('label'); + if (label.length) { + label.attr('for', chipId); + + if ($chips.data('chips').length) { + label.addClass('active'); + } + } + }; + + this.renderChip = function(elem) { + if (!elem.tag) return; + + var html = '
                  ' + elem.tag; + if (elem.image) { + html += ' '; + } + html += 'close'; + html += '
                  '; + return html; + }; + + this.setPlaceholder = function($chips) { + if ($chips.data('chips').length && curr_options.placeholder) { + $chips.find('input').prop('placeholder', curr_options.placeholder); + + } else if (!$chips.data('chips').length && curr_options.secondaryPlaceholder) { + $chips.find('input').prop('placeholder', curr_options.secondaryPlaceholder); + } + }; + + this.isValid = function($chips, elem) { + var chips = $chips.data('chips'); + var exists = false; + for (var i=0; i < chips.length; i++) { + if (chips[i].tag === elem.tag) { + exists = true; + return; + } + } + return '' !== elem.tag && !exists; + }; + + this.addChip = function(elem, $chips) { + if (!self.isValid($chips, elem)) { + return; + } + var chipHtml = self.renderChip(elem); + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + newData.push(oldData[i]); + } + newData.push(elem); + + $chips.data('chips', newData); + $(chipHtml).insertBefore($chips.find('input')); + $chips.trigger('chip.add', elem); + self.setPlaceholder($chips); + }; + + this.deleteChip = function(chipIndex, $chips) { + var chip = $chips.data('chips')[chipIndex]; + $chips.find('.chip').eq(chipIndex).remove(); + + var newData = []; + var oldData = $chips.data('chips'); + for (var i = 0; i < oldData.length; i++) { + if (i !== chipIndex) { + newData.push(oldData[i]); + } + } + + $chips.data('chips', newData); + $chips.trigger('chip.delete', chip); + self.setPlaceholder($chips); + }; + + this.selectChip = function(chipIndex, $chips) { + var $chip = $chips.find('.chip').eq(chipIndex); + if ($chip && false === $chip.hasClass('selected')) { + $chip.addClass('selected'); + $chips.trigger('chip.select', $chips.data('chips')[chipIndex]); + } + }; + + this.getChipsElement = function(index, $chips) { + return $chips.eq(index); + }; + + // init + this.init(); + + if (!chipsHandleEvents) { + this.handleEvents(); + chipsHandleEvents = true; + } + }; +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/collapsible.js b/assets/libs/materialize/js/collapsible.js new file mode 100644 index 0000000..650c702 --- /dev/null +++ b/assets/libs/materialize/js/collapsible.js @@ -0,0 +1,160 @@ +(function ($) { + $.fn.collapsible = function(options) { + var defaults = { + accordion: undefined, + onOpen: undefined, + onClose: undefined + }; + + options = $.extend(defaults, options); + + + return this.each(function() { + + var $this = $(this); + + var $panel_headers = $(this).find('> li > .collapsible-header'); + + var collapsible_type = $this.data("collapsible"); + + // Turn off any existing event handlers + $this.off('click.collapse', '> li > .collapsible-header'); + $panel_headers.off('click.collapse'); + + + /**************** + Helper Functions + ****************/ + + // Accordion Open + function accordionOpen(object) { + $panel_headers = $this.find('> li > .collapsible-header'); + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else{ + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + + $panel_headers.not(object).removeClass('active').parent().removeClass('active'); + + // Close previously open accordion elements. + $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() { + if ($(this).is(':visible')) { + $(this).slideUp({ + duration: 350, + easing: "easeOutQuart", + queue: false, + complete: + function() { + $(this).css('height', ''); + execCallbacks($(this).siblings('.collapsible-header')); + } + }); + } + }); + } + + // Expandable Open + function expandableOpen(object) { + if (object.hasClass('active')) { + object.parent().addClass('active'); + } + else { + object.parent().removeClass('active'); + } + if (object.parent().hasClass('active')){ + object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + else { + object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}}); + } + } + + // Open collapsible. object: .collapsible-header + function collapsibleOpen(object) { + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + accordionOpen(object); + } else { // Handle Expandables + expandableOpen(object); + } + + execCallbacks(object); + } + + // Handle callbacks + function execCallbacks(object) { + if (object.hasClass('active')) { + if (typeof(options.onOpen) === "function") { + options.onOpen.call(this, object.parent()); + } + } else { + if (typeof(options.onClose) === "function") { + options.onClose.call(this, object.parent()); + } + } + } + + /** + * Check if object is children of panel header + * @param {Object} object Jquery object + * @return {Boolean} true if it is children + */ + function isChildrenOfPanelHeader(object) { + + var panelHeader = getPanelHeader(object); + + return panelHeader.length > 0; + } + + /** + * Get panel header from a children element + * @param {Object} object Jquery object + * @return {Object} panel header object + */ + function getPanelHeader(object) { + + return object.closest('li > .collapsible-header'); + } + + /***** End Helper Functions *****/ + + + + // Add click handler to only direct collapsible header children + $this.on('click.collapse', '> li > .collapsible-header', function(e) { + var element = $(e.target); + + if (isChildrenOfPanelHeader(element)) { + element = getPanelHeader(element); + } + + element.toggleClass('active'); + + collapsibleOpen(element); + }); + + + // Open first active + if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion + collapsibleOpen($panel_headers.filter('.active').first()); + + } else { // Handle Expandables + $panel_headers.filter('.active').each(function() { + collapsibleOpen($(this)); + }); + } + + }); + }; + + $(document).ready(function(){ + $('.collapsible').collapsible(); + }); +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/date_picker/picker.date.js b/assets/libs/materialize/js/date_picker/picker.date.js new file mode 100644 index 0000000..fb264d0 --- /dev/null +++ b/assets/libs/materialize/js/date_picker/picker.date.js @@ -0,0 +1,1430 @@ +/*! + * Date picker for pickadate.js v3.5.0 + * http://amsul.github.io/pickadate.js/date.htm + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( ['picker', 'jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('./picker.js'), require('jquery') ) + + // Browser globals. + else factory( Picker, jQuery ) + +}(function( Picker, $ ) { + + +/** + * Globals and constants + */ +var DAYS_IN_WEEK = 7, + WEEKS_IN_CALENDAR = 6, + _ = Picker._ + + + +/** + * The date picker constructor + */ +function DatePicker( picker, settings ) { + + var calendar = this, + element = picker.$node[ 0 ], + elementValue = element.value, + elementDataValue = picker.$node.data( 'value' ), + valueString = elementDataValue || elementValue, + formatString = elementDataValue ? settings.formatSubmit : settings.format, + isRTL = function() { + + return element.currentStyle ? + + // For IE. + element.currentStyle.direction == 'rtl' : + + // For normal browsers. + getComputedStyle( picker.$root[0] ).direction == 'rtl' + } + + calendar.settings = settings + calendar.$node = picker.$node + + // The queue of methods that will be used to build item objects. + calendar.queue = { + min: 'measure create', + max: 'measure create', + now: 'now create', + select: 'parse create validate', + highlight: 'parse navigate create validate', + view: 'parse create validate viewset', + disable: 'deactivate', + enable: 'activate' + } + + // The component's item object. + calendar.item = {} + + calendar.item.clear = null + calendar.item.disable = ( settings.disable || [] ).slice( 0 ) + calendar.item.enable = -(function( collectionDisabled ) { + return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 + })( calendar.item.disable ) + + calendar. + set( 'min', settings.min ). + set( 'max', settings.max ). + set( 'now' ) + + // When there’s a value, set the `select`, which in turn + // also sets the `highlight` and `view`. + if ( valueString ) { + calendar.set( 'select', valueString, { format: formatString }) + } + + // If there’s no value, default to highlighting “today”. + else { + calendar. + set( 'select', null ). + set( 'highlight', calendar.item.now ) + } + + + // The keycode to movement mapping. + calendar.key = { + 40: 7, // Down + 38: -7, // Up + 39: function() { return isRTL() ? -1 : 1 }, // Right + 37: function() { return isRTL() ? 1 : -1 }, // Left + go: function( timeChange ) { + var highlightedObject = calendar.item.highlight, + targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) + calendar.set( + 'highlight', + targetDate, + { interval: timeChange } + ) + this.render() + } + } + + + // Bind some picker events. + picker. + on( 'render', function() { + picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) + } + }) + picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { + var value = this.value + if ( value ) { + picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) + picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) + } + }) + }, 1 ). + on( 'open', function() { + var includeToday = '' + if ( calendar.disabled( calendar.get('now') ) ) { + includeToday = ':not(.' + settings.klass.buttonToday + ')' + } + picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false ) + }, 1 ). + on( 'close', function() { + picker.$root.find( 'button, select' ).attr( 'disabled', true ) + }, 1 ) + +} //DatePicker + + +/** + * Set a datepicker item object. + */ +DatePicker.prototype.set = function( type, value, options ) { + + var calendar = this, + calendarItem = calendar.item + + // If the value is `null` just set it immediately. + if ( value === null ) { + if ( type == 'clear' ) type = 'select' + calendarItem[ type ] = value + return calendar + } + + // Otherwise go through the queue of methods, and invoke the functions. + // Update this as the time unit, and set the final value as this item. + // * In the case of `enable`, keep the queue but set `disable` instead. + // And in the case of `flip`, keep the queue but set `enable` instead. + calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { + value = calendar[ method ]( type, value, options ) + return value + }).pop() + + // Check if we need to cascade through more updates. + if ( type == 'select' ) { + calendar.set( 'highlight', calendarItem.select, options ) + } + else if ( type == 'highlight' ) { + calendar.set( 'view', calendarItem.highlight, options ) + } + else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { + if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) { + calendar.set( 'select', calendarItem.select, options ) + } + if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) { + calendar.set( 'highlight', calendarItem.highlight, options ) + } + } + + return calendar +} //DatePicker.prototype.set + + +/** + * Get a datepicker item object. + */ +DatePicker.prototype.get = function( type ) { + return this.item[ type ] +} //DatePicker.prototype.get + + +/** + * Create a picker date object. + */ +DatePicker.prototype.create = function( type, value, options ) { + + var isInfiniteValue, + calendar = this + + // If there’s no value, use the type as the value. + value = value === undefined ? type : value + + + // If it’s infinity, update the value. + if ( value == -Infinity || value == Infinity ) { + isInfiniteValue = value + } + + // If it’s an object, use the native date object. + else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { + value = value.obj + } + + // If it’s an array, convert it into a date and make sure + // that it’s a valid date – otherwise default to today. + else if ( $.isArray( value ) ) { + value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) + value = _.isDate( value ) ? value : calendar.create().obj + } + + // If it’s a number or date object, make a normalized date. + else if ( _.isInteger( value ) || _.isDate( value ) ) { + value = calendar.normalize( new Date( value ), options ) + } + + // If it’s a literal true or any other case, set it to now. + else /*if ( value === true )*/ { + value = calendar.now( type, value, options ) + } + + // Return the compiled object. + return { + year: isInfiniteValue || value.getFullYear(), + month: isInfiniteValue || value.getMonth(), + date: isInfiniteValue || value.getDate(), + day: isInfiniteValue || value.getDay(), + obj: isInfiniteValue || value, + pick: isInfiniteValue || value.getTime() + } +} //DatePicker.prototype.create + + +/** + * Create a range limit object using an array, date object, + * literal “true”, or integer relative to another time. + */ +DatePicker.prototype.createRange = function( from, to ) { + + var calendar = this, + createDate = function( date ) { + if ( date === true || $.isArray( date ) || _.isDate( date ) ) { + return calendar.create( date ) + } + return date + } + + // Create objects if possible. + if ( !_.isInteger( from ) ) { + from = createDate( from ) + } + if ( !_.isInteger( to ) ) { + to = createDate( to ) + } + + // Create relative dates. + if ( _.isInteger( from ) && $.isPlainObject( to ) ) { + from = [ to.year, to.month, to.date + from ]; + } + else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { + to = [ from.year, from.month, from.date + to ]; + } + + return { + from: createDate( from ), + to: createDate( to ) + } +} //DatePicker.prototype.createRange + + +/** + * Check if a date unit falls within a date range object. + */ +DatePicker.prototype.withinRange = function( range, dateUnit ) { + range = this.createRange(range.from, range.to) + return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick +} + + +/** + * Check if two date range objects overlap. + */ +DatePicker.prototype.overlapRanges = function( one, two ) { + + var calendar = this + + // Convert the ranges into comparable dates. + one = calendar.createRange( one.from, one.to ) + two = calendar.createRange( two.from, two.to ) + + return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || + calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) +} + + +/** + * Get the date today. + */ +DatePicker.prototype.now = function( type, value, options ) { + value = new Date() + if ( options && options.rel ) { + value.setDate( value.getDate() + options.rel ) + } + return this.normalize( value, options ) +} + + +/** + * Navigate to next/prev month. + */ +DatePicker.prototype.navigate = function( type, value, options ) { + + var targetDateObject, + targetYear, + targetMonth, + targetDate, + isTargetArray = $.isArray( value ), + isTargetObject = $.isPlainObject( value ), + viewsetObject = this.item.view/*, + safety = 100*/ + + + if ( isTargetArray || isTargetObject ) { + + if ( isTargetObject ) { + targetYear = value.year + targetMonth = value.month + targetDate = value.date + } + else { + targetYear = +value[0] + targetMonth = +value[1] + targetDate = +value[2] + } + + // If we’re navigating months but the view is in a different + // month, navigate to the view’s year and month. + if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { + targetYear = viewsetObject.year + targetMonth = viewsetObject.month + } + + // Figure out the expected target year and month. + targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) + targetYear = targetDateObject.getFullYear() + targetMonth = targetDateObject.getMonth() + + // If the month we’re going to doesn’t have enough days, + // keep decreasing the date until we reach the month’s last date. + while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) { + targetDate -= 1 + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.' + }*/ + } + + value = [ targetYear, targetMonth, targetDate ] + } + + return value +} //DatePicker.prototype.navigate + + +/** + * Normalize a date by setting the hours to midnight. + */ +DatePicker.prototype.normalize = function( value/*, options*/ ) { + value.setHours( 0, 0, 0, 0 ) + return value +} + + +/** + * Measure the range of dates. + */ +DatePicker.prototype.measure = function( type, value/*, options*/ ) { + + var calendar = this + + // If it’s anything false-y, remove the limits. + if ( !value ) { + value = type == 'min' ? -Infinity : Infinity + } + + // If it’s a string, parse it. + else if ( typeof value == 'string' ) { + value = calendar.parse( type, value ) + } + + // If it's an integer, get a date relative to today. + else if ( _.isInteger( value ) ) { + value = calendar.now( type, value, { rel: value } ) + } + + return value +} ///DatePicker.prototype.measure + + +/** + * Create a viewset object based on navigation. + */ +DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { + return this.create([ dateObject.year, dateObject.month, 1 ]) +} + + +/** + * Validate a date as enabled and shift if needed. + */ +DatePicker.prototype.validate = function( type, dateObject, options ) { + + var calendar = this, + + // Keep a reference to the original date. + originalDateObject = dateObject, + + // Make sure we have an interval. + interval = options && options.interval ? options.interval : 1, + + // Check if the calendar enabled dates are inverted. + isFlippedBase = calendar.item.enable === -1, + + // Check if we have any enabled dates after/before now. + hasEnabledBeforeTarget, hasEnabledAfterTarget, + + // The min & max limits. + minLimitObject = calendar.item.min, + maxLimitObject = calendar.item.max, + + // Check if we’ve reached the limit during shifting. + reachedMin, reachedMax, + + // Check if the calendar is inverted and at least one weekday is enabled. + hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) { + + // If there’s a date, check where it is relative to the target. + if ( $.isArray( value ) ) { + var dateTime = calendar.create( value ).pick + if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true + else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true + } + + // Return only integers for enabled weekdays. + return _.isInteger( value ) + }).length/*, + + safety = 100*/ + + + + // Cases to validate for: + // [1] Not inverted and date disabled. + // [2] Inverted and some dates enabled. + // [3] Not inverted and out of range. + // + // Cases to **not** validate for: + // • Navigating months. + // • Not inverted and date enabled. + // • Inverted and all dates disabled. + // • ..and anything else. + if ( !options || !options.nav ) if ( + /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) || + /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) || + /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) ) + ) { + + + // When inverted, flip the direction if there aren’t any enabled weekdays + // and there are no enabled dates in the direction of the interval. + if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) { + interval *= -1 + } + + + // Keep looping until we reach an enabled date. + while ( /*safety &&*/ calendar.disabled( dateObject ) ) { + + /*safety -= 1 + if ( !safety ) { + throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.' + }*/ + + + // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval. + if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { + dateObject = originalDateObject + interval = interval > 0 ? 1 : -1 + } + + + // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. + if ( dateObject.pick <= minLimitObject.pick ) { + reachedMin = true + interval = 1 + dateObject = calendar.create([ + minLimitObject.year, + minLimitObject.month, + minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1) + ]) + } + else if ( dateObject.pick >= maxLimitObject.pick ) { + reachedMax = true + interval = -1 + dateObject = calendar.create([ + maxLimitObject.year, + maxLimitObject.month, + maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1) + ]) + } + + + // If we’ve reached both limits, just break out of the loop. + if ( reachedMin && reachedMax ) { + break + } + + + // Finally, create the shifted date using the interval and keep looping. + dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ]) + } + + } //endif + + + // Return the date object settled on. + return dateObject +} //DatePicker.prototype.validate + + +/** + * Check if a date is disabled. + */ +DatePicker.prototype.disabled = function( dateToVerify ) { + + var + calendar = this, + + // Filter through the disabled dates to check if this is one. + isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) { + + // If the date is a number, match the weekday with 0index and `firstDay` check. + if ( _.isInteger( dateToDisable ) ) { + return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7 + } + + // If it’s an array or a native JS date, create and match the exact date. + if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) { + return dateToVerify.pick === calendar.create( dateToDisable ).pick + } + + // If it’s an object, match a date within the “from” and “to” range. + if ( $.isPlainObject( dateToDisable ) ) { + return calendar.withinRange( dateToDisable, dateToVerify ) + } + }) + + // If this date matches a disabled date, confirm it’s not inverted. + isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { + return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || + $.isPlainObject( dateToDisable ) && dateToDisable.inverted + }).length + + // Check the calendar “enabled” flag and respectively flip the + // disabled state. Then also check if it’s beyond the min/max limits. + return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || + dateToVerify.pick < calendar.item.min.pick || + dateToVerify.pick > calendar.item.max.pick + +} //DatePicker.prototype.disabled + + +/** + * Parse a string into a usable type. + */ +DatePicker.prototype.parse = function( type, value, options ) { + + var calendar = this, + parsingObject = {} + + // If it’s already parsed, we’re good. + if ( !value || typeof value != 'string' ) { + return value + } + + // We need a `.format` to parse the value with. + if ( !( options && options.format ) ) { + options = options || {} + options.format = calendar.settings.format + } + + // Convert the format into an array and then map through it. + calendar.formats.toArray( options.format ).map( function( label ) { + + var + // Grab the formatting label. + formattingLabel = calendar.formats[ label ], + + // The format length is from the formatting label function or the + // label length without the escaping exclamation (!) mark. + formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length + + // If there's a format label, split the value up to the format length. + // Then add it to the parsing object with appropriate label. + if ( formattingLabel ) { + parsingObject[ label ] = value.substr( 0, formatLength ) + } + + // Update the value as the substring from format length to end. + value = value.substr( formatLength ) + }) + + // Compensate for month 0index. + return [ + parsingObject.yyyy || parsingObject.yy, + +( parsingObject.mm || parsingObject.m ) - 1, + parsingObject.dd || parsingObject.d + ] +} //DatePicker.prototype.parse + + +/** + * Various formats to display the object in. + */ +DatePicker.prototype.formats = (function() { + + // Return the length of the first word in a collection. + function getWordLengthFromCollection( string, collection, dateObject ) { + + // Grab the first word from the string. + var word = string.match( /\w+/ )[ 0 ] + + // If there's no month index, add it to the date object + if ( !dateObject.mm && !dateObject.m ) { + dateObject.m = collection.indexOf( word ) + 1 + } + + // Return the length of the word. + return word.length + } + + // Get the length of the first word in a string. + function getFirstWordLength( string ) { + return string.match( /\w+/ )[ 0 ].length + } + + return { + + d: function( string, dateObject ) { + + // If there's string, then get the digits length. + // Otherwise return the selected date. + return string ? _.digits( string ) : dateObject.date + }, + dd: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected date with a leading zero. + return string ? 2 : _.lead( dateObject.date ) + }, + ddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the short selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ] + }, + dddd: function( string, dateObject ) { + + // If there's a string, then get the length of the first word. + // Otherwise return the full selected weekday. + return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ] + }, + m: function( string, dateObject ) { + + // If there's a string, then get the length of the digits + // Otherwise return the selected month with 0index compensation. + return string ? _.digits( string ) : dateObject.month + 1 + }, + mm: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected month with 0index and leading zero. + return string ? 2 : _.lead( dateObject.month + 1 ) + }, + mmm: function( string, dateObject ) { + + var collection = this.settings.monthsShort + + // If there's a string, get length of the relevant month from the short + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + mmmm: function( string, dateObject ) { + + var collection = this.settings.monthsFull + + // If there's a string, get length of the relevant month from the full + // months collection. Otherwise return the selected month from that collection. + return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] + }, + yy: function( string, dateObject ) { + + // If there's a string, then the length is always 2. + // Otherwise return the selected year by slicing out the first 2 digits. + return string ? 2 : ( '' + dateObject.year ).slice( 2 ) + }, + yyyy: function( string, dateObject ) { + + // If there's a string, then the length is always 4. + // Otherwise return the selected year. + return string ? 4 : dateObject.year + }, + + // Create an array by splitting the formatting string passed. + toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) }, + + // Format an object into a string using the formatting options. + toString: function ( formatString, itemObject ) { + var calendar = this + return calendar.formats.toArray( formatString ).map( function( label ) { + return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) + }).join( '' ) + } + } +})() //DatePicker.prototype.formats + + + + +/** + * Check if two date units are the exact. + */ +DatePicker.prototype.isDateExact = function( one, two ) { + + var calendar = this + + // When we’re working with weekdays, do a direct comparison. + if ( + ( _.isInteger( one ) && _.isInteger( two ) ) || + ( typeof one == 'boolean' && typeof two == 'boolean' ) + ) { + return one === two + } + + // When we’re working with date representations, compare the “pick” value. + if ( + ( _.isDate( one ) || $.isArray( one ) ) && + ( _.isDate( two ) || $.isArray( two ) ) + ) { + return calendar.create( one ).pick === calendar.create( two ).pick + } + + // When we’re working with range objects, compare the “from” and “to”. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to ) + } + + return false +} + + +/** + * Check if two date units overlap. + */ +DatePicker.prototype.isDateOverlap = function( one, two ) { + + var calendar = this, + firstDay = calendar.settings.firstDay ? 1 : 0 + + // When we’re working with a weekday index, compare the days. + if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { + one = one % 7 + firstDay + return one === calendar.create( two ).day + 1 + } + if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { + two = two % 7 + firstDay + return two === calendar.create( one ).day + 1 + } + + // When we’re working with range objects, check if the ranges overlap. + if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { + return calendar.overlapRanges( one, two ) + } + + return false +} + + +/** + * Flip the “enabled” state. + */ +DatePicker.prototype.flipEnable = function(val) { + var itemObject = this.item + itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) +} + + +/** + * Mark a collection of dates as “disabled”. + */ +DatePicker.prototype.deactivate = function( type, datesToDisable ) { + + var calendar = this, + disabledItems = calendar.item.disable.slice(0) + + + // If we’re flipping, that’s all we need to do. + if ( datesToDisable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToDisable === false ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToDisable === true ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the dates to disable. + else { + + datesToDisable.map(function( unitToDisable ) { + + var matchFound + + // When we have disabled items, check for matches. + // If something is matched, immediately break out. + for ( var index = 0; index < disabledItems.length; index += 1 ) { + if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { + matchFound = true + break + } + } + + // If nothing was found, add the validated unit to the collection. + if ( !matchFound ) { + if ( + _.isInteger( unitToDisable ) || + _.isDate( unitToDisable ) || + $.isArray( unitToDisable ) || + ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) + ) { + disabledItems.push( unitToDisable ) + } + } + }) + } + + // Return the updated collection. + return disabledItems +} //DatePicker.prototype.deactivate + + +/** + * Mark a collection of dates as “enabled”. + */ +DatePicker.prototype.activate = function( type, datesToEnable ) { + + var calendar = this, + disabledItems = calendar.item.disable, + disabledItemsCount = disabledItems.length + + // If we’re flipping, that’s all we need to do. + if ( datesToEnable == 'flip' ) { + calendar.flipEnable() + } + + else if ( datesToEnable === true ) { + calendar.flipEnable(1) + disabledItems = [] + } + + else if ( datesToEnable === false ) { + calendar.flipEnable(-1) + disabledItems = [] + } + + // Otherwise go through the disabled dates. + else { + + datesToEnable.map(function( unitToEnable ) { + + var matchFound, + disabledUnit, + index, + isExactRange + + // Go through the disabled items and try to find a match. + for ( index = 0; index < disabledItemsCount; index += 1 ) { + + disabledUnit = disabledItems[index] + + // When an exact match is found, remove it from the collection. + if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { + matchFound = disabledItems[index] = null + isExactRange = true + break + } + + // When an overlapped match is found, add the “inverted” state to it. + else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { + if ( $.isPlainObject( unitToEnable ) ) { + unitToEnable.inverted = true + matchFound = unitToEnable + } + else if ( $.isArray( unitToEnable ) ) { + matchFound = unitToEnable + if ( !matchFound[3] ) matchFound.push( 'inverted' ) + } + else if ( _.isDate( unitToEnable ) ) { + matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] + } + break + } + } + + // If a match was found, remove a previous duplicate entry. + if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // In the event that we’re dealing with an exact range of dates, + // make sure there are no “inverted” dates because of it. + if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { + if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { + disabledItems[index] = null + break + } + } + + // If something is still matched, add it into the collection. + if ( matchFound ) { + disabledItems.push( matchFound ) + } + }) + } + + // Return the updated collection. + return disabledItems.filter(function( val ) { return val != null }) +} //DatePicker.prototype.activate + + +/** + * Create a string for the nodes in the picker. + */ +DatePicker.prototype.nodes = function( isOpen ) { + + var + calendar = this, + settings = calendar.settings, + calendarItem = calendar.item, + nowObject = calendarItem.now, + selectedObject = calendarItem.select, + highlightedObject = calendarItem.highlight, + viewsetObject = calendarItem.view, + disabledCollection = calendarItem.disable, + minLimitObject = calendarItem.min, + maxLimitObject = calendarItem.max, + + + // Create the calendar table head using a copy of weekday labels collection. + // * We do a copy so we don't mutate the original array. + tableHead = (function( collection, fullCollection ) { + + // If the first day should be Monday, move Sunday to the end. + if ( settings.firstDay ) { + collection.push( collection.shift() ) + fullCollection.push( fullCollection.shift() ) + } + + // Create and return the table head group. + return _.node( + 'thead', + _.node( + 'tr', + _.group({ + min: 0, + max: DAYS_IN_WEEK - 1, + i: 1, + node: 'th', + item: function( counter ) { + return [ + collection[ counter ], + settings.klass.weekdays, + 'scope=col title="' + fullCollection[ counter ] + '"' + ] + } + }) + ) + ) //endreturn + + // Materialize modified + })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysLetter ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead + + + // Create the nav for next/prev month. + createMonthNav = function( next ) { + + // Otherwise, return the created month tag. + return _.node( + 'div', + ' ', + settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + ( + + // If the focused month is outside the range, disabled the button. + ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) || + ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ? + ' ' + settings.klass.navDisabled : '' + ), + 'data-nav=' + ( next || -1 ) + ' ' + + _.ariaAttr({ + role: 'button', + controls: calendar.$node[0].id + '_table' + }) + ' ' + + 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"' + ) //endreturn + }, //createMonthNav + + + // Create the month label. + //Materialize modified + createMonthLabel = function(override) { + + var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull + + // Materialize modified + if (override == "short_months") { + monthsCollection = settings.monthsShort; + } + + // If there are months to select, add a dropdown menu. + if ( settings.selectMonths && override == undefined) { + + return _.node( 'select', + _.group({ + min: 0, + max: 11, + i: 1, + node: 'option', + item: function( loopedMonth ) { + + return [ + + // The looped month and no classes. + monthsCollection[ loopedMonth ], 0, + + // Set the value and selected index. + 'value=' + loopedMonth + + ( viewsetObject.month == loopedMonth ? ' selected' : '' ) + + ( + ( + ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) || + ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month ) + ) ? + ' disabled' : '' + ) + ] + } + }), + settings.klass.selectMonth + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelMonthSelect + '"' + ) + } + + // Materialize modified + if (override == "short_months") + if (selectedObject != null) + return _.node( 'div', monthsCollection[ selectedObject.month ] ); + else return _.node( 'div', monthsCollection[ viewsetObject.month ] ); + + // If there's a need for a month selector + return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month ) + }, //createMonthLabel + + + // Create the year label. + // Materialize modified + createYearLabel = function(override) { + + var focusedYear = viewsetObject.year, + + // If years selector is set to a literal "true", set it to 5. Otherwise + // divide in half to get half before and half after focused year. + numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) + + // If there are years to select, add a dropdown menu. + if ( numberYears ) { + + var + minYear = minLimitObject.year, + maxYear = maxLimitObject.year, + lowestYear = focusedYear - numberYears, + highestYear = focusedYear + numberYears + + // If the min year is greater than the lowest year, increase the highest year + // by the difference and set the lowest year to the min year. + if ( minYear > lowestYear ) { + highestYear += minYear - lowestYear + lowestYear = minYear + } + + // If the max year is less than the highest year, decrease the lowest year + // by the lower of the two: available and needed years. Then set the + // highest year to the max year. + if ( maxYear < highestYear ) { + + var availableYears = lowestYear - minYear, + neededYears = highestYear - maxYear + + lowestYear -= availableYears > neededYears ? neededYears : availableYears + highestYear = maxYear + } + + if ( settings.selectYears && override == undefined ) { + return _.node( 'select', + _.group({ + min: lowestYear, + max: highestYear, + i: 1, + node: 'option', + item: function( loopedYear ) { + return [ + + // The looped year and no classes. + loopedYear, 0, + + // Set the value and selected index. + 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' ) + ] + } + }), + settings.klass.selectYear + ' browser-default', + ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + + 'title="' + settings.labelYearSelect + '"' + ) + } + } + + // Materialize modified + if (override == "raw") + return _.node( 'div', focusedYear ) + + // Otherwise just return the year focused + return _.node( 'div', focusedYear, settings.klass.year ) + } //createYearLabel + + + // Materialize modified + createDayLabel = function() { + if (selectedObject != null) + return _.node( 'div', selectedObject.date) + else return _.node( 'div', nowObject.date) + } + createWeekdayLabel = function() { + var display_day; + + if (selectedObject != null) + display_day = selectedObject.day; + else + display_day = nowObject.day; + var weekday = settings.weekdaysFull[ display_day ] + return weekday + } + + + // Create and return the entire calendar. +return _.node( + // Date presentation View + 'div', + _.node( + 'div', + createWeekdayLabel(), + "picker__weekday-display" + )+ + _.node( + // Div for short Month + 'div', + createMonthLabel("short_months"), + settings.klass.month_display + )+ + _.node( + // Div for Day + 'div', + createDayLabel() , + settings.klass.day_display + )+ + _.node( + // Div for Year + 'div', + createYearLabel("raw") , + settings.klass.year_display + ), + settings.klass.date_display + )+ + // Calendar container + _.node('div', + _.node('div', + ( settings.selectYears ? createMonthLabel() + createYearLabel() : createMonthLabel() + createYearLabel() ) + + createMonthNav() + createMonthNav( 1 ), + settings.klass.header + ) + _.node( + 'table', + tableHead + + _.node( + 'tbody', + _.group({ + min: 0, + max: WEEKS_IN_CALENDAR - 1, + i: 1, + node: 'tr', + item: function( rowCounter ) { + + // If Monday is the first day and the month starts on Sunday, shift the date back a week. + var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 + + return [ + _.group({ + min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index + max: function() { + return this.min + DAYS_IN_WEEK - 1 + }, + i: 1, + node: 'td', + item: function( targetDate ) { + + // Convert the time date from a relative date to a target date. + targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) + + var isSelected = selectedObject && selectedObject.pick == targetDate.pick, + isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, + isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick, + formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] ) + + return [ + _.node( + 'div', + targetDate.date, + (function( klasses ) { + + // Add the `infocus` or `outfocus` classes based on month in view. + klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) + + // Add the `today` class if needed. + if ( nowObject.pick == targetDate.pick ) { + klasses.push( settings.klass.now ) + } + + // Add the `selected` class if something's selected and the time matches. + if ( isSelected ) { + klasses.push( settings.klass.selected ) + } + + // Add the `highlighted` class if something's highlighted and the time matches. + if ( isHighlighted ) { + klasses.push( settings.klass.highlighted ) + } + + // Add the `disabled` class if something's disabled and the object matches. + if ( isDisabled ) { + klasses.push( settings.klass.disabled ) + } + + return klasses.join( ' ' ) + })([ settings.klass.day ]), + 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({ + role: 'gridcell', + label: formattedDate, + selected: isSelected && calendar.$node.val() === formattedDate ? true : null, + activedescendant: isHighlighted ? true : null, + disabled: isDisabled ? true : null + }) + ), + '', + _.ariaAttr({ role: 'presentation' }) + ] //endreturn + } + }) + ] //endreturn + } + }) + ), + settings.klass.table, + 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({ + role: 'grid', + controls: calendar.$node[0].id, + readonly: true + }) + ) + , settings.klass.calendar_container) // end calendar + + + + + // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”. + _.node( + 'div', + _.node( 'button', settings.today, "btn-flat picker__today", + 'type=button data-pick=' + nowObject.pick + + ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node( 'button', settings.clear, "btn-flat picker__clear", + 'type=button data-clear=1' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ) + + _.node('button', settings.close, "btn-flat picker__close", + 'type=button data-close=true ' + + ( isOpen ? '' : ' disabled' ) + ' ' + + _.ariaAttr({ controls: calendar.$node[0].id }) ), + settings.klass.footer + ) //endreturn +} //DatePicker.prototype.nodes + + + + +/** + * The date picker defaults. + */ +DatePicker.defaults = (function( prefix ) { + + return { + + // The title label to use for the month nav buttons + labelMonthNext: 'Next month', + labelMonthPrev: 'Previous month', + + // The title label to use for the dropdown selectors + labelMonthSelect: 'Select a month', + labelYearSelect: 'Select a year', + + // Months and weekdays + monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], + monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], + weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], + weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], + + // Materialize modified + weekdaysLetter: [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ], + + // Today and clear + today: 'Today', + clear: 'Clear', + close: 'Close', + + // The format to show on the `input` element + format: 'd mmmm, yyyy', + + // Classes + klass: { + + table: prefix + 'table', + + header: prefix + 'header', + + + // Materialize Added klasses + date_display: prefix + 'date-display', + day_display: prefix + 'day-display', + month_display: prefix + 'month-display', + year_display: prefix + 'year-display', + calendar_container: prefix + 'calendar-container', + // end + + + + navPrev: prefix + 'nav--prev', + navNext: prefix + 'nav--next', + navDisabled: prefix + 'nav--disabled', + + month: prefix + 'month', + year: prefix + 'year', + + selectMonth: prefix + 'select--month', + selectYear: prefix + 'select--year', + + weekdays: prefix + 'weekday', + + day: prefix + 'day', + disabled: prefix + 'day--disabled', + selected: prefix + 'day--selected', + highlighted: prefix + 'day--highlighted', + now: prefix + 'day--today', + infocus: prefix + 'day--infocus', + outfocus: prefix + 'day--outfocus', + + footer: prefix + 'footer', + + buttonClear: prefix + 'button--clear', + buttonToday: prefix + 'button--today', + buttonClose: prefix + 'button--close' + } + } +})( Picker.klasses().picker + '__' ) + + + + + +/** + * Extend the picker to add the date picker. + */ +Picker.extend( 'pickadate', DatePicker ) + + +})); + + diff --git a/assets/libs/materialize/js/date_picker/picker.js b/assets/libs/materialize/js/date_picker/picker.js new file mode 100644 index 0000000..48fbbad --- /dev/null +++ b/assets/libs/materialize/js/date_picker/picker.js @@ -0,0 +1,1123 @@ +/*! + * pickadate.js v3.5.0, 2014/04/13 + * By Amsul, http://amsul.ca + * Hosted on http://amsul.github.io/pickadate.js + * Licensed under MIT + */ + +(function ( factory ) { + + // AMD. + if ( typeof define == 'function' && define.amd ) + define( 'picker', ['jquery'], factory ) + + // Node.js/browserify. + else if ( typeof exports == 'object' ) + module.exports = factory( require('jquery') ) + + // Browser globals. + else this.Picker = factory( jQuery ) + +}(function( $ ) { + +var $window = $( window ) +var $document = $( document ) +var $html = $( document.documentElement ) + + +/** + * The picker constructor that creates a blank picker. + */ +function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { + + // If there’s no element, return the picker constructor. + if ( !ELEMENT ) return PickerConstructor + + + var + IS_DEFAULT_THEME = false, + + + // The state of the picker. + STATE = { + id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) + }, + + + // Merge the defaults and options passed. + SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {}, + + + // Merge the default classes with the settings classes. + CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ), + + + // The element node wrapper into a jQuery object. + $ELEMENT = $( ELEMENT ), + + + // Pseudo picker constructor. + PickerInstance = function() { + return this.start() + }, + + + // The picker prototype. + P = PickerInstance.prototype = { + + constructor: PickerInstance, + + $node: $ELEMENT, + + + /** + * Initialize everything + */ + start: function() { + + // If it’s already started, do nothing. + if ( STATE && STATE.start ) return P + + + // Update the picker states. + STATE.methods = {} + STATE.start = true + STATE.open = false + STATE.type = ELEMENT.type + + + // Confirm focus state, convert into text input to remove UA stylings, + // and set as readonly to prevent keyboard popup. + ELEMENT.autofocus = ELEMENT == getActiveElement() + ELEMENT.readOnly = !SETTINGS.editable + ELEMENT.id = ELEMENT.id || STATE.id + if ( ELEMENT.type != 'text' ) { + ELEMENT.type = 'text' + } + + + // Create a new picker component with the settings. + P.component = new COMPONENT(P, SETTINGS) + + + // Create the picker root with a holder and then prepare it. + P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root" tabindex="0"') ) + prepareElementRoot() + + + // If there’s a format for the hidden input element, create the element. + if ( SETTINGS.formatSubmit ) { + prepareElementHidden() + } + + + // Prepare the input element. + prepareElement() + + + // Insert the root as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) + else $ELEMENT.after( P.$root ) + + + // Bind the default component and settings events. + P.on({ + start: P.component.onStart, + render: P.component.onRender, + stop: P.component.onStop, + open: P.component.onOpen, + close: P.component.onClose, + set: P.component.onSet + }).on({ + start: SETTINGS.onStart, + render: SETTINGS.onRender, + stop: SETTINGS.onStop, + open: SETTINGS.onOpen, + close: SETTINGS.onClose, + set: SETTINGS.onSet + }) + + + // Once we’re all set, check the theme in use. + IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] ) + + + // If the element has autofocus, open the picker. + if ( ELEMENT.autofocus ) { + P.open() + } + + + // Trigger queued the “start” and “render” events. + return P.trigger( 'start' ).trigger( 'render' ) + }, //start + + + /** + * Render a new picker + */ + render: function( entireComponent ) { + + // Insert a new component holder in the root or box. + if ( entireComponent ) P.$root.html( createWrappedComponent() ) + else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) + + // Trigger the queued “render” events. + return P.trigger( 'render' ) + }, //render + + + /** + * Destroy everything + */ + stop: function() { + + // If it’s already stopped, do nothing. + if ( !STATE.start ) return P + + // Then close the picker. + P.close() + + // Remove the hidden field. + if ( P._hidden ) { + P._hidden.parentNode.removeChild( P._hidden ) + } + + // Remove the root. + P.$root.remove() + + // Remove the input class, remove the stored data, and unbind + // the events (after a tick for IE - see `P.close`). + $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) + setTimeout( function() { + $ELEMENT.off( '.' + STATE.id ) + }, 0) + + // Restore the element state + ELEMENT.type = STATE.type + ELEMENT.readOnly = false + + // Trigger the queued “stop” events. + P.trigger( 'stop' ) + + // Reset the picker states. + STATE.methods = {} + STATE.start = false + + return P + }, //stop + + + /** + * Open up the picker + */ + open: function( dontGiveFocus ) { + + // If it’s already open, do nothing. + if ( STATE.open ) return P + + // Add the “active” class. + $ELEMENT.addClass( CLASSES.active ) + aria( ELEMENT, 'expanded', true ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So add the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Add the “opened” class to the picker root. + P.$root.addClass( CLASSES.opened ) + aria( P.$root[0], 'hidden', false ) + + }, 0 ) + + // If we have to give focus, bind the element and doc events. + if ( dontGiveFocus !== false ) { + + // Set it as open. + STATE.open = true + + // Prevent the page from scrolling. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', 'hidden' ). + css( 'padding-right', '+=' + getScrollbarWidth() ) + } + + // Pass focus to the root element’s jQuery object. + // * Workaround for iOS8 to bring the picker’s root into view. + P.$root.eq(0).focus() + + // Bind the document events. + $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { + + var target = event.target + + // If the target of the event is not the element, close the picker picker. + // * Don’t worry about clicks or focusins on the root because those don’t bubble up. + // Also, for Firefox, a click on an `option` element bubbles up directly + // to the doc. So make sure the target wasn't the doc. + // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling, + // which causes the picker to unexpectedly close when right-clicking it. So make + // sure the event wasn’t a right-click. + if ( target != ELEMENT && target != document && event.which != 3 ) { + + // If the target was the holder that covers the screen, + // keep the element focused to maintain tabindex. + P.close( target === P.$root.children()[0] ) + } + + }).on( 'keydown.' + STATE.id, function( event ) { + + var + // Get the keycode. + keycode = event.keyCode, + + // Translate that to a selection change. + keycodeToMove = P.component.key[ keycode ], + + // Grab the target. + target = event.target + + + // On escape, close the picker and give focus. + if ( keycode == 27 ) { + P.close( true ) + } + + + // Check if there is a key movement or “enter” keypress on the element. + else if ( target == P.$root[0] && ( keycodeToMove || keycode == 13 ) ) { + + // Prevent the default action to stop page movement. + event.preventDefault() + + // Trigger the key movement action. + if ( keycodeToMove ) { + PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] ) + } + + // On “enter”, if the highlighted item isn’t disabled, set the value and close. + else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) { + P.set( 'select', P.component.item.highlight ).close() + } + } + + + // If the target is within the root and “enter” is pressed, + // prevent the default action and trigger a click on the target instead. + else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { + event.preventDefault() + target.click() + } + }) + } + + // Trigger the queued “open” events. + return P.trigger( 'open' ) + }, //open + + + /** + * Close the picker + */ + close: function( giveFocus ) { + + // If we need to give focus, do it before changing states. + if ( giveFocus ) { + // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :| + // The focus is triggered *after* the close has completed - causing it + // to open again. So unbind and rebind the event at the next tick. + P.$root.off( 'focus.toOpen' ).eq(0).focus() + setTimeout( function() { + P.$root.on( 'focus.toOpen', handleFocusToOpenEvent ) + }, 0 ) + } + + // Remove the “active” class. + $ELEMENT.removeClass( CLASSES.active ) + aria( ELEMENT, 'expanded', false ) + + // * A Firefox bug, when `html` has `overflow:hidden`, results in + // killing transitions :(. So remove the “opened” state on the next tick. + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 + setTimeout( function() { + + // Remove the “opened” and “focused” class from the picker root. + P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) + aria( P.$root[0], 'hidden', true ) + + }, 0 ) + + // If it’s already closed, do nothing more. + if ( !STATE.open ) return P + + // Set it as closed. + STATE.open = false + + // Allow the page to scroll. + if ( IS_DEFAULT_THEME ) { + $html. + css( 'overflow', '' ). + css( 'padding-right', '-=' + getScrollbarWidth() ) + } + + // Unbind the document events. + $document.off( '.' + STATE.id ) + + // Trigger the queued “close” events. + return P.trigger( 'close' ) + }, //close + + + /** + * Clear the values + */ + clear: function( options ) { + return P.set( 'clear', null, options ) + }, //clear + + + /** + * Set something + */ + set: function( thing, value, options ) { + + var thingItem, thingValue, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + // Make sure we have usable options. + options = thingIsObject && $.isPlainObject( value ) ? value : options || {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = value + } + + // Go through the things of items to set. + for ( thingItem in thingObject ) { + + // Grab the value of the thing. + thingValue = thingObject[ thingItem ] + + // First, if the item exists and there’s a value, set it. + if ( thingItem in P.component.item ) { + if ( thingValue === undefined ) thingValue = null + P.component.set( thingItem, thingValue, options ) + } + + // Then, check to update the element value and broadcast a change. + if ( thingItem == 'select' || thingItem == 'clear' ) { + $ELEMENT. + val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ). + trigger( 'change' ) + } + } + + // Render a new picker. + P.render() + } + + // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`. + return options.muted ? P : P.trigger( 'set', thingObject ) + }, //set + + + /** + * Get something + */ + get: function( thing, format ) { + + // Make sure there’s something to get. + thing = thing || 'value' + + // If a picker state exists, return that. + if ( STATE[ thing ] != null ) { + return STATE[ thing ] + } + + // Return the submission value, if that. + if ( thing == 'valueSubmit' ) { + if ( P._hidden ) { + return P._hidden.value + } + thing = 'value' + } + + // Return the value, if that. + if ( thing == 'value' ) { + return ELEMENT.value + } + + // Check if a component item exists, return that. + if ( thing in P.component.item ) { + if ( typeof format == 'string' ) { + var thingValue = P.component.get( thing ) + return thingValue ? + PickerConstructor._.trigger( + P.component.formats.toString, + P.component, + [ format, thingValue ] + ) : '' + } + return P.component.get( thing ) + } + }, //get + + + + /** + * Bind events on the things. + */ + on: function( thing, method, internal ) { + + var thingName, thingMethod, + thingIsObject = $.isPlainObject( thing ), + thingObject = thingIsObject ? thing : {} + + if ( thing ) { + + // If the thing isn’t an object, make it one. + if ( !thingIsObject ) { + thingObject[ thing ] = method + } + + // Go through the things to bind to. + for ( thingName in thingObject ) { + + // Grab the method of the thing. + thingMethod = thingObject[ thingName ] + + // If it was an internal binding, prefix it. + if ( internal ) { + thingName = '_' + thingName + } + + // Make sure the thing methods collection exists. + STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] + + // Add the method to the relative method collection. + STATE.methods[ thingName ].push( thingMethod ) + } + } + + return P + }, //on + + + + /** + * Unbind events on the things. + */ + off: function() { + var i, thingName, + names = arguments; + for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { + thingName = names[i] + if ( thingName in STATE.methods ) { + delete STATE.methods[thingName] + } + } + return P + }, + + + /** + * Fire off method events. + */ + trigger: function( name, data ) { + var _trigger = function( name ) { + var methodList = STATE.methods[ name ] + if ( methodList ) { + methodList.map( function( method ) { + PickerConstructor._.trigger( method, P, [ data ] ) + }) + } + } + _trigger( '_' + name ) + _trigger( name ) + return P + } //trigger + } //PickerInstance.prototype + + + /** + * Wrap the picker holder components together. + */ + function createWrappedComponent() { + + // Create a picker wrapper holder + return PickerConstructor._.node( 'div', + + // Create a picker wrapper node + PickerConstructor._.node( 'div', + + // Create a picker frame + PickerConstructor._.node( 'div', + + // Create a picker box node + PickerConstructor._.node( 'div', + + // Create the components nodes. + P.component.nodes( STATE.open ), + + // The picker box class + CLASSES.box + ), + + // Picker wrap class + CLASSES.wrap + ), + + // Picker frame class + CLASSES.frame + ), + + // Picker holder class + CLASSES.holder + ) //endreturn + } //createWrappedComponent + + + + /** + * Prepare the input element with all bindings. + */ + function prepareElement() { + + $ELEMENT. + + // Store the picker data by component name. + data(NAME, P). + + // Add the “input” class name. + addClass(CLASSES.input). + + // Remove the tabindex. + attr('tabindex', -1). + + // If there’s a `data-value`, update the value of the element. + val( $ELEMENT.data('value') ? + P.get('select', SETTINGS.format) : + ELEMENT.value + ) + + + // Only bind keydown events if the element isn’t editable. + if ( !SETTINGS.editable ) { + + $ELEMENT. + + // On focus/click, focus onto the root to open it up. + on( 'focus.' + STATE.id + ' click.' + STATE.id, function( event ) { + event.preventDefault() + P.$root.eq(0).focus() + }). + + // Handle keyboard event based on the picker being opened or not. + on( 'keydown.' + STATE.id, handleKeydownEvent ) + } + + + // Update the aria attributes. + aria(ELEMENT, { + haspopup: true, + expanded: false, + readonly: false, + owns: ELEMENT.id + '_root' + }) + } + + + /** + * Prepare the root picker element with all bindings. + */ + function prepareElementRoot() { + + P.$root. + + on({ + + // For iOS8. + keydown: handleKeydownEvent, + + // When something within the root is focused, stop from bubbling + // to the doc and remove the “focused” state from the root. + focusin: function( event ) { + P.$root.removeClass( CLASSES.focused ) + event.stopPropagation() + }, + + // When something within the root holder is clicked, stop it + // from bubbling to the doc. + 'mousedown click': function( event ) { + + var target = event.target + + // Make sure the target isn’t the root holder so it can bubble up. + if ( target != P.$root.children()[ 0 ] ) { + + event.stopPropagation() + + // * For mousedown events, cancel the default action in order to + // prevent cases where focus is shifted onto external elements + // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). + // Also, for Firefox, don’t prevent action on the `option` element. + if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) { + + event.preventDefault() + + // Re-focus onto the root so that users can click away + // from elements focused within the picker. + P.$root.eq(0).focus() + } + } + } + }). + + // Add/remove the “target” class on focus and blur. + on({ + focus: function() { + $ELEMENT.addClass( CLASSES.target ) + }, + blur: function() { + $ELEMENT.removeClass( CLASSES.target ) + } + }). + + // Open the picker and adjust the root “focused” state + on( 'focus.toOpen', handleFocusToOpenEvent ). + + // If there’s a click on an actionable element, carry out the actions. + on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() { + + var $target = $( this ), + targetData = $target.data(), + targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ), + + // * For IE, non-focusable elements can be active elements as well + // (http://stackoverflow.com/a/2684561). + activeElement = getActiveElement() + activeElement = activeElement && ( activeElement.type || activeElement.href ) + + // If it’s disabled or nothing inside is actively focused, re-focus the element. + if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { + P.$root.eq(0).focus() + } + + // If something is superficially changed, update the `highlight` based on the `nav`. + if ( !targetDisabled && targetData.nav ) { + P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } ) + } + + // If something is picked, set `select` then close with focus. + else if ( !targetDisabled && 'pick' in targetData ) { + P.set( 'select', targetData.pick ) + } + + // If a “clear” button is pressed, empty the values and close with focus. + else if ( targetData.clear ) { + P.clear().close( true ) + } + + else if ( targetData.close ) { + P.close( true ) + } + + }) //P.$root + + aria( P.$root[0], 'hidden', true ) + } + + + /** + * Prepare the hidden input element along with all bindings. + */ + function prepareElementHidden() { + + var name + + if ( SETTINGS.hiddenName === true ) { + name = ELEMENT.name + ELEMENT.name = '' + } + else { + name = [ + typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', + typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' + ] + name = name[0] + ELEMENT.name + name[1] + } + + P._hidden = $( + '' + )[0] + + $ELEMENT. + + // If the value changes, update the hidden input with the correct format. + on('change.' + STATE.id, function() { + P._hidden.value = ELEMENT.value ? + P.get('select', SETTINGS.formatSubmit) : + '' + }) + + + // Insert the hidden input as specified in the settings. + if ( SETTINGS.container ) $( SETTINGS.container ).append( P._hidden ) + else $ELEMENT.after( P._hidden ) + } + + + // For iOS8. + function handleKeydownEvent( event ) { + + var keycode = event.keyCode, + + // Check if one of the delete keys was pressed. + isKeycodeDelete = /^(8|46)$/.test(keycode) + + // For some reason IE clears the input value on “escape”. + if ( keycode == 27 ) { + P.close() + return false + } + + // Check if `space` or `delete` was pressed or the picker is closed with a key movement. + if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { + + // Prevent it from moving the page and bubbling to doc. + event.preventDefault() + event.stopPropagation() + + // If `delete` was pressed, clear the values and close the picker. + // Otherwise open the picker. + if ( isKeycodeDelete ) { P.clear().close() } + else { P.open() } + } + } + + + // Separated for IE + function handleFocusToOpenEvent( event ) { + + // Stop the event from propagating to the doc. + event.stopPropagation() + + // If it’s a focus event, add the “focused” class to the root. + if ( event.type == 'focus' ) { + P.$root.addClass( CLASSES.focused ) + } + + // And then finally open the picker. + P.open() + } + + + // Return a new picker instance. + return new PickerInstance() +} //PickerConstructor + + + +/** + * The default classes and prefix to use for the HTML classes. + */ +PickerConstructor.klasses = function( prefix ) { + prefix = prefix || 'picker' + return { + + picker: prefix, + opened: prefix + '--opened', + focused: prefix + '--focused', + + input: prefix + '__input', + active: prefix + '__input--active', + target: prefix + '__input--target', + + holder: prefix + '__holder', + + frame: prefix + '__frame', + wrap: prefix + '__wrap', + + box: prefix + '__box' + } +} //PickerConstructor.klasses + + + +/** + * Check if the default theme is being used. + */ +function isUsingDefaultTheme( element ) { + + var theme, + prop = 'position' + + // For IE. + if ( element.currentStyle ) { + theme = element.currentStyle[prop] + } + + // For normal browsers. + else if ( window.getComputedStyle ) { + theme = getComputedStyle( element )[prop] + } + + return theme == 'fixed' +} + + + +/** + * Get the width of the browser’s scrollbar. + * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js + */ +function getScrollbarWidth() { + + if ( $html.height() <= $window.height() ) { + return 0 + } + + var $outer = $( '
                  ' ). + appendTo( 'body' ) + + // Get the width without scrollbars. + var widthWithoutScroll = $outer[0].offsetWidth + + // Force adding scrollbars. + $outer.css( 'overflow', 'scroll' ) + + // Add the inner div. + var $inner = $( '
                  ' ).appendTo( $outer ) + + // Get the width with scrollbars. + var widthWithScroll = $inner[0].offsetWidth + + // Remove the divs. + $outer.remove() + + // Return the difference between the widths. + return widthWithoutScroll - widthWithScroll +} + + + +/** + * PickerConstructor helper methods. + */ +PickerConstructor._ = { + + /** + * Create a group of nodes. Expects: + * ` + { + min: {Integer}, + max: {Integer}, + i: {Integer}, + node: {String}, + item: {Function} + } + * ` + */ + group: function( groupObject ) { + + var + // Scope for the looped object + loopObjectScope, + + // Create the nodes list + nodesList = '', + + // The counter starts from the `min` + counter = PickerConstructor._.trigger( groupObject.min, groupObject ) + + + // Loop from the `min` to `max`, incrementing by `i` + for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { + + // Trigger the `item` function within scope of the object + loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) + + // Splice the subgroup and create nodes out of the sub nodes + nodesList += PickerConstructor._.node( + groupObject.node, + loopObjectScope[ 0 ], // the node + loopObjectScope[ 1 ], // the classes + loopObjectScope[ 2 ] // the attributes + ) + } + + // Return the list of nodes + return nodesList + }, //group + + + /** + * Create a dom node string + */ + node: function( wrapper, item, klass, attribute ) { + + // If the item is false-y, just return an empty string + if ( !item ) return '' + + // If the item is an array, do a join + item = $.isArray( item ) ? item.join( '' ) : item + + // Check for the class + klass = klass ? ' class="' + klass + '"' : '' + + // Check for any attributes + attribute = attribute ? ' ' + attribute : '' + + // Return the wrapped item + return '<' + wrapper + klass + attribute + '>' + item + '' + }, //node + + + /** + * Lead numbers below 10 with a zero. + */ + lead: function( number ) { + return ( number < 10 ? '0': '' ) + number + }, + + + /** + * Trigger a function otherwise return the value. + */ + trigger: function( callback, scope, args ) { + return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback + }, + + + /** + * If the second character is a digit, length is 2 otherwise 1. + */ + digits: function( string ) { + return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 + }, + + + /** + * Tell if something is a date object. + */ + isDate: function( value ) { + return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) + }, + + + /** + * Tell if something is an integer. + */ + isInteger: function( value ) { + return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 + }, + + + /** + * Create ARIA attribute strings. + */ + ariaAttr: ariaAttr +} //PickerConstructor._ + + + +/** + * Extend the picker with a component and defaults. + */ +PickerConstructor.extend = function( name, Component ) { + + // Extend jQuery. + $.fn[ name ] = function( options, action ) { + + // Grab the component data. + var componentData = this.data( name ) + + // If the picker is requested, return the data object. + if ( options == 'picker' ) { + return componentData + } + + // If the component data exists and `options` is a string, carry out the action. + if ( componentData && typeof options == 'string' ) { + return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) + } + + // Otherwise go through each matched element and if the component + // doesn’t exist, create a new picker using `this` element + // and merging the defaults and options with a deep copy. + return this.each( function() { + var $this = $( this ) + if ( !$this.data( name ) ) { + new PickerConstructor( this, name, Component, options ) + } + }) + } + + // Set the defaults. + $.fn[ name ].defaults = Component.defaults +} //PickerConstructor.extend + + + +function aria(element, attribute, value) { + if ( $.isPlainObject(attribute) ) { + for ( var key in attribute ) { + ariaSet(element, key, attribute[key]) + } + } + else { + ariaSet(element, attribute, value) + } +} +function ariaSet(element, attribute, value) { + element.setAttribute( + (attribute == 'role' ? '' : 'aria-') + attribute, + value + ) +} +function ariaAttr(attribute, data) { + if ( !$.isPlainObject(attribute) ) { + attribute = { attribute: data } + } + data = '' + for ( var key in attribute ) { + var attr = (key == 'role' ? '' : 'aria-') + key, + attrVal = attribute[key] + data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' + } + return data +} + +// IE8 bug throws an error for activeElements within iframes. +function getActiveElement() { + try { + return document.activeElement + } catch ( err ) { } +} + + + +// Expose the picker constructor. +return PickerConstructor + + +})); + + diff --git a/assets/libs/materialize/js/dropdown.js b/assets/libs/materialize/js/dropdown.js new file mode 100644 index 0000000..11b6d22 --- /dev/null +++ b/assets/libs/materialize/js/dropdown.js @@ -0,0 +1,265 @@ +(function ($) { + + // Add posibility to scroll to selected option + // usefull for select for example + $.fn.scrollTo = function(elem) { + $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); + return this; + }; + + $.fn.dropdown = function (options) { + var defaults = { + inDuration: 300, + outDuration: 225, + constrain_width: true, // Constrains width of dropdown to the activator + hover: false, + gutter: 0, // Spacing from edge + belowOrigin: false, + alignment: 'left', + stopPropagation: false + }; + + // Open dropdown. + if (options === "open") { + this.each(function() { + $(this).trigger('open'); + }); + return false; + } + + // Close dropdown. + if (options === "close") { + this.each(function() { + $(this).trigger('close'); + }); + return false; + } + + this.each(function(){ + var origin = $(this); + var curr_options = $.extend({}, defaults, options); + var isFocused = false; + + // Dropdown menu + var activates = $("#"+ origin.attr('data-activates')); + + function updateOptions() { + if (origin.data('induration') !== undefined) + curr_options.inDuration = origin.data('induration'); + if (origin.data('outduration') !== undefined) + curr_options.outDuration = origin.data('outduration'); + if (origin.data('constrainwidth') !== undefined) + curr_options.constrain_width = origin.data('constrainwidth'); + if (origin.data('hover') !== undefined) + curr_options.hover = origin.data('hover'); + if (origin.data('gutter') !== undefined) + curr_options.gutter = origin.data('gutter'); + if (origin.data('beloworigin') !== undefined) + curr_options.belowOrigin = origin.data('beloworigin'); + if (origin.data('alignment') !== undefined) + curr_options.alignment = origin.data('alignment'); + if (origin.data('stoppropagation') !== undefined) + curr_options.stopPropagation = origin.data('stoppropagation'); + } + + updateOptions(); + + // Attach dropdown to its activator + origin.after(activates); + + /* + Helper function to position and resize dropdown. + Used in hover and click handler. + */ + function placeDropdown(eventType) { + // Check for simultaneous focus and click events. + if (eventType === 'focus') { + isFocused = true; + } + + // Check html data attributes + updateOptions(); + + // Set Dropdown state + activates.addClass('active'); + origin.addClass('active'); + + // Constrain width + if (curr_options.constrain_width === true) { + activates.css('width', origin.outerWidth()); + + } else { + activates.css('white-space', 'nowrap'); + } + + // Offscreen detection + var windowHeight = window.innerHeight; + var originHeight = origin.innerHeight(); + var offsetLeft = origin.offset().left; + var offsetTop = origin.offset().top - $(window).scrollTop(); + var currAlignment = curr_options.alignment; + var gutterSpacing = 0; + var leftPosition = 0; + + // Below Origin + var verticalOffset = 0; + if (curr_options.belowOrigin === true) { + verticalOffset = originHeight; + } + + // Check for scrolling positioned container. + var scrollYOffset = 0; + var scrollXOffset = 0; + var wrapper = origin.parent(); + if (!wrapper.is('body')) { + if (wrapper[0].scrollHeight > wrapper[0].clientHeight) { + scrollYOffset = wrapper[0].scrollTop; + } + if (wrapper[0].scrollWidth > wrapper[0].clientWidth) { + scrollXOffset = wrapper[0].scrollLeft; + } + } + + + if (offsetLeft + activates.innerWidth() > $(window).width()) { + // Dropdown goes past screen on right, force right alignment + currAlignment = 'right'; + + } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { + // Dropdown goes past screen on left, force left alignment + currAlignment = 'left'; + } + // Vertical bottom offscreen detection + if (offsetTop + activates.innerHeight() > windowHeight) { + // If going upwards still goes offscreen, just crop height of dropdown. + if (offsetTop + originHeight - activates.innerHeight() < 0) { + var adjustedHeight = windowHeight - offsetTop - verticalOffset; + activates.css('max-height', adjustedHeight); + } else { + // Flow upwards. + if (!verticalOffset) { + verticalOffset += originHeight; + } + verticalOffset -= activates.innerHeight(); + } + } + + // Handle edge alignment + if (currAlignment === 'left') { + gutterSpacing = curr_options.gutter; + leftPosition = origin.position().left + gutterSpacing; + } + else if (currAlignment === 'right') { + var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); + gutterSpacing = -curr_options.gutter; + leftPosition = offsetRight + gutterSpacing; + } + + // Position dropdown + activates.css({ + position: 'absolute', + top: origin.position().top + verticalOffset + scrollYOffset, + left: leftPosition + scrollXOffset + }); + + + // Show dropdown + activates.stop(true, true).css('opacity', 0) + .slideDown({ + queue: false, + duration: curr_options.inDuration, + easing: 'easeOutCubic', + complete: function() { + $(this).css('height', ''); + } + }) + .animate( {opacity: 1}, {queue: false, duration: curr_options.inDuration, easing: 'easeOutSine'}); + } + + function hideDropdown() { + // Check for simultaneous focus and click events. + isFocused = false; + activates.fadeOut(curr_options.outDuration); + activates.removeClass('active'); + origin.removeClass('active'); + setTimeout(function() { activates.css('max-height', ''); }, curr_options.outDuration); + } + + // Hover + if (curr_options.hover) { + var open = false; + origin.unbind('click.' + origin.attr('id')); + // Hover handler to show dropdown + origin.on('mouseenter', function(e){ // Mouse over + if (open === false) { + placeDropdown(); + open = true; + } + }); + origin.on('mouseleave', function(e){ + // If hover on origin then to something other than dropdown content, then close + var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element + if(!$(toEl).closest('.dropdown-content').is(activates)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + activates.on('mouseleave', function(e){ // Mouse out + var toEl = e.toElement || e.relatedTarget; + if(!$(toEl).closest('.dropdown-button').is(origin)) { + activates.stop(true, true); + hideDropdown(); + open = false; + } + }); + + // Click + } else { + // Click handler to show dropdown + origin.unbind('click.' + origin.attr('id')); + origin.bind('click.'+origin.attr('id'), function(e){ + if (!isFocused) { + if ( origin[0] == e.currentTarget && + !origin.hasClass('active') && + ($(e.target).closest('.dropdown-content').length === 0)) { + e.preventDefault(); // Prevents button click from moving window + if (curr_options.stopPropagation) { + e.stopPropagation(); + } + placeDropdown('click'); + } + // If origin is clicked and menu is open, close menu + else if (origin.hasClass('active')) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + // If menu open, add click close handler to document + if (activates.hasClass('active')) { + $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) { + if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) { + hideDropdown(); + $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + }); + } + } + }); + + } // End else + + // Listen to open and close event - useful for select component + origin.on('open', function(e, eventType) { + placeDropdown(eventType); + }); + origin.on('close', hideDropdown); + + + }); + }; // End dropdown plugin + + $(document).ready(function(){ + $('.dropdown-button').dropdown(); + }); +}( jQuery )); diff --git a/assets/libs/materialize/js/forms.js b/assets/libs/materialize/js/forms.js new file mode 100644 index 0000000..912402b --- /dev/null +++ b/assets/libs/materialize/js/forms.js @@ -0,0 +1,682 @@ +(function ($) { + $(document).ready(function() { + + // Function to update labels of text fields + Materialize.updateTextFields = function() { + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + $(input_selector).each(function(index, element) { + if ($(element).val().length > 0 || element.autofocus ||$(this).attr('placeholder') !== undefined || $(element)[0].validity.badInput === true) { + $(this).siblings('label').addClass('active'); + } + else { + $(this).siblings('label').removeClass('active'); + } + }); + }; + + // Text based inputs + var input_selector = 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], textarea'; + + // Add active if form auto complete + $(document).on('change', input_selector, function () { + if($(this).val().length !== 0 || $(this).attr('placeholder') !== undefined) { + $(this).siblings('label').addClass('active'); + } + validate_field($(this)); + }); + + // Add active if input element has been pre-populated on document ready + $(document).ready(function() { + Materialize.updateTextFields(); + }); + + // HTML DOM FORM RESET handling + $(document).on('reset', function(e) { + var formReset = $(e.target); + if (formReset.is('form')) { + formReset.find(input_selector).removeClass('valid').removeClass('invalid'); + formReset.find(input_selector).each(function () { + if ($(this).attr('value') === '') { + $(this).siblings('label').removeClass('active'); + } + }); + + // Reset select + formReset.find('select.initialized').each(function () { + var reset_text = formReset.find('option[selected]').text(); + formReset.siblings('input.select-dropdown').val(reset_text); + }); + } + }); + + // Add active when element has focus + $(document).on('focus', input_selector, function () { + $(this).siblings('label, .prefix').addClass('active'); + }); + + $(document).on('blur', input_selector, function () { + var $inputElement = $(this); + var selector = ".prefix"; + + if ($inputElement.val().length === 0 && $inputElement[0].validity.badInput !== true && $inputElement.attr('placeholder') === undefined) { + selector += ", label"; + } + + $inputElement.siblings(selector).removeClass('active'); + + validate_field($inputElement); + }); + + window.validate_field = function(object) { + var hasLength = object.attr('length') !== undefined; + var lenAttr = parseInt(object.attr('length')); + var len = object.val().length; + + if (object.val().length === 0 && object[0].validity.badInput === false) { + if (object.hasClass('validate')) { + object.removeClass('valid'); + object.removeClass('invalid'); + } + } + else { + if (object.hasClass('validate')) { + // Check for character counter attributes + if ((object.is(':valid') && hasLength && (len <= lenAttr)) || (object.is(':valid') && !hasLength)) { + object.removeClass('invalid'); + object.addClass('valid'); + } + else { + object.removeClass('valid'); + object.addClass('invalid'); + } + } + } + }; + + // Radio and Checkbox focus class + var radio_checkbox = 'input[type=radio], input[type=checkbox]'; + $(document).on('keyup.radio', radio_checkbox, function(e) { + // TAB, check if tabbing to radio or checkbox. + if (e.which === 9) { + $(this).addClass('tabbed'); + var $this = $(this); + $this.one('blur', function(e) { + + $(this).removeClass('tabbed'); + }); + return; + } + }); + + // Textarea Auto Resize + var hiddenDiv = $('.hiddendiv').first(); + if (!hiddenDiv.length) { + hiddenDiv = $('
                  '); + $('body').append(hiddenDiv); + } + var text_area_selector = '.materialize-textarea'; + + function textareaAutoResize($textarea) { + // Set font properties of hiddenDiv + + var fontFamily = $textarea.css('font-family'); + var fontSize = $textarea.css('font-size'); + var lineHeight = $textarea.css('line-height'); + + if (fontSize) { hiddenDiv.css('font-size', fontSize); } + if (fontFamily) { hiddenDiv.css('font-family', fontFamily); } + if (lineHeight) { hiddenDiv.css('line-height', lineHeight); } + + if ($textarea.attr('wrap') === "off") { + hiddenDiv.css('overflow-wrap', "normal") + .css('white-space', "pre"); + } + + hiddenDiv.text($textarea.val() + '\n'); + var content = hiddenDiv.html().replace(/\n/g, '
                  '); + hiddenDiv.html(content); + + + // When textarea is hidden, width goes crazy. + // Approximate with half of window size + + if ($textarea.is(':visible')) { + hiddenDiv.css('width', $textarea.width()); + } + else { + hiddenDiv.css('width', $(window).width()/2); + } + + $textarea.css('height', hiddenDiv.height()); + } + + $(text_area_selector).each(function () { + var $textarea = $(this); + if ($textarea.val().length) { + textareaAutoResize($textarea); + } + }); + + $('body').on('keyup keydown autoresize', text_area_selector, function () { + textareaAutoResize($(this)); + }); + + // File Input Path + $(document).on('change', '.file-field input[type="file"]', function () { + var file_field = $(this).closest('.file-field'); + var path_input = file_field.find('input.file-path'); + var files = $(this)[0].files; + var file_names = []; + for (var i = 0; i < files.length; i++) { + file_names.push(files[i].name); + } + path_input.val(file_names.join(", ")); + path_input.trigger('change'); + }); + + /**************** + * Range Input * + ****************/ + + var range_type = 'input[type=range]'; + var range_mousedown = false; + var left; + + $(range_type).each(function () { + var thumb = $(''); + $(this).after(thumb); + }); + + var range_wrapper = '.range-field'; + $(document).on('change', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + thumb.find('.value').html($(this).val()); + }); + + $(document).on('input mousedown touchstart', range_type, function(e) { + var thumb = $(this).siblings('.thumb'); + var width = $(this).outerWidth(); + + // If thumb indicator does not exist yet, create it + if (thumb.length <= 0) { + thumb = $(''); + $(this).after(thumb); + } + + // Set indicator value + thumb.find('.value').html($(this).val()); + + range_mousedown = true; + $(this).addClass('active'); + + if (!thumb.hasClass('active')) { + thumb.velocity({ height: "30px", width: "30px", top: "-20px", marginLeft: "-15px"}, { duration: 300, easing: 'easeOutExpo' }); + } + + if (e.type !== 'input') { + if(e.pageX === undefined || e.pageX === null){//mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + } + + thumb.find('.value').html($(this).val()); + }); + + $(document).on('mouseup touchend', range_wrapper, function() { + range_mousedown = false; + $(this).removeClass('active'); + }); + + $(document).on('mousemove touchmove', range_wrapper, function(e) { + var thumb = $(this).children('.thumb'); + var left; + if (range_mousedown) { + if (!thumb.hasClass('active')) { + thumb.velocity({ height: '30px', width: '30px', top: '-20px', marginLeft: '-15px'}, { duration: 300, easing: 'easeOutExpo' }); + } + if (e.pageX === undefined || e.pageX === null) { //mobile + left = e.originalEvent.touches[0].pageX - $(this).offset().left; + } + else{ // desktop + left = e.pageX - $(this).offset().left; + } + var width = $(this).outerWidth(); + + if (left < 0) { + left = 0; + } + else if (left > width) { + left = width; + } + thumb.addClass('active').css('left', left); + thumb.find('.value').html(thumb.siblings(range_type).val()); + } + }); + + $(document).on('mouseout touchleave', range_wrapper, function() { + if (!range_mousedown) { + + var thumb = $(this).children('.thumb'); + + if (thumb.hasClass('active')) { + thumb.velocity({ height: '0', width: '0', top: '10px', marginLeft: '-6px'}, { duration: 100 }); + } + thumb.removeClass('active'); + } + }); + + /************************** + * Auto complete plugin * + *************************/ + $.fn.autocomplete = function (options) { + // Defaults + var defaults = { + data: {} + }; + + options = $.extend(defaults, options); + + return this.each(function() { + var $input = $(this); + var data = options.data, + $inputDiv = $input.closest('.input-field'); // Div to append on + + // Check if data isn't empty + if (!$.isEmptyObject(data)) { + // Create autocomplete element + var $autocomplete = $(''); + + // Append autocomplete element + if ($inputDiv.length) { + $inputDiv.append($autocomplete); // Set ul in body + } else { + $input.after($autocomplete); + } + + var highlight = function(string, $el) { + var img = $el.find('img'); + var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""), + matchEnd = matchStart + string.length - 1, + beforeMatch = $el.text().slice(0, matchStart), + matchText = $el.text().slice(matchStart, matchEnd + 1), + afterMatch = $el.text().slice(matchEnd + 1); + $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + ""); + if (img.length) { + $el.prepend(img); + } + }; + + // Perform search + $input.on('keyup', function (e) { + // Capture Enter + if (e.which === 13) { + $autocomplete.find('li').first().click(); + return; + } + + var val = $input.val().toLowerCase(); + $autocomplete.empty(); + + // Check if the input isn't empty + if (val !== '') { + for(var key in data) { + if (data.hasOwnProperty(key) && + key.toLowerCase().indexOf(val) !== -1 && + key.toLowerCase() !== val) { + var autocompleteOption = $('
                • '); + if(!!data[key]) { + autocompleteOption.append(''+ key +''); + } else { + autocompleteOption.append(''+ key +''); + } + $autocomplete.append(autocompleteOption); + + highlight(val, autocompleteOption); + } + } + } + }); + + // Set input value + $autocomplete.on('click', 'li', function () { + $input.val($(this).text().trim()); + $input.trigger('change'); + $autocomplete.empty(); + }); + } + }); + }; + + }); // End of $(document).ready + + /******************* + * Select Plugin * + ******************/ + $.fn.material_select = function (callback) { + $(this).each(function(){ + var $select = $(this); + + if ($select.hasClass('browser-default')) { + return; // Continue to next (return false breaks out of entire loop) + } + + var multiple = $select.attr('multiple') ? true : false, + lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt + + if (lastID) { + $select.parent().find('span.caret').remove(); + $select.parent().find('input').remove(); + + $select.unwrap(); + $('ul#select-options-'+lastID).remove(); + } + + // If destroying the select, remove the selelct-id and reset it to it's uninitialized state. + if(callback === 'destroy') { + $select.data('select-id', null).removeClass('initialized'); + return; + } + + var uniqueID = Materialize.guid(); + $select.data('select-id', uniqueID); + var wrapper = $('
                  '); + wrapper.addClass($select.attr('class')); + var options = $(''), + selectChildren = $select.children('option, optgroup'), + valuesSelected = [], + optionsHover = false; + + var label = $select.find('option:selected').html() || $select.find('option:first').html() || ""; + + // Function that renders and appends the option taking into + // account type and possible image icon. + var appendOptionWithIcon = function(select, option, type) { + // Add disabled attr if disabled + var disabledClass = (option.is(':disabled')) ? 'disabled ' : ''; + var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : ''; + + // add icons + var icon_url = option.data('icon'); + var classes = option.attr('class'); + if (!!icon_url) { + var classString = ''; + if (!!classes) classString = ' class="' + classes + '"'; + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
                • ' + option.html() + '
                • ')); + } else { + options.append($('
                • ' + option.html() + '
                • ')); + } + return true; + } + + // Check for multiple type. + if (type === 'multiple') { + options.append($('
                • ' + option.html() + '
                • ')); + } else { + options.append($('
                • ' + option.html() + '
                • ')); + } + }; + + /* Create dropdown structure. */ + if (selectChildren.length) { + selectChildren.each(function() { + if ($(this).is('option')) { + // Direct descendant option. + if (multiple) { + appendOptionWithIcon($select, $(this), 'multiple'); + + } else { + appendOptionWithIcon($select, $(this)); + } + } else if ($(this).is('optgroup')) { + // Optgroup. + var selectOptions = $(this).children('option'); + options.append($('
                • ' + $(this).attr('label') + '
                • ')); + + selectOptions.each(function() { + appendOptionWithIcon($select, $(this), 'optgroup-option'); + }); + } + }); + } + + options.find('li:not(.optgroup)').each(function (i) { + $(this).click(function (e) { + // Check if option element is disabled + if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) { + var selected = true; + + if (multiple) { + $('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; }); + selected = toggleEntryFromArray(valuesSelected, $(this).index(), $select); + $newSelect.trigger('focus'); + } else { + options.find('li').removeClass('active'); + $(this).toggleClass('active'); + $newSelect.val($(this).text()); + } + + activateOption(options, $(this)); + $select.find('option').eq(i).prop('selected', selected); + // Trigger onchange() event + $select.trigger('change'); + if (typeof callback !== 'undefined') callback(); + } + + e.stopPropagation(); + }); + }); + + // Wrap Elements + $select.wrap(wrapper); + // Add Select Display Element + var dropdownIcon = $(''); + if ($select.is(':disabled')) + dropdownIcon.addClass('disabled'); + + // escape double quotes + var sanitizedLabelHtml = label.replace(/"/g, '"'); + + var $newSelect = $(''); + $select.before($newSelect); + $newSelect.before(dropdownIcon); + + $newSelect.after(options); + // Check if section element is disabled + if (!$select.is(':disabled')) { + $newSelect.dropdown({'hover': false, 'closeOnClick': false}); + } + + // Copy tabindex + if ($select.attr('tabindex')) { + $($newSelect[0]).attr('tabindex', $select.attr('tabindex')); + } + + $select.addClass('initialized'); + + $newSelect.on({ + 'focus': function (){ + if ($('ul.select-dropdown').not(options[0]).is(':visible')) { + $('input.select-dropdown').trigger('close'); + } + if (!options.is(':visible')) { + $(this).trigger('open', ['focus']); + var label = $(this).val(); + var selectedOption = options.find('li').filter(function() { + return $(this).text().toLowerCase() === label.toLowerCase(); + })[0]; + activateOption(options, selectedOption); + } + }, + 'click': function (e){ + e.stopPropagation(); + } + }); + + $newSelect.on('blur', function() { + if (!multiple) { + $(this).trigger('close'); + } + options.find('li.selected').removeClass('selected'); + }); + + options.hover(function() { + optionsHover = true; + }, function () { + optionsHover = false; + }); + + $(window).on({ + 'click': function () { + multiple && (optionsHover || $newSelect.trigger('close')); + } + }); + + // Add initial multiple selections. + if (multiple) { + $select.find("option:selected:not(:disabled)").each(function () { + var index = $(this).index(); + + toggleEntryFromArray(valuesSelected, index, $select); + options.find("li").eq(index).find(":checkbox").prop("checked", true); + }); + } + + // Make option as selected and scroll to selected position + var activateOption = function(collection, newOption) { + if (newOption) { + collection.find('li.selected').removeClass('selected'); + var option = $(newOption); + option.addClass('selected'); + options.scrollTo(option); + } + }; + + // Allow user to search by typing + // this array is cleared after 1 second + var filterQuery = [], + onKeyDown = function(e){ + // TAB - switch to another input + if(e.which == 9){ + $newSelect.trigger('close'); + return; + } + + // ARROW DOWN WHEN SELECT IS CLOSED - open select options + if(e.which == 40 && !options.is(':visible')){ + $newSelect.trigger('open'); + return; + } + + // ENTER WHEN SELECT IS CLOSED - submit form + if(e.which == 13 && !options.is(':visible')){ + return; + } + + e.preventDefault(); + + // CASE WHEN USER TYPE LETTERS + var letter = String.fromCharCode(e.which).toLowerCase(), + nonLetters = [9,13,27,38,40]; + if (letter && (nonLetters.indexOf(e.which) === -1)) { + filterQuery.push(letter); + + var string = filterQuery.join(''), + newOption = options.find('li').filter(function() { + return $(this).text().toLowerCase().indexOf(string) === 0; + })[0]; + + if (newOption) { + activateOption(options, newOption); + } + } + + // ENTER - select option and close when select options are opened + if (e.which == 13) { + var activeOption = options.find('li.selected:not(.disabled)')[0]; + if(activeOption){ + $(activeOption).trigger('click'); + if (!multiple) { + $newSelect.trigger('close'); + } + } + } + + // ARROW DOWN - move to next not disabled option + if (e.which == 40) { + if (options.find('li.selected').length) { + newOption = options.find('li.selected').next('li:not(.disabled)')[0]; + } else { + newOption = options.find('li:not(.disabled)')[0]; + } + activateOption(options, newOption); + } + + // ESC - close options + if (e.which == 27) { + $newSelect.trigger('close'); + } + + // ARROW UP - move to previous not disabled option + if (e.which == 38) { + newOption = options.find('li.selected').prev('li:not(.disabled)')[0]; + if(newOption) + activateOption(options, newOption); + } + + // Automaticaly clean filter query so user can search again by starting letters + setTimeout(function(){ filterQuery = []; }, 1000); + }; + + $newSelect.on('keydown', onKeyDown); + }); + + function toggleEntryFromArray(entriesArray, entryIndex, select) { + var index = entriesArray.indexOf(entryIndex), + notAdded = index === -1; + + if (notAdded) { + entriesArray.push(entryIndex); + } else { + entriesArray.splice(index, 1); + } + + select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active'); + + // use notAdded instead of true (to detect if the option is selected or not) + select.find('option').eq(entryIndex).prop('selected', notAdded); + setValueToInput(entriesArray, select); + + return notAdded; + } + + function setValueToInput(entriesArray, select) { + var value = ''; + + for (var i = 0, count = entriesArray.length; i < count; i++) { + var text = select.find('option').eq(entriesArray[i]).text(); + + i === 0 ? value += text : value += ', ' + text; + } + + if (value === '') { + value = select.find('option:disabled').eq(0).text(); + } + + select.siblings('input.select-dropdown').val(value); + } + }; + +}( jQuery )); diff --git a/assets/libs/materialize/js/global.js b/assets/libs/materialize/js/global.js new file mode 100644 index 0000000..a548a02 --- /dev/null +++ b/assets/libs/materialize/js/global.js @@ -0,0 +1,98 @@ +// Required for Meteor package, the use of window prevents export by Meteor +(function(window){ + if(window.Package){ + Materialize = {}; + } else { + window.Materialize = {}; + } +})(window); + + +/* + * raf.js + * https://github.com/ngryman/raf.js + * + * original requestAnimationFrame polyfill by Erik Möller + * inspired from paul_irish gist and post + * + * Copyright (c) 2013 ngryman + * Licensed under the MIT license. + */ +(function(window) { + var lastTime = 0, + vendors = ['webkit', 'moz'], + requestAnimationFrame = window.requestAnimationFrame, + cancelAnimationFrame = window.cancelAnimationFrame, + i = vendors.length; + + // try to un-prefix existing raf + while (--i >= 0 && !requestAnimationFrame) { + requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; + cancelAnimationFrame = window[vendors[i] + 'CancelRequestAnimationFrame']; + } + + // polyfill with setTimeout fallback + // heavily inspired from @darius gist mod: https://gist.github.com/paulirish/1579671#comment-837945 + if (!requestAnimationFrame || !cancelAnimationFrame) { + requestAnimationFrame = function(callback) { + var now = +Date.now(), + nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { + callback(lastTime = nextTime); + }, nextTime - now); + }; + + cancelAnimationFrame = clearTimeout; + } + + // export to window + window.requestAnimationFrame = requestAnimationFrame; + window.cancelAnimationFrame = cancelAnimationFrame; +}(window)); + + +// Unique ID +Materialize.guid = (function() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return function() { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + + s4() + '-' + s4() + s4() + s4(); + }; +})(); + +/** + * Escapes hash from special characters + * @param {string} hash String returned from this.hash + * @returns {string} + */ +Materialize.escapeHash = function(hash) { + return hash.replace( /(:|\.|\[|\]|,|=)/g, "\\$1" ); +}; + +Materialize.elementOrParentIsFixed = function(element) { + var $element = $(element); + var $checkElements = $element.add($element.parents()); + var isFixed = false; + $checkElements.each(function(){ + if ($(this).css("position") === "fixed") { + isFixed = true; + return false; + } + }); + return isFixed; +}; + +// Velocity has conflicts when loaded with jQuery, this will check for it +// First, check if in noConflict mode +var Vel; +if (jQuery) { + Vel = jQuery.Velocity; +} else if ($) { + Vel = $.Velocity; +} else { + Vel = Velocity; +} diff --git a/assets/libs/materialize/js/hammer.min.js b/assets/libs/materialize/js/hammer.min.js new file mode 100644 index 0000000..6c232c8 --- /dev/null +++ b/assets/libs/materialize/js/hammer.min.js @@ -0,0 +1 @@ +!function(a,b,c,d){"use strict";function k(a,b,c){return setTimeout(q(a,c),b)}function l(a,b,c){return Array.isArray(a)?(m(a,c[b],c),!0):!1}function m(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e-1}function x(a){return a.trim().split(/\s+/g)}function y(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function B(a,b){for(var c,f,g=b[0].toUpperCase()+b.slice(1),h=0;h1&&!c.firstMultiple?c.firstMultiple=gb(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=hb(d);b.timeStamp=j(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=lb(h,i),b.distance=kb(h,i),eb(c,b),b.offsetDirection=jb(b.deltaX,b.deltaY),b.scale=g?nb(g.pointers,d):1,b.rotation=g?mb(g.pointers,d):0,fb(c,b);var k=a.element;v(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function eb(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};(b.eventType===O||f.eventType===Q)&&(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function fb(a,b){var f,g,h,j,c=a.lastInterval||b,e=b.timeStamp-c.timeStamp;if(b.eventType!=R&&(e>N||c.velocity===d)){var k=c.deltaX-b.deltaX,l=c.deltaY-b.deltaY,m=ib(e,k,l);g=m.x,h=m.y,f=i(m.x)>i(m.y)?m.x:m.y,j=jb(k,l),a.lastInterval=b}else f=c.velocity,g=c.velocityX,h=c.velocityY,j=c.direction;b.velocity=f,b.velocityX=g,b.velocityY=h,b.direction=j}function gb(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:h(c/b),y:h(d/b)}}function ib(a,b,c){return{x:b/a||0,y:c/a||0}}function jb(a,b){return a===b?S:i(a)>=i(b)?a>0?T:U:b>0?V:W}function kb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function lb(a,b,c){c||(c=$);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function mb(a,b){return lb(b[1],b[0],_)-lb(a[1],a[0],_)}function nb(a,b){return kb(b[0],b[1],_)/kb(a[0],a[1],_)}function rb(){this.evEl=pb,this.evWin=qb,this.allow=!0,this.pressed=!1,ab.apply(this,arguments)}function wb(){this.evEl=ub,this.evWin=vb,ab.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function Ab(){this.evTarget=yb,this.evWin=zb,this.started=!1,ab.apply(this,arguments)}function Bb(a,b){var c=z(a.touches),d=z(a.changedTouches);return b&(Q|R)&&(c=A(c.concat(d),"identifier",!0)),[c,d]}function Eb(){this.evTarget=Db,this.targetIds={},ab.apply(this,arguments)}function Fb(a,b){var c=z(a.touches),d=this.targetIds;if(b&(O|P)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=z(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return v(a.target,i)}),b===O)for(e=0;eh&&(b.push(a),h=b.length-1):e&(Q|R)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var xb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},yb="touchstart",zb="touchstart touchmove touchend touchcancel";p(Ab,ab,{handler:function(a){var b=xb[a.type];if(b===O&&(this.started=!0),this.started){var c=Bb.call(this,a,b);b&(Q|R)&&0===c[0].length-c[1].length&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}});var Cb={touchstart:O,touchmove:P,touchend:Q,touchcancel:R},Db="touchstart touchmove touchend touchcancel";p(Eb,ab,{handler:function(a){var b=Cb[a.type],c=Fb.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:J,srcEvent:a})}}),p(Gb,ab,{handler:function(a,b,c){var d=c.pointerType==J,e=c.pointerType==L;if(d)this.mouse.allow=!1;else if(e&&!this.mouse.allow)return;b&(Q|R)&&(this.mouse.allow=!0),this.callback(a,b,c)},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var Hb=B(f.style,"touchAction"),Ib=Hb!==d,Jb="compute",Kb="auto",Lb="manipulation",Mb="none",Nb="pan-x",Ob="pan-y";Pb.prototype={set:function(a){a==Jb&&(a=this.compute()),Ib&&(this.manager.element.style[Hb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return m(this.manager.recognizers,function(b){r(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),Qb(a.join(" "))},preventDefaults:function(a){if(!Ib){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return b.preventDefault(),void 0;var d=this.actions,e=w(d,Mb),f=w(d,Ob),g=w(d,Nb);return e||f&&c&X||g&&c&Y?this.preventSrc(b):void 0}},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var Rb=1,Sb=2,Tb=4,Ub=8,Vb=Ub,Wb=16,Xb=32;Yb.prototype={defaults:{},set:function(a){return n(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(l(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_b(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return l(a,"dropRecognizeWith",this)?this:(a=_b(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(l(a,"requireFailure",this))return this;var b=this.requireFail;return a=_b(a,this),-1===y(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(l(a,"dropRequireFailure",this))return this;a=_b(a,this);var b=y(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function d(d){b.manager.emit(b.options.event+(d?Zb(c):""),a)}var b=this,c=this.state;Ub>c&&d(!0),d(),c>=Ub&&d(!0)},tryEmit:function(a){return this.canEmit()?this.emit(a):(this.state=Xb,void 0)},canEmit:function(){for(var a=0;af?T:U,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?S:0>g?V:W,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return ac.prototype.attrTest.call(this,a)&&(this.state&Sb||!(this.state&Sb)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this._super.emit.call(this,a)}}),p(cc,ac,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&Sb)},emit:function(a){if(this._super.emit.call(this,a),1!==a.scale){var b=a.scale<1?"in":"out";this.manager.emit(this.options.event+b,a)}}}),p(dc,Yb,{defaults:{event:"press",pointers:1,time:500,threshold:5},getTouchAction:function(){return[Kb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Q|R)&&!e)this.reset();else if(a.eventType&O)this.reset(),this._timer=k(function(){this.state=Vb,this.tryEmit()},b.time,this);else if(a.eventType&Q)return Vb;return Xb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===Vb&&(a&&a.eventType&Q?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=j(),this.manager.emit(this.options.event,this._input)))}}),p(ec,ac,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[Mb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&Sb)}}),p(fc,ac,{defaults:{event:"swipe",threshold:10,velocity:.65,direction:X|Y,pointers:1},getTouchAction:function(){return bc.prototype.getTouchAction.call(this)},attrTest:function(a){var c,b=this.options.direction;return b&(X|Y)?c=a.velocity:b&X?c=a.velocityX:b&Y&&(c=a.velocityY),this._super.attrTest.call(this,a)&&b&a.direction&&a.distance>this.options.threshold&&i(c)>this.options.velocity&&a.eventType&Q},emit:function(a){var b=$b(a.direction);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),p(gc,Yb,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:2,posThreshold:10},getTouchAction:function(){return[Lb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance
                  ').addClass('material-placeholder'); + var originalWidth = 0; + var originalHeight = 0; + var ancestorsChanged; + var ancestor; + origin.wrap(placeholder); + + + origin.on('click', function(){ + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.width(); + var originalHeight = origin.height(); + + + // If already modal, return to original + if (doneAnimating === false) { + returnToOriginal(); + return false; + } + else if (overlayActive && doneAnimating===true) { + returnToOriginal(); + return false; + } + + + // Set states + doneAnimating = false; + origin.addClass('active'); + overlayActive = true; + + // Set positioning for placeholder + placeholder.css({ + width: placeholder[0].getBoundingClientRect().width, + height: placeholder[0].getBoundingClientRect().height, + position: 'relative', + top: 0, + left: 0 + }); + + // Find ancestor with overflow: hidden; and remove it + ancestorsChanged = undefined; + ancestor = placeholder[0].parentNode; + var count = 0; + while (ancestor !== null && !$(ancestor).is(document)) { + var curr = $(ancestor); + if (curr.css('overflow') !== 'visible') { + curr.css('overflow', 'visible'); + if (ancestorsChanged === undefined) { + ancestorsChanged = curr; + } + else { + ancestorsChanged = ancestorsChanged.add(curr); + } + } + ancestor = ancestor.parentNode; + } + + // Set css on origin + origin.css({position: 'absolute', 'z-index': 1000}) + .data('width', originalWidth) + .data('height', originalHeight); + + // Add overlay + var overlay = $('
                  ') + .css({ + opacity: 0 + }) + .click(function(){ + if (doneAnimating === true) + returnToOriginal(); + }); + // Animate Overlay + // Put before in origin image to preserve z-index layering. + origin.before(overlay); + overlay.velocity({opacity: 1}, + {duration: inDuration, queue: false, easing: 'easeOutQuad'} ); + + // Add and animate caption if it exists + if (origin.data('caption') !== "") { + var $photo_caption = $('
                  '); + $photo_caption.text(origin.data('caption')); + $('body').append($photo_caption); + $photo_caption.css({ "display": "inline" }); + $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'}); + } + + // Resize Image + var ratio = 0; + var widthPercent = originalWidth / windowWidth; + var heightPercent = originalHeight / windowHeight; + var newWidth = 0; + var newHeight = 0; + + if (widthPercent > heightPercent) { + ratio = originalHeight / originalWidth; + newWidth = windowWidth * 0.9; + newHeight = windowWidth * 0.9 * ratio; + } + else { + ratio = originalWidth / originalHeight; + newWidth = (windowHeight * 0.9) * ratio; + newHeight = windowHeight * 0.9; + } + + // Animate image + set z-index + if(origin.hasClass('responsive-img')) { + origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false, + complete: function(){ + origin.css({left: 0, top: 0}) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); + } // End Complete + }); // End Velocity + } + else { + origin.css('left', 0) + .css('top', 0) + .velocity( + { + height: newHeight, + width: newWidth, + left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2, + top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2 + }, + { + duration: inDuration, + queue: false, + easing: 'easeOutQuad', + complete: function(){doneAnimating = true;} + } + ); // End Velocity + } + + }); // End origin on click + + + // Return on scroll + $(window).scroll(function() { + if (overlayActive) { + returnToOriginal(); + } + }); + + // Return on ESC + $(document).keyup(function(e) { + + if (e.keyCode === 27 && doneAnimating === true) { // ESC key + if (overlayActive) { + returnToOriginal(); + } + } + }); + + + // This function returns the modaled image to the original spot + function returnToOriginal() { + + doneAnimating = false; + + var placeholder = origin.parent('.material-placeholder'); + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var originalWidth = origin.data('width'); + var originalHeight = origin.data('height'); + + origin.velocity("stop", true); + $('#materialbox-overlay').velocity("stop", true); + $('.materialbox-caption').velocity("stop", true); + + + $('#materialbox-overlay').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + // Remove Overlay + overlayActive = false; + $(this).remove(); + } + }); + + // Resize Image + origin.velocity( + { + width: originalWidth, + height: originalHeight, + left: 0, + top: 0 + }, + { + duration: outDuration, + queue: false, easing: 'easeOutQuad' + } + ); + + // Remove Caption + reset css settings on image + $('.materialbox-caption').velocity({opacity: 0}, { + duration: outDuration, // Delay prevents animation overlapping + queue: false, easing: 'easeOutQuad', + complete: function(){ + placeholder.css({ + height: '', + width: '', + position: '', + top: '', + left: '' + }); + + origin.css({ + height: '', + top: '', + left: '', + width: '', + 'max-width': '', + position: '', + 'z-index': '' + }); + + // Remove class + origin.removeClass('active'); + doneAnimating = true; + $(this).remove(); + + // Remove overflow overrides on ancestors + if (ancestorsChanged) { + ancestorsChanged.css('overflow', ''); + } + } + }); + + } + }); +}; + +$(document).ready(function(){ + $('.materialboxed').materialbox(); +}); + +}( jQuery )); diff --git a/assets/libs/materialize/js/modal.js b/assets/libs/materialize/js/modal.js new file mode 100644 index 0000000..3a64e3c --- /dev/null +++ b/assets/libs/materialize/js/modal.js @@ -0,0 +1,184 @@ +(function($) { + var _stack = 0, + _lastID = 0, + _generateID = function() { + _lastID++; + return 'materialize-modal-overlay-' + _lastID; + }; + + var methods = { + init : function(options) { + var defaults = { + opacity: 0.5, + in_duration: 350, + out_duration: 250, + ready: undefined, + complete: undefined, + dismissible: true, + starting_top: '4%', + ending_top: '10%' + }; + + // Override defaults + options = $.extend(defaults, options); + + return this.each(function() { + var $modal = $(this); + var modal_id = $(this).attr("id") || '#' + $(this).data('target'); + + var closeModal = function() { + var overlayID = $modal.data('overlay-id'); + var $overlay = $('#' + overlayID); + $modal.removeClass('open'); + + // Enable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $modal.find('.modal-close').off('click.close'); + $(document).off('keyup.modal' + overlayID); + + $overlay.velocity( { opacity: 0}, {duration: options.out_duration, queue: false, ease: "easeOutQuart"}); + + + // Define Bottom Sheet animation + var exitVelocityOptions = { + duration: options.out_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + $(this).css({display:"none"}); + + // Call complete callback + if (typeof(options.complete) === "function") { + options.complete.call(this, $modal); + } + $overlay.remove(); + _stack--; + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "-100%", opacity: 0}, exitVelocityOptions); + } + else { + $modal.velocity( + { top: options.starting_top, opacity: 0, scaleX: 0.7}, + exitVelocityOptions + ); + } + }; + + var openModal = function($trigger) { + var $body = $('body'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + if ($modal.hasClass('open')) { + return; + } + + var overlayID = _generateID(); + var $overlay = $(''); + lStack = (++_stack); + + // Store a reference of the overlay + $overlay.attr('id', overlayID).css('z-index', 1000 + lStack * 2); + $modal.data('overlay-id', overlayID).css('z-index', 1000 + lStack * 2 + 1); + $modal.addClass('open'); + + $("body").append($overlay); + + if (options.dismissible) { + $overlay.click(function() { + closeModal(); + }); + // Return on ESC + $(document).on('keyup.modal' + overlayID, function(e) { + if (e.keyCode === 27) { // ESC key + closeModal(); + } + }); + } + + $modal.find(".modal-close").on('click.close', function(e) { + closeModal(); + }); + + $overlay.css({ display : "block", opacity : 0 }); + + $modal.css({ + display : "block", + opacity: 0 + }); + + $overlay.velocity({opacity: options.opacity}, {duration: options.in_duration, queue: false, ease: "easeOutCubic"}); + $modal.data('associated-overlay', $overlay[0]); + + // Define Bottom Sheet animation + var enterVelocityOptions = { + duration: options.in_duration, + queue: false, + ease: "easeOutCubic", + // Handle modal ready callback + complete: function() { + if (typeof(options.ready) === "function") { + options.ready.call(this, $modal, $trigger); + } + } + }; + if ($modal.hasClass('bottom-sheet')) { + $modal.velocity({bottom: "0", opacity: 1}, enterVelocityOptions); + } + else { + $.Velocity.hook($modal, "scaleX", 0.7); + $modal.css({ top: options.starting_top }); + $modal.velocity({top: options.ending_top, opacity: 1, scaleX: '1'}, enterVelocityOptions); + } + + }; + + // Reset handlers + $(document).off('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]'); + $(this).off('openModal'); + $(this).off('closeModal'); + + // Close Handlers + $(document).on('click.modalTrigger', 'a[href="#' + modal_id + '"], [data-target="' + modal_id + '"]', function(e) { + options.starting_top = ($(this).offset().top - $(window).scrollTop()) /1.15; + openModal($(this)); + e.preventDefault(); + }); // done set on click + + $(this).on('openModal', function() { + var modal_id = $(this).attr("href") || '#' + $(this).data('target'); + openModal(); + }); + + $(this).on('closeModal', function() { + closeModal(); + }); + }); // done return + }, + open : function() { + $(this).trigger('openModal'); + }, + close : function() { + $(this).trigger('closeModal'); + } + }; + + $.fn.modal = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.modal' ); + } + }; +})(jQuery); diff --git a/assets/libs/materialize/js/parallax.js b/assets/libs/materialize/js/parallax.js new file mode 100644 index 0000000..fc7856f --- /dev/null +++ b/assets/libs/materialize/js/parallax.js @@ -0,0 +1,58 @@ +(function ($) { + + $.fn.parallax = function () { + var window_width = $(window).width(); + // Parallax Scripts + return this.each(function(i) { + var $this = $(this); + $this.addClass('parallax'); + + function updateParallax(initial) { + var container_height; + if (window_width < 601) { + container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height(); + } + else { + container_height = ($this.height() > 0) ? $this.height() : 500; + } + var $img = $this.children("img").first(); + var img_height = $img.height(); + var parallax_dist = img_height - container_height; + var bottom = $this.offset().top + container_height; + var top = $this.offset().top; + var scrollTop = $(window).scrollTop(); + var windowHeight = window.innerHeight; + var windowBottom = scrollTop + windowHeight; + var percentScrolled = (windowBottom - top) / (container_height + windowHeight); + var parallax = Math.round((parallax_dist * percentScrolled)); + + if (initial) { + $img.css('display', 'block'); + } + if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) { + $img.css('transform', "translate3D(-50%," + parallax + "px, 0)"); + } + + } + + // Wait for image load + $this.children("img").one("load", function() { + updateParallax(true); + }).each(function() { + if (this.complete) $(this).trigger("load"); + }); + + $(window).scroll(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + $(window).resize(function() { + window_width = $(window).width(); + updateParallax(false); + }); + + }); + + }; +}( jQuery )); diff --git a/assets/libs/materialize/js/pushpin.js b/assets/libs/materialize/js/pushpin.js new file mode 100644 index 0000000..5f42246 --- /dev/null +++ b/assets/libs/materialize/js/pushpin.js @@ -0,0 +1,71 @@ +(function ($) { + $.fn.pushpin = function (options) { + // Defaults + var defaults = { + top: 0, + bottom: Infinity, + offset: 0 + }; + + // Remove pushpin event and classes + if (options === "remove") { + this.each(function () { + if (id = $(this).data('pushpin-id')) { + $(window).off('scroll.' + id); + $(this).removeData('pushpin-id').removeClass('pin-top pinned pin-bottom').removeAttr('style'); + } + }); + return false; + } + + options = $.extend(defaults, options); + + + $index = 0; + return this.each(function() { + var $uniqueId = Materialize.guid(), + $this = $(this), + $original_offset = $(this).offset().top; + + function removePinClasses(object) { + object.removeClass('pin-top'); + object.removeClass('pinned'); + object.removeClass('pin-bottom'); + } + + function updateElements(objects, scrolled) { + objects.each(function () { + // Add position fixed (because its between top and bottom) + if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) { + removePinClasses($(this)); + $(this).css('top', options.offset); + $(this).addClass('pinned'); + } + + // Add pin-top (when scrolled position is above top) + if (scrolled < options.top && !$(this).hasClass('pin-top')) { + removePinClasses($(this)); + $(this).css('top', 0); + $(this).addClass('pin-top'); + } + + // Add pin-bottom (when scrolled position is below bottom) + if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) { + removePinClasses($(this)); + $(this).addClass('pin-bottom'); + $(this).css('top', options.bottom - $original_offset); + } + }); + } + + $(this).data('pushpin-id', $uniqueId); + updateElements($this, $(window).scrollTop()); + $(window).on('scroll.' + $uniqueId, function () { + var $scrolled = $(window).scrollTop() + options.offset; + updateElements($this, $scrolled); + }); + + }); + + }; +}( jQuery )); \ No newline at end of file diff --git a/assets/libs/materialize/js/scrollFire.js b/assets/libs/materialize/js/scrollFire.js new file mode 100755 index 0000000..76eccd4 --- /dev/null +++ b/assets/libs/materialize/js/scrollFire.js @@ -0,0 +1,48 @@ +(function($) { + + // Input: Array of JSON objects {selector, offset, callback} + + Materialize.scrollFire = function(options) { + + var didScroll = false; + + window.addEventListener("scroll", function() { + didScroll = true; + }); + + // Rate limit to 100ms + setInterval(function() { + if(didScroll) { + didScroll = false; + + var windowScroll = window.pageYOffset + window.innerHeight; + + for (var i = 0 ; i < options.length; i++) { + // Get options from each line + var value = options[i]; + var selector = value.selector, + offset = value.offset, + callback = value.callback; + + var currentElement = document.querySelector(selector); + if ( currentElement !== null) { + var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset; + + if (windowScroll > (elementOffset + offset)) { + if (value.done !== true) { + if (typeof(callback) === 'function') { + callback.call(this, currentElement); + } else if (typeof(callback) === 'string') { + var callbackFunc = new Function(callback); + callbackFunc(currentElement); + } + value.done = true; + } + } + } + } + } + }, 100); + }; + +})(jQuery); diff --git a/assets/libs/materialize/js/scrollspy.js b/assets/libs/materialize/js/scrollspy.js new file mode 100755 index 0000000..73954be --- /dev/null +++ b/assets/libs/materialize/js/scrollspy.js @@ -0,0 +1,284 @@ +/** + * Extend jquery with a scrollspy plugin. + * This watches the window scroll and fires events when elements are scrolled into viewport. + * + * throttle() and getTime() taken from Underscore.js + * https://github.com/jashkenas/underscore + * + * @author Copyright 2013 John Smart + * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE + * @see https://github.com/thesmart + * @version 0.1.2 + */ +(function($) { + + var jWindow = $(window); + var elements = []; + var elementsInView = []; + var isSpying = false; + var ticks = 0; + var unique_id = 1; + var offset = { + top : 0, + right : 0, + bottom : 0, + left : 0, + } + + /** + * Find elements that are within the boundary + * @param {number} top + * @param {number} right + * @param {number} bottom + * @param {number} left + * @return {jQuery} A collection of elements + */ + function findElements(top, right, bottom, left) { + var hits = $(); + $.each(elements, function(i, element) { + if (element.height() > 0) { + var elTop = element.offset().top, + elLeft = element.offset().left, + elRight = elLeft + element.width(), + elBottom = elTop + element.height(); + + var isIntersect = !(elLeft > right || + elRight < left || + elTop > bottom || + elBottom < top); + + if (isIntersect) { + hits.push(element); + } + } + }); + + return hits; + } + + + /** + * Called when the user scrolls the window + */ + function onScroll(scrollOffset) { + // unique tick id + ++ticks; + + // viewport rectangle + var top = jWindow.scrollTop(), + left = jWindow.scrollLeft(), + right = left + jWindow.width(), + bottom = top + jWindow.height(); + + // determine which elements are in view + var intersections = findElements(top+offset.top + scrollOffset || 200, right+offset.right, bottom+offset.bottom, left+offset.left); + $.each(intersections, function(i, element) { + + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick != 'number') { + // entered into view + element.triggerHandler('scrollSpy:enter'); + } + + // update tick id + element.data('scrollSpy:ticks', ticks); + }); + + // determine which elements are no longer in view + $.each(elementsInView, function(i, element) { + var lastTick = element.data('scrollSpy:ticks'); + if (typeof lastTick == 'number' && lastTick !== ticks) { + // exited from view + element.triggerHandler('scrollSpy:exit'); + element.data('scrollSpy:ticks', null); + } + }); + + // remember elements in view for next tick + elementsInView = intersections; + } + + /** + * Called when window is resized + */ + function onWinSize() { + jWindow.trigger('scrollSpy:winSize'); + } + + /** + * Get time in ms + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @type {function} + * @return {number} + */ + var getTime = (Date.now || function () { + return new Date().getTime(); + }); + + /** + * Returns a function, that, when invoked, will only be triggered at most once + * during a given window of time. Normally, the throttled function will run + * as much as it can, without ever going more than once per `wait` duration; + * but if you'd like to disable the execution on the leading edge, pass + * `{leading: false}`. To disable execution on the trailing edge, ditto. + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @param {function} func + * @param {number} wait + * @param {Object=} options + * @returns {Function} + */ + function throttle(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + options || (options = {}); + var later = function () { + previous = options.leading === false ? 0 : getTime(); + timeout = null; + result = func.apply(context, args); + context = args = null; + }; + return function () { + var now = getTime(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + /** + * Enables ScrollSpy using a selector + * @param {jQuery|string} selector The elements collection, or a selector + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.scrollSpy = function(selector, options) { + var defaults = { + throttle: 100, + scrollOffset: 200 // offset - 200 allows elements near bottom of page to scroll + }; + options = $.extend(defaults, options); + + var visible = []; + selector = $(selector); + selector.each(function(i, element) { + elements.push($(element)); + $(element).data("scrollSpy:id", i); + // Smooth scroll to section + $('a[href="#' + $(element).attr('id') + '"]').click(function(e) { + e.preventDefault(); + var offset = $(Materialize.escapeHash(this.hash)).offset().top + 1; + $('html, body').animate({ scrollTop: offset - options.scrollOffset }, {duration: 400, queue: false, easing: 'easeOutCubic'}); + }); + }); + + offset.top = options.offsetTop || 0; + offset.right = options.offsetRight || 0; + offset.bottom = options.offsetBottom || 0; + offset.left = options.offsetLeft || 0; + + var throttledScroll = throttle(function() { + onScroll(options.scrollOffset); + }, options.throttle || 100); + var readyScroll = function(){ + $(document).ready(throttledScroll); + }; + + if (!isSpying) { + jWindow.on('scroll', readyScroll); + jWindow.on('resize', readyScroll); + isSpying = true; + } + + // perform a scan once, after current execution context, and after dom is ready + setTimeout(readyScroll, 0); + + + selector.on('scrollSpy:enter', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + var $this = $(this); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) { + visible.unshift($(this)); + } + else { + visible.push($(this)); + } + } + else { + visible.push($(this)); + } + + + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + }); + selector.on('scrollSpy:exit', function() { + visible = $.grep(visible, function(value) { + return value.height() != 0; + }); + + if (visible[0]) { + $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active'); + var $this = $(this); + visible = $.grep(visible, function(value) { + return value.attr('id') != $this.attr('id'); + }); + if (visible[0]) { // Check if empty + $('a[href="#' + visible[0].attr('id') + '"]').addClass('active'); + } + } + }); + + return selector; + }; + + /** + * Listen for window resize events + * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms + * @returns {jQuery} $(window) + */ + $.winSizeSpy = function(options) { + $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls + options = options || { + throttle: 100 + }; + return jWindow.on('resize', throttle(onWinSize, options.throttle || 100)); + }; + + /** + * Enables ScrollSpy on a collection of elements + * e.g. $('.scrollSpy').scrollSpy() + * @param {Object=} options Optional. + throttle : number -> scrollspy throttling. Default: 100 ms + offsetTop : number -> offset from top. Default: 0 + offsetRight : number -> offset from right. Default: 0 + offsetBottom : number -> offset from bottom. Default: 0 + offsetLeft : number -> offset from left. Default: 0 + * @returns {jQuery} + */ + $.fn.scrollSpy = function(options) { + return $.scrollSpy($(this), options); + }; + +})(jQuery); diff --git a/assets/libs/materialize/js/sideNav.js b/assets/libs/materialize/js/sideNav.js new file mode 100644 index 0000000..8b319ec --- /dev/null +++ b/assets/libs/materialize/js/sideNav.js @@ -0,0 +1,370 @@ +(function ($) { + + var methods = { + init : function(options) { + var defaults = { + menuWidth: 300, + edge: 'left', + closeOnClick: false, + draggable: true + }; + options = $.extend(defaults, options); + + $(this).each(function(){ + var $this = $(this); + var menu_id = $("#"+ $this.attr('data-activates')); + + // Set to width + if (options.menuWidth != 300) { + menu_id.css('width', options.menuWidth); + } + + // Add Touch Area + var $dragTarget; + if (options.draggable) { + $dragTarget = $('
                  ').attr('data-sidenav', $this.attr('data-activates')); + $('body').append($dragTarget); + } else { + $dragTarget = $(); + } + + if (options.edge == 'left') { + menu_id.css('transform', 'translateX(-100%)'); + $dragTarget.css({'left': 0}); // Add Touch Area + } + else { + menu_id.addClass('right-aligned') // Change text-alignment to right + .css('transform', 'translateX(100%)'); + $dragTarget.css({'right': 0}); // Add Touch Area + } + + // If fixed sidenav, bring menu out + if (menu_id.hasClass('fixed')) { + if (window.innerWidth > 992) { + menu_id.css('transform', 'translateX(0)'); + } + } + + // Window resize to reset on large screens fixed + if (menu_id.hasClass('fixed')) { + $(window).resize( function() { + if (window.innerWidth > 992) { + // Close menu if window is resized bigger than 992 and user has fixed sidenav + if ($('#sidenav-overlay').length !== 0 && menuOut) { + removeMenu(true); + } + else { + // menu_id.removeAttr('style'); + menu_id.css('transform', 'translateX(0%)'); + // menu_id.css('width', options.menuWidth); + } + } + else if (menuOut === false){ + if (options.edge === 'left') { + menu_id.css('transform', 'translateX(-100%)'); + } else { + menu_id.css('transform', 'translateX(100%)'); + } + + } + + }); + } + + // if closeOnClick, then add close event for all a tags in side sideNav + if (options.closeOnClick === true) { + menu_id.on("click.itemclick", "a:not(.collapsible-header)", function(){ + removeMenu(); + }); + } + + var removeMenu = function(restoreNav) { + panning = false; + menuOut = false; + // Reenable scrolling + $('body').css({ + overflow: '', + width: '' + }); + + $('#sidenav-overlay').velocity({opacity: 0}, {duration: 200, + queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + if (options.edge === 'left') { + // Reset phantom div + $dragTarget.css({width: '', right: '', left: '0'}); + menu_id.velocity( + {'translateX': '-100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + + }); + } + else { + // Reset phantom div + $dragTarget.css({width: '', right: '0', left: ''}); + menu_id.velocity( + {'translateX': '100%'}, + { duration: 200, + queue: false, + easing: 'easeOutCubic', + complete: function() { + if (restoreNav === true) { + // Restore Fixed sidenav + menu_id.removeAttr('style'); + menu_id.css('width', options.menuWidth); + } + } + }); + } + }; + + + + // Touch Event + var panning = false; + var menuOut = false; + + if (options.draggable) { + $dragTarget.on('click', function(){ + if (menuOut) { + removeMenu(); + } + }); + + $dragTarget.hammer({ + prevent_default: false + }).bind('pan', function(e) { + + if (e.gesture.pointerType == "touch") { + + var direction = e.gesture.direction; + var x = e.gesture.center.x; + var y = e.gesture.center.y; + var velocityX = e.gesture.velocityX; + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('#sidenav-overlay'); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // If overlay does not exist, create one and if it is clicked, close menu + if ($overlay.length === 0) { + $overlay = $('
                  '); + $overlay.css('opacity', 0).click( function(){ + removeMenu(); + }); + $('body').append($overlay); + } + + // Keep within boundaries + if (options.edge === 'left') { + if (x > options.menuWidth) { x = options.menuWidth; } + else if (x < 0) { x = 0; } + } + + if (options.edge === 'left') { + // Left Direction + if (x < (options.menuWidth / 2)) { menuOut = false; } + // Right Direction + else if (x >= (options.menuWidth / 2)) { menuOut = true; } + menu_id.css('transform', 'translateX(' + (x - options.menuWidth) + 'px)'); + } + else { + // Left Direction + if (x < (window.innerWidth - options.menuWidth / 2)) { + menuOut = true; + } + // Right Direction + else if (x >= (window.innerWidth - options.menuWidth / 2)) { + menuOut = false; + } + var rightPos = (x - options.menuWidth / 2); + if (rightPos < 0) { + rightPos = 0; + } + + menu_id.css('transform', 'translateX(' + rightPos + 'px)'); + } + + + // Percentage overlay + var overlayPerc; + if (options.edge === 'left') { + overlayPerc = x / options.menuWidth; + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + else { + overlayPerc = Math.abs((x - window.innerWidth) / options.menuWidth); + $overlay.velocity({opacity: overlayPerc }, {duration: 10, queue: false, easing: 'easeOutQuad'}); + } + } + + }).bind('panend', function(e) { + + if (e.gesture.pointerType == "touch") { + var $overlay = $('
                  '); + var velocityX = e.gesture.velocityX; + var x = e.gesture.center.x; + var leftPos = x - options.menuWidth; + var rightPos = x - options.menuWidth / 2; + if (leftPos > 0 ) { + leftPos = 0; + } + if (rightPos < 0) { + rightPos = 0; + } + panning = false; + + if (options.edge === 'left') { + // If velocityX <= 0.3 then the user is flinging the menu closed so ignore menuOut + if ((menuOut && velocityX <= 0.3) || velocityX < -0.5) { + // Return menu to open + if (leftPos !== 0) { + menu_id.velocity({'translateX': [0, leftPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: 0, left: ''}); + menuOut = true; + } + else if (!menuOut || velocityX > 0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + // Slide menu closed + menu_id.velocity({'translateX': [-1 * options.menuWidth - 10, leftPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: '', left: 0}); + } + } + else { + if ((menuOut && velocityX >= -0.3) || velocityX > 0.5) { + // Return menu to open + if (rightPos !== 0) { + menu_id.velocity({'translateX': [0, rightPos]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.velocity({opacity: 1 }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + $dragTarget.css({width: '50%', right: '', left: 0}); + menuOut = true; + } + else if (!menuOut || velocityX < -0.3) { + // Enable Scrolling + $('body').css({ + overflow: '', + width: '' + }); + + // Slide menu closed + menu_id.velocity({'translateX': [options.menuWidth + 10, rightPos]}, {duration: 200, queue: false, easing: 'easeOutQuad'}); + $overlay.velocity({opacity: 0 }, {duration: 200, queue: false, easing: 'easeOutQuad', + complete: function () { + $(this).remove(); + }}); + $dragTarget.css({width: '10px', right: 0, left: ''}); + } + } + + } + }); + } + + $this.click(function() { + if (menuOut === true) { + menuOut = false; + panning = false; + removeMenu(); + } + else { + + // Disable Scrolling + var $body = $('body'); + var $overlay = $('
                  '); + var oldWidth = $body.innerWidth(); + $body.css('overflow', 'hidden'); + $body.width(oldWidth); + + // Push current drag target on top of DOM tree + $('body').append($dragTarget); + + if (options.edge === 'left') { + $dragTarget.css({width: '50%', right: 0, left: ''}); + menu_id.velocity({'translateX': [0, -1 * options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else { + $dragTarget.css({width: '50%', right: '', left: 0}); + menu_id.velocity({'translateX': [0, options.menuWidth]}, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + $overlay.css('opacity', 0) + .click(function(){ + menuOut = false; + panning = false; + removeMenu(); + $overlay.velocity({opacity: 0}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $(this).remove(); + } }); + + }); + $('body').append($overlay); + $overlay.velocity({opacity: 1}, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function () { + menuOut = true; + panning = false; + } + }); + } + + return false; + }); + }); + + + }, + destroy: function () { + var $overlay = $('#sidenav-overlay'); + var $dragTarget = $('.drag-target[data-sidenav="' + $(this).attr('data-activates') + '"]'); + $overlay.trigger('click'); + $dragTarget.remove(); + $(this).off('click'); + $overlay.remove(); + }, + show : function() { + this.trigger('click'); + }, + hide : function() { + $('#sidenav-overlay').trigger('click'); + } + }; + + + $.fn.sideNav = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.sideNav' ); + } + }; // Plugin end +}( jQuery )); diff --git a/assets/libs/materialize/js/slider.js b/assets/libs/materialize/js/slider.js new file mode 100644 index 0000000..6b8f24a --- /dev/null +++ b/assets/libs/materialize/js/slider.js @@ -0,0 +1,321 @@ +(function ($) { + + var methods = { + + init : function(options) { + var defaults = { + indicators: true, + height: 400, + transition: 500, + interval: 6000 + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each slider, we want to keep track of + // which slide is active and its associated content + var $this = $(this); + var $slider = $this.find('ul.slides').first(); + var $slides = $slider.find('> li'); + var $active_index = $slider.find('.active').index(); + var $active, $indicators, $interval; + if ($active_index != -1) { $active = $slides.eq($active_index); } + + // Transitions the caption depending on alignment + function captionTransition(caption, duration) { + if (caption.hasClass("center-align")) { + caption.velocity({opacity: 0, translateY: -100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("right-align")) { + caption.velocity({opacity: 0, translateX: 100}, {duration: duration, queue: false}); + } + else if (caption.hasClass("left-align")) { + caption.velocity({opacity: 0, translateX: -100}, {duration: duration, queue: false}); + } + } + + // This function will transition the slide to any index of the next slide + function moveToSlide(index) { + // Wrap around indices. + if (index >= $slides.length) index = 0; + else if (index < 0) index = $slides.length -1; + + $active_index = $slider.find('.active').index(); + + // Only do if index changes + if ($active_index != index) { + $active = $slides.eq($active_index); + $caption = $active.find('.caption'); + + $active.removeClass('active'); + $active.velocity({opacity: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad', + complete: function() { + $slides.not('.active').velocity({opacity: 0, translateX: 0, translateY: 0}, {duration: 0, queue: false}); + } }); + captionTransition($caption, options.transition); + + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).removeClass('active'); + } + + $slides.eq(index).velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, delay: options.transition, queue: false, easing: 'easeOutQuad'}); + $slides.eq(index).addClass('active'); + + + // Update indicators + if (options.indicators) { + $indicators.eq(index).addClass('active'); + } + } + } + + // Set height of slider + // If fullscreen, do nothing + if (!$this.hasClass('fullscreen')) { + if (options.indicators) { + // Add height if indicators are present + $this.height(options.height + 40); + } + else { + $this.height(options.height); + } + $slider.height(options.height); + } + + + // Set initial positions of captions + $slides.find('.caption').each(function () { + captionTransition($(this), 0); + }); + + // Move img src into background-image + $slides.find('img').each(function () { + var placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; + if ($(this).attr('src') !== placeholderBase64) { + $(this).css('background-image', 'url(' + $(this).attr('src') + ')' ); + $(this).attr('src', placeholderBase64); + } + }); + + // dynamically add indicators + if (options.indicators) { + $indicators = $('
                    '); + $slides.each(function( index ) { + var $indicator = $('
                  • '); + + // Handle clicks on indicators + $indicator.click(function () { + var $parent = $slider.parent(); + var curr_index = $parent.find($(this)).index(); + moveToSlide(curr_index); + + // reset interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + $indicators.append($indicator); + }); + $this.append($indicators); + $indicators = $this.find('ul.indicators').find('li.indicator-item'); + } + + if ($active) { + $active.show(); + } + else { + $slides.first().addClass('active').velocity({opacity: 1}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + + $active_index = 0; + $active = $slides.eq($active_index); + + // Update indicators + if (options.indicators) { + $indicators.eq($active_index).addClass('active'); + } + } + + // Adjust height to current slide + $active.find('img').each(function() { + $active.find('.caption').velocity({opacity: 1, translateX: 0, translateY: 0}, {duration: options.transition, queue: false, easing: 'easeOutQuad'}); + }); + + // auto scroll + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + + }, options.transition + options.interval + ); + + + // HammerJS, Swipe navigation + + // Touch Event + var panning = false; + var swipeLeft = false; + var swipeRight = false; + + $this.hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + + // reset interval + clearInterval($interval); + + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $curr_slide = $slider.find('.active'); + $curr_slide.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.65)) { + swipeRight = true; + } + // Swipe Right + else if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.65)) { + swipeLeft = true; + } + + // Make Slide Behind active slide visible + var next_slide; + if (swipeLeft) { + next_slide = $curr_slide.next(); + if (next_slide.length === 0) { + next_slide = $slides.first(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + if (swipeRight) { + next_slide = $curr_slide.prev(); + if (next_slide.length === 0) { + next_slide = $slides.last(); + } + next_slide.velocity({ opacity: 1 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + + + } + + }).bind('panend', function(e) { + if (e.gesture.pointerType === "touch") { + + $curr_slide = $slider.find('.active'); + panning = false; + curr_index = $slider.find('.active').index(); + + if (!swipeRight && !swipeLeft || $slides.length <=1) { + // Return to original spot + $curr_slide.velocity({ translateX: 0 + }, {duration: 300, queue: false, easing: 'easeOutQuad'}); + } + else if (swipeLeft) { + moveToSlide(curr_index + 1); + $curr_slide.velocity({translateX: -1 * $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + else if (swipeRight) { + moveToSlide(curr_index - 1); + $curr_slide.velocity({translateX: $this.innerWidth() }, {duration: 300, queue: false, easing: 'easeOutQuad', + complete: function() { + $curr_slide.velocity({opacity: 0, translateX: 0}, {duration: 0, queue: false}); + } }); + } + swipeLeft = false; + swipeRight = false; + + // Restart interval + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + } + }); + + $this.on('sliderPause', function() { + clearInterval($interval); + }); + + $this.on('sliderStart', function() { + clearInterval($interval); + $interval = setInterval( + function(){ + $active_index = $slider.find('.active').index(); + if ($slides.length == $active_index + 1) $active_index = 0; // loop to start + else $active_index += 1; + + moveToSlide($active_index); + + }, options.transition + options.interval + ); + }); + + $this.on('sliderNext', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index + 1); + }); + + $this.on('sliderPrev', function() { + $active_index = $slider.find('.active').index(); + moveToSlide($active_index - 1); + }); + + }); + + + + }, + pause : function() { + $(this).trigger('sliderPause'); + }, + start : function() { + $(this).trigger('sliderStart'); + }, + next : function() { + $(this).trigger('sliderNext'); + }, + prev : function() { + $(this).trigger('sliderPrev'); + } + }; + + + $.fn.slider = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tooltip' ); + } + }; // Plugin end +}( jQuery )); diff --git a/assets/libs/materialize/js/tabs.js b/assets/libs/materialize/js/tabs.js new file mode 100644 index 0000000..aa436be --- /dev/null +++ b/assets/libs/materialize/js/tabs.js @@ -0,0 +1,164 @@ +(function ($) { + + var methods = { + init : function(options) { + var defaults = { + onShow: null + }; + options = $.extend(defaults, options); + + return this.each(function() { + + // For each set of tabs, we want to keep track of + // which tab is active and its associated content + var $this = $(this), + window_width = $(window).width(); + + var $active, $content, $links = $this.find('li.tab a'), + $tabs_width = $this.width(), + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length, + $index = 0; + + // Finds right attribute for indicator based on active tab. + // el: jQuery Object + var calcRightPos = function(el) { + return $tabs_width - el.position().left - el.outerWidth() - $this.scrollLeft(); + }; + + // Finds left attribute for indicator based on active tab. + // el: jQuery Object + var calcLeftPos = function(el) { + return el.position().left + $this.scrollLeft(); + }; + + // If the location.hash matches one of the links, use that as the active tab. + $active = $($links.filter('[href="'+location.hash+'"]')); + + // If no match is found, use the first link or any with class 'active' as the initial active tab. + if ($active.length === 0) { + $active = $(this).find('li.tab a.active').first(); + } + if ($active.length === 0) { + $active = $(this).find('li.tab a').first(); + } + + $active.addClass('active'); + $index = $links.index($active); + if ($index < 0) { + $index = 0; + } + + if ($active[0] !== undefined) { + $content = $($active[0].hash); + } + + // append indicator then set indicator width to tab width + $this.append('
                    '); + var $indicator = $this.find('.indicator'); + if ($this.is(":visible")) { + // $indicator.css({"right": $tabs_width - (($index + 1) * $tab_width)}); + // $indicator.css({"left": $index * $tab_width}); + setTimeout(function() { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + }, 0); + } + $(window).resize(function () { + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + if ($index < 0) { + $index = 0; + } + if ($tab_width !== 0 && $tabs_width !== 0) { + $indicator.css({"right": calcRightPos($active) }); + $indicator.css({"left": calcLeftPos($active) }); + } + }); + + // Hide the remaining content + $links.not($active).each(function () { + $(Materialize.escapeHash(this.hash)).hide(); + }); + + + // Bind the click event handler + $this.on('click', 'a', function(e) { + if ($(this).parent().hasClass('disabled')) { + e.preventDefault(); + return; + } + + // Act as regular link if target attribute is specified. + if (!!$(this).attr("target")) { + return; + } + + $tabs_width = $this.width(); + $tab_width = Math.max($tabs_width, $this[0].scrollWidth) / $links.length; + + // Make the old tab inactive. + $active.removeClass('active'); + if ($content !== undefined) { + $content.hide(); + } + + // Update the variables with the new link and content + $active = $(this); + $content = $(Materialize.escapeHash(this.hash)); + $links = $this.find('li.tab a'); + var activeRect = $active.position(); + + // Make the tab active. + $active.addClass('active'); + var $prev_index = $index; + $index = $links.index($(this)); + if ($index < 0) { + $index = 0; + } + // Change url to current tab + // window.location.hash = $active.attr('href'); + + if ($content !== undefined) { + $content.show(); + if (typeof(options.onShow) === "function") { + options.onShow.call(this, $content); + } + } + + // Update indicator + + if (($index - $prev_index) >= 0) { + $indicator.velocity({"right": calcRightPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"left": calcLeftPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + + } else { + $indicator.velocity({"left": calcLeftPos($active) }, { duration: 300, queue: false, easing: 'easeOutQuad'}); + $indicator.velocity({"right": calcRightPos($active) }, {duration: 300, queue: false, easing: 'easeOutQuad', delay: 90}); + } + + // Prevent the anchor's default click action + e.preventDefault(); + }); + }); + + }, + select_tab : function( id ) { + this.find('a[href="#' + id + '"]').trigger('click'); + } + }; + + $.fn.tabs = function(methodOrOptions) { + if ( methods[methodOrOptions] ) { + return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + // Default to "init" + return methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.tabs' ); + } + }; + + $(document).ready(function(){ + $('ul.tabs').tabs(); + }); +}( jQuery )); diff --git a/assets/libs/materialize/js/toasts.js b/assets/libs/materialize/js/toasts.js new file mode 100644 index 0000000..9a19cc5 --- /dev/null +++ b/assets/libs/materialize/js/toasts.js @@ -0,0 +1,137 @@ +Materialize.toast = function (message, displayLength, className, completeCallback) { + className = className || ""; + + var container = document.getElementById('toast-container'); + + // Create toast container if it does not exist + if (container === null) { + // create notification container + container = document.createElement('div'); + container.id = 'toast-container'; + document.body.appendChild(container); + } + + // Select and append toast + var newToast = createToast(message); + + // only append toast if message is not undefined + if(message){ + container.appendChild(newToast); + } + + newToast.style.top = '35px'; + newToast.style.opacity = 0; + + // Animate toast in + Vel(newToast, { "top" : "0px", opacity: 1 }, {duration: 300, + easing: 'easeOutCubic', + queue: false}); + + // Allows timer to be pause while being panned + var timeLeft = displayLength; + var counterInterval; + if (timeLeft != null) { + counterInterval = setInterval (function(){ + if (newToast.parentNode === null) + window.clearInterval(counterInterval); + + // If toast is not being dragged, decrease its time remaining + if (!newToast.classList.contains('panning')) { + timeLeft -= 20; + } + + if (timeLeft <= 0) { + // Animate toast out + Vel(newToast, {"opacity": 0, marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + // Call the optional callback + if(typeof(completeCallback) === "function") + completeCallback(); + // Remove toast after it times out + this[0].parentNode.removeChild(this[0]); + } + }); + window.clearInterval(counterInterval); + } + }, 20); + } + + + + function createToast(html) { + + // Create toast + var toast = document.createElement('div'); + toast.classList.add('toast'); + if (className) { + var classes = className.split(' '); + + for (var i = 0, count = classes.length; i < count; i++) { + toast.classList.add(classes[i]); + } + } + // If type of parameter is HTML Element + if ( typeof HTMLElement === "object" ? html instanceof HTMLElement : html && typeof html === "object" && html !== null && html.nodeType === 1 && typeof html.nodeName==="string" +) { + toast.appendChild(html); + } + else if (html instanceof jQuery) { + // Check if it is jQuery object + toast.appendChild(html[0]); + } + else { + // Insert as text; + toast.innerHTML = html; + } + // Bind hammer + var hammerHandler = new Hammer(toast, {prevent_default: false}); + hammerHandler.on('pan', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // Change toast state + if (!toast.classList.contains('panning')){ + toast.classList.add('panning'); + } + + var opacityPercent = 1-Math.abs(deltaX / activationDistance); + if (opacityPercent < 0) + opacityPercent = 0; + + Vel(toast, {left: deltaX, opacity: opacityPercent }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + }); + + hammerHandler.on('panend', function(e) { + var deltaX = e.deltaX; + var activationDistance = 80; + + // If toast dragged past activation point + if (Math.abs(deltaX) > activationDistance) { + Vel(toast, {marginTop: '-40px'}, { duration: 375, + easing: 'easeOutExpo', + queue: false, + complete: function(){ + if(typeof(completeCallback) === "function") { + completeCallback(); + } + toast.parentNode.removeChild(toast); + } + }); + + } else { + toast.classList.remove('panning'); + // Put toast back into original position + Vel(toast, { left: 0, opacity: 1 }, { duration: 300, + easing: 'easeOutExpo', + queue: false + }); + + } + }); + + return toast; + } +}; diff --git a/assets/libs/materialize/js/tooltip.js b/assets/libs/materialize/js/tooltip.js new file mode 100644 index 0000000..7c2d2a8 --- /dev/null +++ b/assets/libs/materialize/js/tooltip.js @@ -0,0 +1,236 @@ +(function ($) { + $.fn.tooltip = function (options) { + var timeout = null, + margin = 5; + + // Defaults + var defaults = { + delay: 350, + tooltip: '', + position: 'bottom', + html: false + }; + + // Remove tooltip from the activator + if (options === "remove") { + this.each(function() { + $('#' + $(this).attr('data-tooltip-id')).remove(); + $(this).off('mouseenter.tooltip mouseleave.tooltip'); + }); + return false; + } + + options = $.extend(defaults, options); + + return this.each(function() { + var tooltipId = Materialize.guid(); + var origin = $(this); + + // Destroy old tooltip + if (origin.attr('data-tooltip-id')) { + $('#' + origin.attr('data-tooltip-id')).remove(); + } + + origin.attr('data-tooltip-id', tooltipId); + + // Get attributes. + var allowHtml, + tooltipDelay, + tooltipPosition, + tooltipText, + tooltipEl, + backdrop; + var setAttributes = function() { + allowHtml = origin.attr('data-html') ? origin.attr('data-html') === 'true' : options.html; + tooltipDelay = origin.attr('data-delay'); + tooltipDelay = (tooltipDelay === undefined || tooltipDelay === '') ? + options.delay : tooltipDelay; + tooltipPosition = origin.attr('data-position'); + tooltipPosition = (tooltipPosition === undefined || tooltipPosition === '') ? + options.position : tooltipPosition; + tooltipText = origin.attr('data-tooltip'); + tooltipText = (tooltipText === undefined || tooltipText === '') ? + options.tooltip : tooltipText; + }; + setAttributes(); + + var renderTooltipEl = function() { + var tooltip = $('
                    '); + + // Create Text span + if (allowHtml) { + tooltipText = $('').html(tooltipText); + } else{ + tooltipText = $('').text(tooltipText); + } + + // Create tooltip + tooltip.append(tooltipText) + .appendTo($('body')) + .attr('id', tooltipId); + + // Create backdrop + backdrop = $('
                    '); + backdrop.appendTo(tooltip); + return tooltip; + }; + tooltipEl = renderTooltipEl(); + + // Destroy previously binded events + origin.off('mouseenter.tooltip mouseleave.tooltip'); + // Mouse In + var started = false, timeoutRef; + origin.on({'mouseenter.tooltip': function(e) { + var showTooltip = function() { + setAttributes(); + started = true; + tooltipEl.velocity('stop'); + backdrop.velocity('stop'); + tooltipEl.css({ display: 'block', left: '0px', top: '0px' }); + + // Tooltip positioning + var originWidth = origin.outerWidth(); + var originHeight = origin.outerHeight(); + + var tooltipHeight = tooltipEl.outerHeight(); + var tooltipWidth = tooltipEl.outerWidth(); + var tooltipVerticalMovement = '0px'; + var tooltipHorizontalMovement = '0px'; + var scaleXFactor = 8; + var scaleYFactor = 8; + var targetTop, targetLeft, newCoordinates; + + if (tooltipPosition === "top") { + // Top Position + targetTop = origin.offset().top - tooltipHeight - margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipVerticalMovement = '-10px'; + backdrop.css({ + bottom: 0, + left: 0, + borderRadius: '14px 14px 0 0', + transformOrigin: '50% 100%', + marginTop: tooltipHeight, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + // Left Position + else if (tooltipPosition === "left") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left - tooltipWidth - margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '-10px'; + backdrop.css({ + top: '-7px', + right: 0, + width: '14px', + height: '14px', + borderRadius: '14px 0 0 14px', + transformOrigin: '95% 50%', + marginTop: tooltipHeight/2, + marginLeft: tooltipWidth + }); + } + // Right Position + else if (tooltipPosition === "right") { + targetTop = origin.offset().top + originHeight/2 - tooltipHeight/2; + targetLeft = origin.offset().left + originWidth + margin; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + + tooltipHorizontalMovement = '+10px'; + backdrop.css({ + top: '-7px', + left: 0, + width: '14px', + height: '14px', + borderRadius: '0 14px 14px 0', + transformOrigin: '5% 50%', + marginTop: tooltipHeight/2, + marginLeft: '0px' + }); + } + else { + // Bottom Position + targetTop = origin.offset().top + origin.outerHeight() + margin; + targetLeft = origin.offset().left + originWidth/2 - tooltipWidth/2; + newCoordinates = repositionWithinScreen(targetLeft, targetTop, tooltipWidth, tooltipHeight); + tooltipVerticalMovement = '+10px'; + backdrop.css({ + top: 0, + left: 0, + marginLeft: (tooltipWidth/2) - (backdrop.width()/2) + }); + } + + // Set tooptip css placement + tooltipEl.css({ + top: newCoordinates.y, + left: newCoordinates.x + }); + + // Calculate Scale to fill + scaleXFactor = Math.SQRT2 * tooltipWidth / parseInt(backdrop.css('width')); + scaleYFactor = Math.SQRT2 * tooltipHeight / parseInt(backdrop.css('height')); + + tooltipEl.velocity({ marginTop: tooltipVerticalMovement, marginLeft: tooltipHorizontalMovement}, { duration: 350, queue: false }) + .velocity({opacity: 1}, {duration: 300, delay: 50, queue: false}); + backdrop.css({ display: 'block' }) + .velocity({opacity:1},{duration: 55, delay: 0, queue: false}) + .velocity({scaleX: scaleXFactor, scaleY: scaleYFactor}, {duration: 300, delay: 0, queue: false, easing: 'easeInOutQuad'}); + }; + + timeoutRef = setTimeout(showTooltip, tooltipDelay); // End Interval + + // Mouse Out + }, + 'mouseleave.tooltip': function(){ + // Reset State + started = false; + clearTimeout(timeoutRef); + + // Animate back + setTimeout(function() { + if (started !== true) { + tooltipEl.velocity({ + opacity: 0, marginTop: 0, marginLeft: 0}, { duration: 225, queue: false}); + backdrop.velocity({opacity: 0, scaleX: 1, scaleY: 1}, { + duration:225, + queue: false, + complete: function(){ + backdrop.css('display', 'none'); + tooltipEl.css('display', 'none'); + started = false;} + }); + } + },225); + } + }); + }); + }; + + var repositionWithinScreen = function(x, y, width, height) { + var newX = x; + var newY = y; + + if (newX < 0) { + newX = 4; + } else if (newX + width > window.innerWidth) { + newX -= newX + width - window.innerWidth; + } + + if (newY < 0) { + newY = 4; + } else if (newY + height > window.innerHeight + $(window).scrollTop) { + newY -= newY + height - window.innerHeight; + } + + return {x: newX, y: newY}; + }; + + $(document).ready(function(){ + $('.tooltipped').tooltip(); + }); +}( jQuery )); diff --git a/assets/libs/materialize/js/transitions.js b/assets/libs/materialize/js/transitions.js new file mode 100644 index 0000000..d4e9159 --- /dev/null +++ b/assets/libs/materialize/js/transitions.js @@ -0,0 +1,169 @@ +(function ($) { + // Image transition function + Materialize.fadeInImage = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + element.css({opacity: 0}); + $(element).velocity({opacity: 1}, { + duration: 650, + queue: false, + easing: 'easeOutSine' + }); + $(element).velocity({opacity: 1}, { + duration: 1300, + queue: false, + easing: 'swing', + step: function(now, fx) { + fx.start = 100; + var grayscale_setting = now/100; + var brightness_setting = 150 - (100 - now)/1.75; + + if (brightness_setting < 100) { + brightness_setting = 100; + } + if (now >= 0) { + $(this).css({ + "-webkit-filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)", + "filter": "grayscale("+grayscale_setting+")" + "brightness("+brightness_setting+"%)" + }); + } + } + }); + }; + + // Horizontal staggered list + Materialize.showStaggeredList = function(selectorOrEl) { + var element; + if (typeof(selectorOrEl) === 'string') { + element = $(selectorOrEl); + } else if (typeof(selectorOrEl) === 'object') { + element = selectorOrEl; + } else { + return; + } + var time = 0; + element.find('li').velocity( + { translateX: "-100px"}, + { duration: 0 }); + + element.find('li').each(function() { + $(this).velocity( + { opacity: "1", translateX: "0"}, + { duration: 800, delay: time, easing: [60, 10] }); + time += 120; + }); + }; + + + $(document).ready(function() { + // Hardcoded .staggered-list scrollFire + // var staggeredListOptions = []; + // $('ul.staggered-list').each(function (i) { + + // var label = 'scrollFire-' + i; + // $(this).addClass(label); + // staggeredListOptions.push( + // {selector: 'ul.staggered-list.' + label, + // offset: 200, + // callback: 'showStaggeredList("ul.staggered-list.' + label + '")'}); + // }); + // scrollFire(staggeredListOptions); + + // HammerJS, Swipe navigation + + // Touch Event + var swipeLeft = false; + var swipeRight = false; + + + // Dismissible Collections + $('.dismissable').each(function() { + $(this).hammer({ + prevent_default: false + }).bind('pan', function(e) { + if (e.gesture.pointerType === "touch") { + var $this = $(this); + var direction = e.gesture.direction; + var x = e.gesture.deltaX; + var velocityX = e.gesture.velocityX; + + $this.velocity({ translateX: x + }, {duration: 50, queue: false, easing: 'easeOutQuad'}); + + // Swipe Left + if (direction === 4 && (x > ($this.innerWidth() / 2) || velocityX < -0.75)) { + swipeLeft = true; + } + + // Swipe Right + if (direction === 2 && (x < (-1 * $this.innerWidth() / 2) || velocityX > 0.75)) { + swipeRight = true; + } + } + }).bind('panend', function(e) { + // Reset if collection is moved back into original position + if (Math.abs(e.gesture.deltaX) < ($(this).innerWidth() / 2)) { + swipeRight = false; + swipeLeft = false; + } + + if (e.gesture.pointerType === "touch") { + var $this = $(this); + if (swipeLeft || swipeRight) { + var fullWidth; + if (swipeLeft) { fullWidth = $this.innerWidth(); } + else { fullWidth = -1 * $this.innerWidth(); } + + $this.velocity({ translateX: fullWidth, + }, {duration: 100, queue: false, easing: 'easeOutQuad', complete: + function() { + $this.css('border', 'none'); + $this.velocity({ height: 0, padding: 0, + }, {duration: 200, queue: false, easing: 'easeOutQuad', complete: + function() { $this.remove(); } + }); + } + }); + } + else { + $this.velocity({ translateX: 0, + }, {duration: 100, queue: false, easing: 'easeOutQuad'}); + } + swipeLeft = false; + swipeRight = false; + } + }); + + }); + + + // time = 0 + // // Vertical Staggered list + // $('ul.staggered-list.vertical li').velocity( + // { translateY: "100px"}, + // { duration: 0 }); + + // $('ul.staggered-list.vertical li').each(function() { + // $(this).velocity( + // { opacity: "1", translateY: "0"}, + // { duration: 800, delay: time, easing: [60, 25] }); + // time += 120; + // }); + + // // Fade in and Scale + // $('.fade-in.scale').velocity( + // { scaleX: .4, scaleY: .4, translateX: -600}, + // { duration: 0}); + // $('.fade-in').each(function() { + // $(this).velocity( + // { opacity: "1", scaleX: 1, scaleY: 1, translateX: 0}, + // { duration: 800, easing: [60, 10] }); + // }); + }); +}( jQuery )); diff --git a/assets/libs/materialize/js/velocity.min.js b/assets/libs/materialize/js/velocity.min.js new file mode 100644 index 0000000..ea21aad --- /dev/null +++ b/assets/libs/materialize/js/velocity.min.js @@ -0,0 +1,5 @@ +/*! VelocityJS.org (1.2.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ +/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ +/*! Note that this has been modified by Materialize to confirm that Velocity is not already being imported. */ +jQuery.Velocity?console.log("Velocity is already loaded. You may be needlessly importing Velocity again; note that Materialize includes Velocity."):(!function(e){function t(e){var t=e.length,a=r.type(e);return"function"===a||r.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===a||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var r=function(e,t){return new r.fn.init(e,t)};r.isWindow=function(e){return null!=e&&e==e.window},r.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e},r.isArray=Array.isArray||function(e){return"array"===r.type(e)},r.isPlainObject=function(e){var t;if(!e||"object"!==r.type(e)||e.nodeType||r.isWindow(e))return!1;try{if(e.constructor&&!o.call(e,"constructor")&&!o.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(a){return!1}for(t in e);return void 0===t||o.call(e,t)},r.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},r.data=function(e,t,n){if(void 0===n){var o=e[r.expando],i=o&&a[o];if(void 0===t)return i;if(i&&t in i)return i[t]}else if(void 0!==t){var o=e[r.expando]||(e[r.expando]=++r.uuid);return a[o]=a[o]||{},a[o][t]=n,n}},r.removeData=function(e,t){var n=e[r.expando],o=n&&a[n];o&&r.each(t,function(e,t){delete o[t]})},r.extend=function(){var e,t,a,n,o,i,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[l]||{},l++),"object"!=typeof s&&"function"!==r.type(s)&&(s={}),l===u&&(s=this,l--);u>l;l++)if(null!=(o=arguments[l]))for(n in o)e=s[n],a=o[n],s!==a&&(c&&a&&(r.isPlainObject(a)||(t=r.isArray(a)))?(t?(t=!1,i=e&&r.isArray(e)?e:[]):i=e&&r.isPlainObject(e)?e:{},s[n]=r.extend(c,i,a)):void 0!==a&&(s[n]=a));return s},r.queue=function(e,a,n){function o(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){a=(a||"fx")+"queue";var i=r.data(e,a);return n?(!i||r.isArray(n)?i=r.data(e,a,o(n)):i.push(n),i):i||[]}},r.dequeue=function(e,t){r.each(e.nodeType?[e]:e,function(e,a){t=t||"fx";var n=r.queue(a,t),o=n.shift();"inprogress"===o&&(o=n.shift()),o&&("fx"===t&&n.unshift("inprogress"),o.call(a,function(){r.dequeue(a,t)}))})},r.fn=r.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),a=this.offset(),n=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:r(e).offset();return a.top-=parseFloat(t.style.marginTop)||0,a.left-=parseFloat(t.style.marginLeft)||0,e.style&&(n.top+=parseFloat(e.style.borderTopWidth)||0,n.left+=parseFloat(e.style.borderLeftWidth)||0),{top:a.top-n.top,left:a.left-n.left}}};var a={};r.expando="velocity"+(new Date).getTime(),r.uuid=0;for(var n={},o=n.hasOwnProperty,i=n.toString,s="Boolean Number String Function Array Date RegExp Object Error".split(" "),l=0;ln;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return m.isString(e)?b.Easings[e]||(r=!1):r=m.isArray(e)&&1===e.length?s.apply(null,e):m.isArray(e)&&2===e.length?x.apply(null,e.concat([t])):m.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=b.Easings[b.defaults.easing]?b.defaults.easing:v),r}function c(e){if(e){var t=(new Date).getTime(),r=b.State.calls.length;r>1e4&&(b.State.calls=n(b.State.calls));for(var o=0;r>o;o++)if(b.State.calls[o]){var s=b.State.calls[o],l=s[0],u=s[2],d=s[3],g=!!d,y=null;d||(d=b.State.calls[o][3]=t-16);for(var h=Math.min((t-d)/u.duration,1),v=0,x=l.length;x>v;v++){var P=l[v],V=P.element;if(i(V)){var C=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var T=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];f.each(T,function(e,t){S.setPropertyValue(V,"display",t)})}S.setPropertyValue(V,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&S.setPropertyValue(V,"visibility",u.visibility);for(var k in P)if("element"!==k){var A,F=P[k],j=m.isString(F.easing)?b.Easings[F.easing]:F.easing;if(1===h)A=F.endValue;else{var E=F.endValue-F.startValue;if(A=F.startValue+E*j(h,u,E),!g&&A===F.currentValue)continue}if(F.currentValue=A,"tween"===k)y=A;else{if(S.Hooks.registered[k]){var H=S.Hooks.getRoot(k),N=i(V).rootPropertyValueCache[H];N&&(F.rootPropertyValue=N)}var L=S.setPropertyValue(V,k,F.currentValue+(0===parseFloat(A)?"":F.unitType),F.rootPropertyValue,F.scrollData);S.Hooks.registered[k]&&(i(V).rootPropertyValueCache[H]=S.Normalizations.registered[H]?S.Normalizations.registered[H]("extract",null,L[1]):L[1]),"transform"===L[0]&&(C=!0)}}u.mobileHA&&i(V).transformCache.translate3d===a&&(i(V).transformCache.translate3d="(0px, 0px, 0px)",C=!0),C&&S.flushTransformCache(V)}}u.display!==a&&"none"!==u.display&&(b.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(b.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],h,Math.max(0,d+u.duration-t),d,y),1===h&&p(o)}}b.State.isTicking&&w(c)}function p(e,t){if(!b.State.calls[e])return!1;for(var r=b.State.calls[e][0],n=b.State.calls[e][1],o=b.State.calls[e][2],s=b.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&S.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&S.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&(f.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test(f.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var d=!1;f.each(S.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(d=!0,delete i(p).transformCache[t])}),o.mobileHA&&(d=!0,delete i(p).transformCache.translate3d),d&&S.flushTransformCache(p),S.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(g){setTimeout(function(){throw g},1)}s&&o.loop!==!0&&s(n),i(p)&&o.loop===!0&&!t&&(f.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),b(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&f.dequeue(p,o.queue)}b.State.calls[e]=!1;for(var m=0,y=b.State.calls.length;y>m;m++)if(b.State.calls[m]!==!1){l=!0;break}l===!1&&(b.State.isTicking=!1,delete b.State.calls,b.State.calls=[])}var f,d=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),g=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r,a=(new Date).getTime();return r=Math.max(0,16-(a-e)),e=a+r,setTimeout(function(){t(a+r)},r)}}(),m={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},y=!1;if(e.fn&&e.fn.jquery?(f=e,y=!0):f=t.Velocity.Utilities,8>=d&&!y)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=d)return void(jQuery.fn.velocity=jQuery.fn.animate);var h=400,v="swing",b={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:f,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:h,easing:v,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){f.data(e,"velocity",{isSVG:m.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:2},debug:!1};t.pageYOffset!==a?(b.State.scrollAnchor=t,b.State.scrollPropertyLeft="pageXOffset",b.State.scrollPropertyTop="pageYOffset"):(b.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,b.State.scrollPropertyLeft="scrollLeft",b.State.scrollPropertyTop="scrollTop");var x=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o,i,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0,p=1e-4,f=.016;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,l.tension=e,l.friction=t,o=null!==n,o?(c=a(e,t),i=c/n*f):i=f;s=r(s||l,i),u.push(1+s.x),c+=16,Math.abs(s.x)>p&&Math.abs(s.v)>p;);return o?function(e){return u[e*(u.length-1)|0]}:c}}();b.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},f.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){b.Easings[t[0]]=l.apply(null,t[1])});var S=b.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=d)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=d||b.State.isGingerbread||(S.Lists.transformsBase=S.Lists.transformsBase.concat(S.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=d||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=d?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=d?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(d||b.State.isAndroid&&!b.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(b.State.prefixMatches[e])return[b.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),m.isString(b.State.prefixElement.style[n]))return b.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t,r=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;return e=e.replace(r,function(e,t,r,a){return t+t+r+r+a+a}),t=a.exec(e),t?[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&S.setPropertyValue(e,"display","none")}var l=0;if(8>=d)l=f.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===S.getPropertyValue(e,"display")&&(u=!0,S.setPropertyValue(e,"display",S.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(S.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(S.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==S.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(S.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(S.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(S.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(S.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var g;g=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===d&&"filter"===r?g.getPropertyValue(r):g[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var m=s(e,"position");("fixed"===m||"absolute"===m&&/top|left/i.test(r))&&(l=f(e).position()[r]+"px")}return l}var l;if(S.Hooks.registered[r]){var u=r,c=S.Hooks.getRoot(u);n===a&&(n=S.getPropertyValue(e,S.Names.prefixCheck(c)[0])),S.Normalizations.registered[c]&&(n=S.Normalizations.registered[c]("extract",e,n)),l=S.Hooks.extractValue(u,n)}else if(S.Normalizations.registered[r]){var p,g;p=S.Normalizations.registered[r]("name",e),"transform"!==p&&(g=s(e,S.Names.prefixCheck(p)[0]),S.Values.isCSSNullValue(g)&&S.Hooks.templates[r]&&(g=S.Hooks.templates[r][1])),l=S.Normalizations.registered[r]("extract",e,g)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(m){l=0}else l=e.getAttribute(r);else l=s(e,S.Names.prefixCheck(r)[0]);return S.Values.isCSSNullValue(l)&&(l=0),b.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(S.Normalizations.registered[r]&&"transform"===S.Normalizations.registered[r]("name",e))S.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(S.Hooks.registered[r]){var l=r,u=S.Hooks.getRoot(r);n=n||S.getPropertyValue(e,u),a=S.Hooks.injectValue(l,a,n),r=u}if(S.Normalizations.registered[r]&&(a=S.Normalizations.registered[r]("inject",e,a),r=S.Normalizations.registered[r]("name",e)),s=S.Names.prefixCheck(r)[0],8>=d)try{e.style[s]=a}catch(c){b.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&S.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;b.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(S.getPropertyValue(e,t))}var r="";if((d||b.State.isAndroid&&!b.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};f.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;f.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===d&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}S.setPropertyValue(e,"transform",r)}};S.Hooks.register(),S.Normalizations.register(),b.hook=function(e,t,r){var n=a;return e=o(e),f.each(e,function(e,o){if(i(o)===a&&b.init(o),r===a)n===a&&(n=b.CSS.getPropertyValue(o,t));else{var s=b.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&b.CSS.flushTransformCache(o),n=s}}),n};var P=function(){function e(){return s?k.promise||null:l}function n(){function e(e){function p(e,t){var r=a,n=a,i=a;return m.isArray(e)?(r=e[0],!m.isArray(e[1])&&/^[\d-]/.test(e[1])||m.isFunction(e[1])||S.RegEx.isHex.test(e[1])?i=e[1]:(m.isString(e[1])&&!S.RegEx.isHex.test(e[1])||m.isArray(e[1]))&&(n=t?e[1]:u(e[1],s.duration),e[2]!==a&&(i=e[2]))):r=e,t||(n=n||s.easing),m.isFunction(r)&&(r=r.call(o,V,w)),m.isFunction(i)&&(i=i.call(o,V,w)),[r||0,n,i]}function d(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=S.Values.getUnitType(e)),[a,r]}function h(){var e={myParent:o.parentNode||r.body,position:S.getPropertyValue(o,"position"),fontSize:S.getPropertyValue(o,"fontSize")},a=e.position===L.lastPosition&&e.myParent===L.lastParent,n=e.fontSize===L.lastFontSize;L.lastParent=e.myParent,L.lastPosition=e.position,L.lastFontSize=e.fontSize;var s=100,l={};if(n&&a)l.emToPx=L.lastEmToPx,l.percentToPxWidth=L.lastPercentToPxWidth,l.percentToPxHeight=L.lastPercentToPxHeight;else{var u=i(o).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");b.init(u),e.myParent.appendChild(u),f.each(["overflow","overflowX","overflowY"],function(e,t){b.CSS.setPropertyValue(u,t,"hidden")}),b.CSS.setPropertyValue(u,"position",e.position),b.CSS.setPropertyValue(u,"fontSize",e.fontSize),b.CSS.setPropertyValue(u,"boxSizing","content-box"),f.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){b.CSS.setPropertyValue(u,t,s+"%")}),b.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=L.lastPercentToPxWidth=(parseFloat(S.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=L.lastPercentToPxHeight=(parseFloat(S.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=L.lastEmToPx=(parseFloat(S.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===L.remToPx&&(L.remToPx=parseFloat(S.getPropertyValue(r.body,"fontSize"))||16),null===L.vwToPx&&(L.vwToPx=parseFloat(t.innerWidth)/100,L.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=L.remToPx,l.vwToPx=L.vwToPx,l.vhToPx=L.vhToPx,b.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),o),l}if(s.begin&&0===V)try{s.begin.call(g,g)}catch(x){setTimeout(function(){throw x},1)}if("scroll"===A){var P,C,T,F=/^x$/i.test(s.axis)?"Left":"Top",j=parseFloat(s.offset)||0;s.container?m.isWrapped(s.container)||m.isNode(s.container)?(s.container=s.container[0]||s.container,P=s.container["scroll"+F],T=P+f(o).position()[F.toLowerCase()]+j):s.container=null:(P=b.State.scrollAnchor[b.State["scrollProperty"+F]],C=b.State.scrollAnchor[b.State["scrollProperty"+("Left"===F?"Top":"Left")]],T=f(o).offset()[F.toLowerCase()]+j),l={scroll:{rootPropertyValue:!1,startValue:P,currentValue:P,endValue:T,unitType:"",easing:s.easing,scrollData:{container:s.container,direction:F,alternateValue:C}},element:o},b.debug&&console.log("tweensContainer (scroll): ",l.scroll,o)}else if("reverse"===A){if(!i(o).tweensContainer)return void f.dequeue(o,s.queue);"none"===i(o).opts.display&&(i(o).opts.display="auto"),"hidden"===i(o).opts.visibility&&(i(o).opts.visibility="visible"),i(o).opts.loop=!1,i(o).opts.begin=null,i(o).opts.complete=null,v.easing||delete s.easing,v.duration||delete s.duration,s=f.extend({},i(o).opts,s);var E=f.extend(!0,{},i(o).tweensContainer);for(var H in E)if("element"!==H){var N=E[H].startValue;E[H].startValue=E[H].currentValue=E[H].endValue,E[H].endValue=N,m.isEmptyObject(v)||(E[H].easing=s.easing),b.debug&&console.log("reverse tweensContainer ("+H+"): "+JSON.stringify(E[H]),o)}l=E}else if("start"===A){var E;i(o).tweensContainer&&i(o).isAnimating===!0&&(E=i(o).tweensContainer),f.each(y,function(e,t){if(RegExp("^"+S.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(S.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=S.Values.hexToRgb(n),u=i?S.Values.hexToRgb(i):a,c=0;cO;O++){var q={delay:j.delay,progress:j.progress};O===z-1&&(q.display=j.display,q.visibility=j.visibility,q.complete=j.complete),P(g,"reverse",q)}return e()}};b=f.extend(P,b),b.animate=P;var w=t.requestAnimationFrame||g;return b.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(w=function(e){return setTimeout(function(){e(!0)},16)},c()):w=t.requestAnimationFrame||g}),e.Velocity=b,e!==t&&(e.fn.velocity=P,e.fn.velocity.defaults=b.defaults),f.each(["Down","Up"],function(e,t){b.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},d={};l.display===a&&(l.display="Down"===t?"inline"===b.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){d[r]=e.style[r];var a=b.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}d.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in d)e.style[t]=d[t];c&&c.call(i,i),s&&s.resolver(i)},b(e,p,l)}}),f.each(["In","Out"],function(e,t){b.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=f.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),b(this,u,l)}}),b}(window.jQuery||window.Zepto||window,window,document)})); diff --git a/assets/libs/materialize/js/waves.js b/assets/libs/materialize/js/waves.js new file mode 100644 index 0000000..c76d463 --- /dev/null +++ b/assets/libs/materialize/js/waves.js @@ -0,0 +1,338 @@ +/*! + * Waves v0.6.4 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */ + +;(function(window) { + 'use strict'; + + var Waves = Waves || {}; + var $$ = document.querySelectorAll.bind(document); + + // Find exact position of element + function isWindow(obj) { + return obj !== null && obj === obj.window; + } + + function getWindow(elem) { + return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; + } + + function offset(elem) { + var docElem, win, + box = {top: 0, left: 0}, + doc = elem && elem.ownerDocument; + + docElem = doc.documentElement; + + if (typeof elem.getBoundingClientRect !== typeof undefined) { + box = elem.getBoundingClientRect(); + } + win = getWindow(doc); + return { + top: box.top + win.pageYOffset - docElem.clientTop, + left: box.left + win.pageXOffset - docElem.clientLeft + }; + } + + function convertStyle(obj) { + var style = ''; + + for (var a in obj) { + if (obj.hasOwnProperty(a)) { + style += (a + ':' + obj[a] + ';'); + } + } + + return style; + } + + var Effect = { + + // Effect delay + duration: 750, + + show: function(e, element) { + + // Disable right click + if (e.button === 2) { + return false; + } + + var el = element || this; + + // Create ripple + var ripple = document.createElement('div'); + ripple.className = 'waves-ripple'; + el.appendChild(ripple); + + // Get click coordinate and element witdh + var pos = offset(el); + var relativeY = (e.pageY - pos.top); + var relativeX = (e.pageX - pos.left); + var scale = 'scale('+((el.clientWidth / 100) * 10)+')'; + + // Support for touch devices + if ('touches' in e) { + relativeY = (e.touches[0].pageY - pos.top); + relativeX = (e.touches[0].pageX - pos.left); + } + + // Attach data to element + ripple.setAttribute('data-hold', Date.now()); + ripple.setAttribute('data-scale', scale); + ripple.setAttribute('data-x', relativeX); + ripple.setAttribute('data-y', relativeY); + + // Set ripple position + var rippleStyle = { + 'top': relativeY+'px', + 'left': relativeX+'px' + }; + + ripple.className = ripple.className + ' waves-notransition'; + ripple.setAttribute('style', convertStyle(rippleStyle)); + ripple.className = ripple.className.replace('waves-notransition', ''); + + // Scale the ripple + rippleStyle['-webkit-transform'] = scale; + rippleStyle['-moz-transform'] = scale; + rippleStyle['-ms-transform'] = scale; + rippleStyle['-o-transform'] = scale; + rippleStyle.transform = scale; + rippleStyle.opacity = '1'; + + rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['-o-transition-duration'] = Effect.duration + 'ms'; + rippleStyle['transition-duration'] = Effect.duration + 'ms'; + + rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; + + ripple.setAttribute('style', convertStyle(rippleStyle)); + }, + + hide: function(e) { + TouchHandler.touchup(e); + + var el = this; + var width = el.clientWidth * 1.4; + + // Get first ripple + var ripple = null; + var ripples = el.getElementsByClassName('waves-ripple'); + if (ripples.length > 0) { + ripple = ripples[ripples.length - 1]; + } else { + return false; + } + + var relativeX = ripple.getAttribute('data-x'); + var relativeY = ripple.getAttribute('data-y'); + var scale = ripple.getAttribute('data-scale'); + + // Get delay beetween mousedown and mouse leave + var diff = Date.now() - Number(ripple.getAttribute('data-hold')); + var delay = 350 - diff; + + if (delay < 0) { + delay = 0; + } + + // Fade out ripple after delay + setTimeout(function() { + var style = { + 'top': relativeY+'px', + 'left': relativeX+'px', + 'opacity': '0', + + // Duration + '-webkit-transition-duration': Effect.duration + 'ms', + '-moz-transition-duration': Effect.duration + 'ms', + '-o-transition-duration': Effect.duration + 'ms', + 'transition-duration': Effect.duration + 'ms', + '-webkit-transform': scale, + '-moz-transform': scale, + '-ms-transform': scale, + '-o-transform': scale, + 'transform': scale, + }; + + ripple.setAttribute('style', convertStyle(style)); + + setTimeout(function() { + try { + el.removeChild(ripple); + } catch(e) { + return false; + } + }, Effect.duration); + }, delay); + }, + + // Little hack to make can perform waves effect + wrapInput: function(elements) { + for (var a = 0; a < elements.length; a++) { + var el = elements[a]; + + if (el.tagName.toLowerCase() === 'input') { + var parent = el.parentNode; + + // If input already have parent just pass through + if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) { + continue; + } + + // Put element class and style to the specified parent + var wrapper = document.createElement('i'); + wrapper.className = el.className + ' waves-input-wrapper'; + + var elementStyle = el.getAttribute('style'); + + if (!elementStyle) { + elementStyle = ''; + } + + wrapper.setAttribute('style', elementStyle); + + el.className = 'waves-button-input'; + el.removeAttribute('style'); + + // Put element as child + parent.replaceChild(wrapper, el); + wrapper.appendChild(el); + } + } + } + }; + + + /** + * Disable mousedown event for 500ms during and after touch + */ + var TouchHandler = { + /* uses an integer rather than bool so there's no issues with + * needing to clear timeouts if another touch event occurred + * within the 500ms. Cannot mouseup between touchstart and + * touchend, nor in the 500ms after touchend. */ + touches: 0, + allowEvent: function(e) { + var allow = true; + + if (e.type === 'touchstart') { + TouchHandler.touches += 1; //push + } else if (e.type === 'touchend' || e.type === 'touchcancel') { + setTimeout(function() { + if (TouchHandler.touches > 0) { + TouchHandler.touches -= 1; //pop after 500ms + } + }, 500); + } else if (e.type === 'mousedown' && TouchHandler.touches > 0) { + allow = false; + } + + return allow; + }, + touchup: function(e) { + TouchHandler.allowEvent(e); + } + }; + + + /** + * Delegated click handler for .waves-effect element. + * returns null when .waves-effect element not in "click tree" + */ + function getWavesEffectElement(e) { + if (TouchHandler.allowEvent(e) === false) { + return null; + } + + var element = null; + var target = e.target || e.srcElement; + + while (target.parentElement !== null) { + if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) { + element = target; + break; + } else if (target.classList.contains('waves-effect')) { + element = target; + break; + } + target = target.parentElement; + } + + return element; + } + + /** + * Bubble the click and show effect if .waves-effect elem was found + */ + function showEffect(e) { + var element = getWavesEffectElement(e); + + if (element !== null) { + Effect.show(e, element); + + if ('ontouchstart' in window) { + element.addEventListener('touchend', Effect.hide, false); + element.addEventListener('touchcancel', Effect.hide, false); + } + + element.addEventListener('mouseup', Effect.hide, false); + element.addEventListener('mouseleave', Effect.hide, false); + } + } + + Waves.displayEffect = function(options) { + options = options || {}; + + if ('duration' in options) { + Effect.duration = options.duration; + } + + //Wrap input inside tag + Effect.wrapInput($$('.waves-effect')); + + if ('ontouchstart' in window) { + document.body.addEventListener('touchstart', showEffect, false); + } + + document.body.addEventListener('mousedown', showEffect, false); + }; + + /** + * Attach Waves to an input element (or any element which doesn't + * bubble mouseup/mousedown events). + * Intended to be used with dynamically loaded forms/inputs, or + * where the user doesn't want a delegated click handler. + */ + Waves.attach = function(element) { + //FUTURE: automatically add waves classes and allow users + // to specify them with an options param? Eg. light/classic/button + if (element.tagName.toLowerCase() === 'input') { + Effect.wrapInput([element]); + element = element.parentElement; + } + + if ('ontouchstart' in window) { + element.addEventListener('touchstart', showEffect, false); + } + + element.addEventListener('mousedown', showEffect, false); + }; + + window.Waves = Waves; + + document.addEventListener('DOMContentLoaded', function() { + Waves.displayEffect(); + }, false); + +})(window); diff --git a/assets/libs/materialize/sass/components/_buttons.scss b/assets/libs/materialize/sass/components/_buttons.scss new file mode 100755 index 0000000..32fa2ab --- /dev/null +++ b/assets/libs/materialize/sass/components/_buttons.scss @@ -0,0 +1,281 @@ +// shared styles +.btn, +.btn-flat { + border: $button-border; + border-radius: $button-radius; + display: inline-block; + height: $button-height; + line-height: $button-height; + padding: $button-padding; + text-transform: uppercase; + vertical-align: middle; + // Gets rid of tap active state + -webkit-tap-highlight-color: transparent; +} + +// Disabled shared style +.btn.disabled, +.btn-floating.disabled, +.btn-large.disabled, +.btn-flat.disabled, +.btn:disabled, +.btn-floating:disabled, +.btn-large:disabled, +.btn-flat:disabled, +.btn[disabled], +.btn-floating[disabled], +.btn-large[disabled], +.btn-flat[disabled] { + pointer-events: none; + background-color: $button-disabled-background !important; + box-shadow: none; + color: $button-disabled-color !important; + cursor: default; + + &:hover { + background-color: $button-disabled-background !important; + color: $button-disabled-color !important; + } +} + +// Shared icon styles +.btn, +.btn-floating, +.btn-large, +.btn-flat { + + outline: 0; + + i { + font-size: $button-font-size; + line-height: inherit; + } +} + +// Shared focus button style +.btn, +.btn-floating { + &:focus { + background-color: darken($button-raised-background, 10%); + } +} + +// Raised Button +.btn { + text-decoration: none; + color: $button-raised-color; + background-color: $button-raised-background; + text-align: center; + letter-spacing: .5px; + @extend .z-depth-1; + transition: .2s ease-out; + cursor: pointer; + + &:hover { + background-color: $button-raised-background-hover; + @extend .z-depth-1-half; + } +} + +// Floating button +.btn-floating { + display: inline-block; + color: $button-floating-color; + position: relative; + overflow: hidden; + z-index: 1; + width: $button-floating-size; + height: $button-floating-size; + line-height: $button-floating-size; + padding: 0; + background-color: $button-floating-background; + border-radius: $button-floating-radius; + @extend .z-depth-1; + transition: .3s; + cursor: pointer; + vertical-align: middle; + + i { + width: inherit; + display: inline-block; + text-align: center; + color: $button-floating-color; + font-size: $button-large-icon-font-size; + line-height: $button-floating-size; + } + + &:hover { + background-color: $button-floating-background-hover; + @extend .z-depth-1-half; + } + + &:before { + border-radius: 0; + } + + &.btn-large { + width: $button-floating-large-size; + height: $button-floating-large-size; + i { + line-height: $button-floating-large-size; + } + } +} + +// button fix +button.btn-floating { + border: $button-border; +} + +// Fixed Action Button +.fixed-action-btn { + &.active { + ul { + visibility: visible; + } + } + + &.horizontal { + padding: 0 0 0 15px; + + ul { + text-align: right; + right: 64px; + top: 50%; + transform: translateY(-50%); + height: 100%; + left: auto; + width: 500px; /*width 100% only goes to width of button container */ + + li { + display: inline-block; + margin: 15px 15px 0 0; + } + } + } + + &.toolbar { + &.active { + & > a i { + opacity: 0; + } + } + + padding: 0; + height: $button-floating-large-size; + + ul { + display: flex; + top: 0; + bottom: 0; + + li { + flex: 1; + display: inline-block; + margin: 0; + height: 100%; + transition: none; + + a { + display: block; + overflow: hidden; + position: relative; + width: 100%; + height: 100%; + background-color: transparent; + box-shadow: none; + color: #fff; + line-height: $button-floating-large-size; + z-index: 1; + + i { + line-height: inherit; + } + } + } + } + } + + position: fixed; + right: 23px; + bottom: 23px; + padding-top: 15px; + margin-bottom: 0; + z-index: 998; + + ul { + left: 0; + right: 0; + text-align: center; + position: absolute; + bottom: 64px; + margin: 0; + visibility: hidden; + + li { + margin-bottom: 15px; + } + + a.btn-floating { + opacity: 0; + } + } + + .fab-backdrop { + position: absolute; + top: 0; + left: 0; + z-index: -1; + width: $button-floating-size; + height: $button-floating-size; + background-color: $button-floating-background; + border-radius: $button-floating-radius; + transform: scale(0); + } +} + +// Flat button +.btn-flat { + box-shadow: none; + background-color: transparent; + color: $button-flat-color; + cursor: pointer; + transition: background-color .2s; + + &:focus, + &:active { + background-color: transparent; + } + + &:focus, + &:hover { + background-color: rgba(0,0,0,.1); + box-shadow: none; + } + + &:active { + background-color: rgba(0,0,0,.2); + } + + &.disabled { + background-color: transparent !important; + color: $button-flat-disabled-color !important; + cursor: default; + } +} + +// Large button +.btn-large { + @extend .btn; + height: $button-large-height; + line-height: $button-large-height; + + i { + font-size: $button-large-icon-font-size; + } +} + +// Block button +.btn-block { + display: block; +} diff --git a/assets/libs/materialize/sass/components/_cards.scss b/assets/libs/materialize/sass/components/_cards.scss new file mode 100644 index 0000000..c54eca7 --- /dev/null +++ b/assets/libs/materialize/sass/components/_cards.scss @@ -0,0 +1,187 @@ + + +.card-panel { + transition: box-shadow .25s; + padding: $card-padding; + margin: $element-top-margin 0 $element-bottom-margin 0; + border-radius: 2px; + @extend .z-depth-1; + background-color: $card-bg-color; +} + +.card { + position: relative; + margin: $element-top-margin 0 $element-bottom-margin 0; + background-color: $card-bg-color; + transition: box-shadow .25s; + border-radius: 2px; + @extend .z-depth-1; + + + .card-title { + font-size: 24px; + font-weight: 300; + &.activator { + cursor: pointer; + } + } + + // Card Sizes + &.small, &.medium, &.large { + position: relative; + + .card-image { + max-height: 60%; + overflow: hidden; + } + .card-image + .card-content { + max-height: 40%; + } + .card-content { + max-height: 100%; + overflow: hidden; + } + .card-action { + position: absolute; + bottom: 0; + left: 0; + right: 0; + } + } + + &.small { + height: 300px; + } + + &.medium { + height: 400px; + } + + &.large { + height: 500px; + } + + // Horizontal Cards + &.horizontal { + &.small, &.medium, &.large { + .card-image { + height: 100%; + max-height: none; + overflow: visible; + + img { + height: 100%; + } + } + } + + display: flex; + + .card-image { + max-width: 50%; + img { + border-radius: 2px 0 0 2px; + max-width: 100%; + width: auto; + } + } + + .card-stacked { + display: flex; + flex-direction: column; + flex: 1; + position: relative; + + .card-content { + flex-grow: 1; + } + } + } + + // Sticky Action Section + &.sticky-action { + .card-action { + z-index: 2; + } + + .card-reveal { + z-index: 1; + padding-bottom: 64px; + } + } + + + + + .card-image { + position: relative; + + // Image background for content + img { + display: block; + border-radius: 2px 2px 0 0; + position: relative; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + } + + .card-title { + color: $card-bg-color; + position: absolute; + bottom: 0; + left: 0; + padding: $card-padding; + } + + } + + .card-content { + padding: $card-padding; + border-radius: 0 0 2px 2px; + + p { + margin: 0; + color: inherit; + } + .card-title { + line-height: 48px; + } + } + + .card-action { + position: relative; + background-color: inherit; + border-top: 1px solid rgba(160,160,160,.2); + padding: $card-padding; + + a:not(.btn):not(.btn-large):not(.btn-floating) { + color: $card-link-color; + margin-right: $card-padding; + transition: color .3s ease; + text-transform: uppercase; + + &:hover { color: $card-link-color-light; } + } + } + + .card-reveal { + padding: $card-padding; + position: absolute; + background-color: $card-bg-color; + width: 100%; + overflow-y: auto; + left: 0; + top: 100%; + height: 100%; + z-index: 3; + display: none; + + .card-title { + cursor: pointer; + display: block; + } + } +} diff --git a/assets/libs/materialize/sass/components/_carousel.scss b/assets/libs/materialize/sass/components/_carousel.scss new file mode 100644 index 0000000..56e54dd --- /dev/null +++ b/assets/libs/materialize/sass/components/_carousel.scss @@ -0,0 +1,85 @@ +.carousel { + &.carousel-slider { + top: 0; + left: 0; + height: 0; + + .carousel-fixed-item { + &.with-indicators { + bottom: 68px; + } + + position: absolute; + left: 0; + right: 0; + bottom: 20px; + z-index: 1; + } + + .carousel-item { + width: 100%; + height: 100%; + min-height: 400px; + position: absolute; + top: 0; + left: 0; + + h2 { + font-size: 24px; + font-weight: 500; + line-height: 32px; + } + + p { + font-size: 15px; + } + } + } + + overflow: hidden; + position: relative; + width: 100%; + height: 400px; + perspective: 500px; + transform-style: preserve-3d; + transform-origin: 0% 50%; + + .carousel-item { + display: none; + width: 200px; + height: 400px; + position: absolute; + top: 0; + left: 0; + + img { + width: 100%; + } + } + + .indicators { + position: absolute; + text-align: center; + left: 0; + right: 0; + bottom: 0; + margin: 0; + + .indicator-item { + &.active { + background-color: #fff; + } + + display: inline-block; + position: relative; + cursor: pointer; + height: 8px; + width: 8px; + margin: 24px 4px; + background-color: rgba(255,255,255,.5); + + transition: background-color .3s; + border-radius: 50%; + } + } +} diff --git a/assets/libs/materialize/sass/components/_chips.scss b/assets/libs/materialize/sass/components/_chips.scss new file mode 100644 index 0000000..f774a41 --- /dev/null +++ b/assets/libs/materialize/sass/components/_chips.scss @@ -0,0 +1,83 @@ +.chip { + display: inline-block; + height: 32px; + font-size: 13px; + font-weight: 500; + color: rgba(0,0,0,.6); + line-height: 32px; + padding: 0 12px; + border-radius: 16px; + background-color: $chip-bg-color; + margin-bottom: $chip-margin; + margin-right: $chip-margin; + + img { + float: left; + margin: 0 8px 0 -12px; + height: 32px; + width: 32px; + border-radius: 50%; + } + + .close { + cursor: pointer; + float: right; + font-size: 16px; + line-height: 32px; + padding-left: 8px; + } +} + +.chips { + border: none; + border-bottom: 1px solid $chip-border-color; + box-shadow: none; + margin: $input-margin; + min-height: 45px; + outline: none; + transition: all .3s; + + &.focus { + border-bottom: 1px solid $chip-selected-color; + box-shadow: 0 1px 0 0 $chip-selected-color; + } + + &:hover { + cursor: text; + } + + .chip.selected { + background-color: $chip-selected-color; + color: #fff; + } + + .input { + background: none; + border: 0; + color: rgba(0,0,0,.6); + display: inline-block; + font-size: $input-font-size; + height: $input-height; + line-height: 32px; + outline: 0; + margin: 0; + padding: 0 !important; + width: 120px !important; + } + + .input:focus { + border: 0 !important; + box-shadow: none !important; + } +} + +// Form prefix +.prefix ~ .chips { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); +} +.chips:empty ~ label { + font-size: 0.8rem; + transform: translateY(-140%); +} diff --git a/assets/libs/materialize/sass/components/_collapsible.scss b/assets/libs/materialize/sass/components/_collapsible.scss new file mode 100644 index 0000000..6a2cb21 --- /dev/null +++ b/assets/libs/materialize/sass/components/_collapsible.scss @@ -0,0 +1,90 @@ +.collapsible { + border-top: 1px solid $collapsible-border-color; + border-right: 1px solid $collapsible-border-color; + border-left: 1px solid $collapsible-border-color; + margin: $element-top-margin 0 $element-bottom-margin 0; + @extend .z-depth-1; +} + +.collapsible-header { + display: block; + cursor: pointer; + min-height: $collapsible-height; + line-height: $collapsible-height; + padding: 0 1rem; + background-color: $collapsible-header-color; + border-bottom: 1px solid $collapsible-border-color; + + i { + width: 2rem; + font-size: 1.6rem; + line-height: $collapsible-height; + display: block; + float: left; + text-align: center; + margin-right: 1rem; + } +} + +.collapsible-body { + display: none; + border-bottom: 1px solid $collapsible-border-color; + box-sizing: border-box; + + p { + margin: 0; + padding: 2rem; + } +} + +// sideNav collapsible styling +.side-nav, +.side-nav.fixed { + + .collapsible { + border: none; + box-shadow: none; + + li { padding: 0; } + } + + .collapsible-header { + background-color: transparent; + border: none; + line-height: inherit; + height: inherit; + padding: 0 $sidenav-padding; + + &:hover { background-color: rgba(0,0,0,.05); } + i { line-height: inherit; } + } + + .collapsible-body { + border: 0; + background-color: $collapsible-header-color; + + li a { + padding: 0 (7.5px + $sidenav-padding) + 0 (15px + $sidenav-padding); + } + } + +} + +// Popout Collapsible + +.collapsible.popout { + border: none; + box-shadow: none; + > li { + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + // transform: scaleX(.92); + margin: 0 24px; + transition: margin .35s cubic-bezier(0.250, 0.460, 0.450, 0.940); + } + > li.active { + box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); + margin: 16px 0; + // transform: scaleX(1); + } +} diff --git a/assets/libs/materialize/sass/components/_color.scss b/assets/libs/materialize/sass/components/_color.scss new file mode 100644 index 0000000..ef9d600 --- /dev/null +++ b/assets/libs/materialize/sass/components/_color.scss @@ -0,0 +1,412 @@ +// Utility Color Classes + +//.success { +// +//} + +// Google Color Palette defined: http://www.google.com/design/spec/style/color.html + + +$materialize-red: ( + "base": #e51c23, + "lighten-5": #fdeaeb, + "lighten-4": #f8c1c3, + "lighten-3": #f3989b, + "lighten-2": #ee6e73, + "lighten-1": #ea454b, + "darken-1": #d0181e, + "darken-2": #b9151b, + "darken-3": #a21318, + "darken-4": #8b1014, +); + +$red: ( + "base": #F44336, + "lighten-5": #FFEBEE, + "lighten-4": #FFCDD2, + "lighten-3": #EF9A9A, + "lighten-2": #E57373, + "lighten-1": #EF5350, + "darken-1": #E53935, + "darken-2": #D32F2F, + "darken-3": #C62828, + "darken-4": #B71C1C, + "accent-1": #FF8A80, + "accent-2": #FF5252, + "accent-3": #FF1744, + "accent-4": #D50000 +); + +$pink: ( + "base": #e91e63, + "lighten-5": #fce4ec, + "lighten-4": #f8bbd0, + "lighten-3": #f48fb1, + "lighten-2": #f06292, + "lighten-1": #ec407a, + "darken-1": #d81b60, + "darken-2": #c2185b, + "darken-3": #ad1457, + "darken-4": #880e4f, + "accent-1": #ff80ab, + "accent-2": #ff4081, + "accent-3": #f50057, + "accent-4": #c51162 +); + +$purple: ( + "base": #9c27b0, + "lighten-5": #f3e5f5, + "lighten-4": #e1bee7, + "lighten-3": #ce93d8, + "lighten-2": #ba68c8, + "lighten-1": #ab47bc, + "darken-1": #8e24aa, + "darken-2": #7b1fa2, + "darken-3": #6a1b9a, + "darken-4": #4a148c, + "accent-1": #ea80fc, + "accent-2": #e040fb, + "accent-3": #d500f9, + "accent-4": #aa00ff +); + +$deep-purple: ( + "base": #673ab7, + "lighten-5": #ede7f6, + "lighten-4": #d1c4e9, + "lighten-3": #b39ddb, + "lighten-2": #9575cd, + "lighten-1": #7e57c2, + "darken-1": #5e35b1, + "darken-2": #512da8, + "darken-3": #4527a0, + "darken-4": #311b92, + "accent-1": #b388ff, + "accent-2": #7c4dff, + "accent-3": #651fff, + "accent-4": #6200ea +); + +$indigo: ( + "base": #3f51b5, + "lighten-5": #e8eaf6, + "lighten-4": #c5cae9, + "lighten-3": #9fa8da, + "lighten-2": #7986cb, + "lighten-1": #5c6bc0, + "darken-1": #3949ab, + "darken-2": #303f9f, + "darken-3": #283593, + "darken-4": #1a237e, + "accent-1": #8c9eff, + "accent-2": #536dfe, + "accent-3": #3d5afe, + "accent-4": #304ffe +); + +$blue: ( + "base": #2196F3, + "lighten-5": #E3F2FD, + "lighten-4": #BBDEFB, + "lighten-3": #90CAF9, + "lighten-2": #64B5F6, + "lighten-1": #42A5F5, + "darken-1": #1E88E5, + "darken-2": #1976D2, + "darken-3": #1565C0, + "darken-4": #0D47A1, + "accent-1": #82B1FF, + "accent-2": #448AFF, + "accent-3": #2979FF, + "accent-4": #2962FF +); + +$light-blue: ( + "base": #03a9f4, + "lighten-5": #e1f5fe, + "lighten-4": #b3e5fc, + "lighten-3": #81d4fa, + "lighten-2": #4fc3f7, + "lighten-1": #29b6f6, + "darken-1": #039be5, + "darken-2": #0288d1, + "darken-3": #0277bd, + "darken-4": #01579b, + "accent-1": #80d8ff, + "accent-2": #40c4ff, + "accent-3": #00b0ff, + "accent-4": #0091ea +); + +$cyan: ( + "base": #00bcd4, + "lighten-5": #e0f7fa, + "lighten-4": #b2ebf2, + "lighten-3": #80deea, + "lighten-2": #4dd0e1, + "lighten-1": #26c6da, + "darken-1": #00acc1, + "darken-2": #0097a7, + "darken-3": #00838f, + "darken-4": #006064, + "accent-1": #84ffff, + "accent-2": #18ffff, + "accent-3": #00e5ff, + "accent-4": #00b8d4 +); + +$teal: ( + "base": #009688, + "lighten-5": #e0f2f1, + "lighten-4": #b2dfdb, + "lighten-3": #80cbc4, + "lighten-2": #4db6ac, + "lighten-1": #26a69a, + "darken-1": #00897b, + "darken-2": #00796b, + "darken-3": #00695c, + "darken-4": #004d40, + "accent-1": #a7ffeb, + "accent-2": #64ffda, + "accent-3": #1de9b6, + "accent-4": #00bfa5 +); + +$green: ( + "base": #4CAF50, + "lighten-5": #E8F5E9, + "lighten-4": #C8E6C9, + "lighten-3": #A5D6A7, + "lighten-2": #81C784, + "lighten-1": #66BB6A, + "darken-1": #43A047, + "darken-2": #388E3C, + "darken-3": #2E7D32, + "darken-4": #1B5E20, + "accent-1": #B9F6CA, + "accent-2": #69F0AE, + "accent-3": #00E676, + "accent-4": #00C853 +); + +$light-green: ( + "base": #8bc34a, + "lighten-5": #f1f8e9, + "lighten-4": #dcedc8, + "lighten-3": #c5e1a5, + "lighten-2": #aed581, + "lighten-1": #9ccc65, + "darken-1": #7cb342, + "darken-2": #689f38, + "darken-3": #558b2f, + "darken-4": #33691e, + "accent-1": #ccff90, + "accent-2": #b2ff59, + "accent-3": #76ff03, + "accent-4": #64dd17 +); + +$lime: ( + "base": #cddc39, + "lighten-5": #f9fbe7, + "lighten-4": #f0f4c3, + "lighten-3": #e6ee9c, + "lighten-2": #dce775, + "lighten-1": #d4e157, + "darken-1": #c0ca33, + "darken-2": #afb42b, + "darken-3": #9e9d24, + "darken-4": #827717, + "accent-1": #f4ff81, + "accent-2": #eeff41, + "accent-3": #c6ff00, + "accent-4": #aeea00 +); + +$yellow: ( + "base": #ffeb3b, + "lighten-5": #fffde7, + "lighten-4": #fff9c4, + "lighten-3": #fff59d, + "lighten-2": #fff176, + "lighten-1": #ffee58, + "darken-1": #fdd835, + "darken-2": #fbc02d, + "darken-3": #f9a825, + "darken-4": #f57f17, + "accent-1": #ffff8d, + "accent-2": #ffff00, + "accent-3": #ffea00, + "accent-4": #ffd600 +); + +$amber: ( + "base": #ffc107, + "lighten-5": #fff8e1, + "lighten-4": #ffecb3, + "lighten-3": #ffe082, + "lighten-2": #ffd54f, + "lighten-1": #ffca28, + "darken-1": #ffb300, + "darken-2": #ffa000, + "darken-3": #ff8f00, + "darken-4": #ff6f00, + "accent-1": #ffe57f, + "accent-2": #ffd740, + "accent-3": #ffc400, + "accent-4": #ffab00 +); + +$orange: ( + "base": #ff9800, + "lighten-5": #fff3e0, + "lighten-4": #ffe0b2, + "lighten-3": #ffcc80, + "lighten-2": #ffb74d, + "lighten-1": #ffa726, + "darken-1": #fb8c00, + "darken-2": #f57c00, + "darken-3": #ef6c00, + "darken-4": #e65100, + "accent-1": #ffd180, + "accent-2": #ffab40, + "accent-3": #ff9100, + "accent-4": #ff6d00 +); + +$deep-orange: ( + "base": #ff5722, + "lighten-5": #fbe9e7, + "lighten-4": #ffccbc, + "lighten-3": #ffab91, + "lighten-2": #ff8a65, + "lighten-1": #ff7043, + "darken-1": #f4511e, + "darken-2": #e64a19, + "darken-3": #d84315, + "darken-4": #bf360c, + "accent-1": #ff9e80, + "accent-2": #ff6e40, + "accent-3": #ff3d00, + "accent-4": #dd2c00 +); + +$brown: ( + "base": #795548, + "lighten-5": #efebe9, + "lighten-4": #d7ccc8, + "lighten-3": #bcaaa4, + "lighten-2": #a1887f, + "lighten-1": #8d6e63, + "darken-1": #6d4c41, + "darken-2": #5d4037, + "darken-3": #4e342e, + "darken-4": #3e2723 +); + +$blue-grey: ( + "base": #607d8b, + "lighten-5": #eceff1, + "lighten-4": #cfd8dc, + "lighten-3": #b0bec5, + "lighten-2": #90a4ae, + "lighten-1": #78909c, + "darken-1": #546e7a, + "darken-2": #455a64, + "darken-3": #37474f, + "darken-4": #263238 +); + +$grey: ( + "base": #9e9e9e, + "lighten-5": #fafafa, + "lighten-4": #f5f5f5, + "lighten-3": #eeeeee, + "lighten-2": #e0e0e0, + "lighten-1": #bdbdbd, + "darken-1": #757575, + "darken-2": #616161, + "darken-3": #424242, + "darken-4": #212121 +); + +$shades: ( + "black": #000000, + "white": #FFFFFF, + "transparent": transparent +); + +$colors: ( + "materialize-red": $materialize-red, + "red": $red, + "pink": $pink, + "purple": $purple, + "deep-purple": $deep-purple, + "indigo": $indigo, + "blue": $blue, + "light-blue": $light-blue, + "cyan": $cyan, + "teal": $teal, + "green": $green, + "light-green": $light-green, + "lime": $lime, + "yellow": $yellow, + "amber": $amber, + "orange": $orange, + "deep-orange": $deep-orange, + "brown": $brown, + "blue-grey": $blue-grey, + "grey": $grey, + "shades": $shades +); + + +// Color Classes + +@each $color_name, $color in $colors { + @each $color_type, $color_value in $color { + @if $color_type == "base" { + .#{$color_name} { + background-color: $color_value !important; + } + .#{$color_name}-text { + color: $color_value !important; + } + } + @else if $color_name != "shades" { + .#{$color_name}.#{$color_type} { + background-color: $color_value !important; + } + .#{$color_name}-text.text-#{$color_type} { + color: $color_value !important; + } + } + } +} + +// Shade classes +@each $color, $color_value in $shades { + .#{$color} { + background-color: $color_value !important; + } + .#{$color}-text { + color: $color_value !important; + } +} + + +// usage: color("name_of_color", "type_of_color") +// to avoid to repeating map-get($colors, ...) + +@function color($color, $type) { + @if map-has-key($colors, $color) { + $curr_color: map-get($colors, $color); + @if map-has-key($curr_color, $type) { + @return map-get($curr_color, $type); + } + } + @warn "Unknown `#{name}` in $colors."; + @return null; +} + diff --git a/assets/libs/materialize/sass/components/_dropdown.scss b/assets/libs/materialize/sass/components/_dropdown.scss new file mode 100644 index 0000000..a958112 --- /dev/null +++ b/assets/libs/materialize/sass/components/_dropdown.scss @@ -0,0 +1,65 @@ +.dropdown-content { + @extend .z-depth-1; + background-color: $dropdown-bg-color; + margin: 0; + display: none; + min-width: 100px; + max-height: 650px; + overflow-y: auto; + opacity: 0; + position: absolute; + z-index: 999; + will-change: width, height; + + li { + clear: both; + color: $off-black; + cursor: pointer; + min-height: $dropdown-item-height; + line-height: 1.5rem; + width: 100%; + text-align: left; + text-transform: none; + + &:hover, &.active, &.selected { + background-color: $dropdown-hover-bg-color; + } + + &.active.selected { + background-color: darken($dropdown-hover-bg-color, 5%); + } + + &.divider { + min-height: 0; + height: 1px; + } + + & > a, & > span { + font-size: 16px; + color: $dropdown-color; + display: block; + line-height: 22px; + padding: (($dropdown-item-height - 22) / 2) 16px; + } + + & > span > label { + top: 1px; + left: 0; + height: 18px; + } + + // Icon alignment override + & > a > i { + height: inherit; + line-height: inherit; + } + } +} + +// Input field specificity bugfix +.input-field.col .dropdown-content [type="checkbox"] + label { + top: 1px; + left: 0; + height: 18px; +} + diff --git a/assets/libs/materialize/sass/components/_global.scss b/assets/libs/materialize/sass/components/_global.scss new file mode 100644 index 0000000..271e0f8 --- /dev/null +++ b/assets/libs/materialize/sass/components/_global.scss @@ -0,0 +1,800 @@ +//Default styles + +html { + box-sizing: border-box; +} +*, *:before, *:after { + box-sizing: inherit; +} + +body { + // display: flex; + // min-height: 100vh; + // flex-direction: column; +} + +main { + // flex: 1 0 auto; +} + +ul { + &:not(.browser-default) { + padding-left: 0; + list-style-type: none; + + li { + list-style-type: none; + } + } +} + +a { + color: $link-color; + text-decoration: none; + + // Gets rid of tap active state + -webkit-tap-highlight-color: transparent; +} + + +// Positioning +.valign-wrapper { + display: flex; + align-items: center; + + .valign { + display: block; + } +} + + +// classic clearfix +.clearfix { + clear: both; +} + + +// Z-levels +.z-depth-0 { + box-shadow: none !important; +} +.z-depth-1 { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); +} +.z-depth-1-half { + box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2); +} +.z-depth-2 { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3); +} +.z-depth-3 { + box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.3); +} +.z-depth-4 { + box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.3); +} +.z-depth-5 { + box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.3); +} + +.hoverable { + transition: box-shadow .25s; + box-shadow: 0; +} + +.hoverable:hover { + transition: box-shadow .25s; + box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +// Dividers + +.divider { + height: 1px; + overflow: hidden; + background-color: color("grey", "lighten-2"); +} + + +// Blockquote + +blockquote { + margin: 20px 0; + padding-left: 1.5rem; + border-left: 5px solid $primary-color; +} + +// Icon Styles + +i { + line-height: inherit; + + &.left { + float: left; + margin-right: 15px; + } + &.right { + float: right; + margin-left: 15px; + } + &.tiny { + font-size: 1rem; + } + &.small { + font-size: 2rem; + } + &.medium { + font-size: 4rem; + } + &.large { + font-size: 6rem; + } +} + +// Images +img.responsive-img, +video.responsive-video { + max-width: 100%; + height: auto; +} + + +// Pagination + +.pagination { + + li { + display: inline-block; + border-radius: 2px; + text-align: center; + vertical-align: top; + height: 30px; + + a { + color: #444; + display: inline-block; + font-size: 1.2rem; + padding: 0 10px; + line-height: 30px; + } + + &.active a { color: #fff; } + + &.active { background-color: $primary-color; } + + &.disabled a { + cursor: default; + color: #999; + } + + i { + font-size: 2rem; + } + } + + + li.pages ul li { + display: inline-block; + float: none; + } +} +@media #{$medium-and-down} { + .pagination { + width: 100%; + + li.prev, + li.next { + width: 10%; + } + + li.pages { + width: 80%; + overflow: hidden; + white-space: nowrap; + } + } +} + +// Breadcrumbs +.breadcrumb { + font-size: 18px; + color: rgba(255,255,255, .7); + + i, + [class^="mdi-"], [class*="mdi-"], + i.material-icons { + display: inline-block; + float: left; + font-size: 24px; + } + + &:before { + content: '\E5CC'; + color: rgba(255,255,255, .7); + vertical-align: top; + display: inline-block; + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 25px; + margin: 0 10px 0 8px; + -webkit-font-smoothing: antialiased; + } + + &:first-child:before { + display: none; + } + + &:last-child { + color: #fff; + } +} + + +// Parallax +.parallax-container { + position: relative; + overflow: hidden; + height: 500px; +} + +.parallax { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + + img { + display: none; + position: absolute; + left: 50%; + bottom: 0; + min-width: 100%; + min-height: 100%; + -webkit-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + transform: translateX(-50%); + } +} + +// Pushpin +.pin-top, .pin-bottom { + position: relative; +} +.pinned { + position: fixed !important; +} + +/********************* + Transition Classes +**********************/ + +ul.staggered-list li { + opacity: 0; +} + +.fade-in { + opacity: 0; + transform-origin: 0 50%; +} + + +/********************* + Media Query Classes +**********************/ +.hide-on-small-only, .hide-on-small-and-down { + @media #{$small-and-down} { + display: none !important; + } +} +.hide-on-med-and-down { + @media #{$medium-and-down} { + display: none !important; + } +} +.hide-on-med-and-up { + @media #{$medium-and-up} { + display: none !important; + } +} +.hide-on-med-only { + @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) { + display: none !important; + } +} +.hide-on-large-only { + @media #{$large-and-up} { + display: none !important; + } +} +.show-on-large { + @media #{$large-and-up} { + display: block !important; + } +} +.show-on-medium { + @media only screen and (min-width: $small-screen) and (max-width: $medium-screen) { + display: block !important; + } +} +.show-on-small { + @media #{$small-and-down} { + display: block !important; + } +} +.show-on-medium-and-up { + @media #{$medium-and-up} { + display: block !important; + } +} +.show-on-medium-and-down { + @media #{$medium-and-down} { + display: block !important; + } +} + + +// Center text on mobile +.center-on-small-only { + @media #{$small-and-down} { + text-align: center; + } +} + +// Footer +footer.page-footer { + margin-top: 20px; + padding-top: 20px; + background-color: $footer-bg-color; + + .footer-copyright { + overflow: hidden; + height: 50px; + line-height: 50px; + color: rgba(255,255,255,.8); + background-color: rgba(51,51,51,.08); + @extend .light; + } +} + +// Tables +table, th, td { + border: none; +} + +table { + width:100%; + display: table; + + &.bordered > thead > tr, + &.bordered > tbody > tr { + border-bottom: 1px solid $table-border-color; + } + + &.striped > tbody { + > tr:nth-child(odd) { + background-color: $table-striped-color; + } + + > tr > td { + border-radius: 0; + } + } + + &.highlight > tbody > tr { + transition: background-color .25s ease; + &:hover { + background-color: $table-striped-color; + } + } + + &.centered { + thead tr th, tbody tr td { + text-align: center; + } + } + +} + +thead { + border-bottom: 1px solid $table-border-color; +} + +td, th{ + padding: 15px 5px; + display: table-cell; + text-align: left; + vertical-align: middle; + border-radius: 2px; +} + +// Responsive Table +@media #{$medium-and-down} { + + table.responsive-table { + width: 100%; + border-collapse: collapse; + border-spacing: 0; + display: block; + position: relative; + + td:empty:before { + content: '\00a0'; + } + + th, + td { + margin: 0; + vertical-align: top; + } + + th { text-align: left; } + thead { + display: block; + float: left; + + tr { + display: block; + padding: 0 10px 0 0; + + th::before { + content: "\00a0"; + } + } + } + tbody { + display: block; + width: auto; + position: relative; + overflow-x: auto; + white-space: nowrap; + + tr { + display: inline-block; + vertical-align: top; + } + } + th { + display: block; + text-align: right; + } + td { + display: block; + min-height: 1.25em; + text-align: left; + } + tr { padding: 0 10px; } + + /* sort out borders */ + thead { + border: 0; + border-right: 1px solid $table-border-color; + } + + &.bordered { + th { border-bottom: 0; border-left: 0; } + td { border-left: 0; border-right: 0; border-bottom: 0; } + tr { border: 0; } + tbody tr { border-right: 1px solid $table-border-color; } + } + + } + +} + + +// Collections +.collection { + margin: $element-top-margin 0 $element-bottom-margin 0; + border: 1px solid $collection-border-color; + border-radius: 2px; + overflow: hidden; + position: relative; + + .collection-item { + background-color: $collection-bg-color; + line-height: 1.5rem; + padding: 10px 20px; + margin: 0; + border-bottom: 1px solid $collection-border-color; + + // Avatar Collection + &.avatar { + min-height: 84px; + padding-left: 72px; + position: relative; + + .circle { + position: absolute; + width: 42px; + height: 42px; + overflow: hidden; + left: 15px; + display: inline-block; + vertical-align: middle; + } + i.circle { + font-size: 18px; + line-height: 42px; + color: #fff; + background-color: #999; + text-align: center; + } + + + .title { + font-size: 16px; + } + + p { + margin: 0; + } + + .secondary-content { + position: absolute; + top: 16px; + right: 16px; + } + + } + + + &:last-child { + border-bottom: none; + } + + &.active { + background-color: $collection-active-bg-color; + color: $collection-active-color; + + .secondary-content { + color: #fff; + } + } + } + a.collection-item{ + display: block; + transition: .25s; + color: $collection-link-color; + &:not(.active) { + &:hover { + background-color: $collection-hover-bg-color; + } + } + } + + &.with-header { + .collection-header { + background-color: $collection-bg-color; + border-bottom: 1px solid $collection-border-color; + padding: 10px 20px; + } + .collection-item { + padding-left: 30px; + } + .collection-item.avatar { + padding-left: 72px; + } + } + +} +// Made less specific to allow easier overriding +.secondary-content { + float: right; + color: $secondary-color; +} +.collapsible .collection { + margin: 0; + border: none; +} + + + +// Badges +span.badge { + min-width: 3rem; + padding: 0 6px; + margin-left: 14px; + text-align: center; + font-size: 1rem; + line-height: inherit; + color: color('grey', 'darken-1'); + float: right; + box-sizing: border-box; + + &.new { + font-weight: 300; + font-size: 0.8rem; + color: #fff; + background-color: $badge-bg-color; + border-radius: 2px; + } + &.new:after { + content: " new"; + } + + &[data-badge-caption]::after { + content: " " attr(data-badge-caption); + } +} +nav ul a span.badge { + display: inline-block; + float: none; + margin-left: 4px; + line-height: 22px; + height: 22px; +} +.side-nav span.badge.new, +.collapsible span.badge.new { + &::before { + content: ''; + position: absolute; + top: 10px; + right: 0; + bottom: 10px; + left: 0; + background-color: $badge-bg-color; + border-radius: 2px; + z-index: -1; + } + + position: relative; + background-color: transparent; +} +.collapsible span.badge.new { + z-index: 1; +} + + + +// Responsive Videos +.video-container { + position: relative; + padding-bottom: 56.25%; + height: 0; + overflow: hidden; + + iframe, object, embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +// Progress Bar +.progress { + position: relative; + height: 4px; + display: block; + width: 100%; + background-color: lighten($progress-bar-color, 40%); + border-radius: 2px; + margin: $element-top-margin 0 $element-bottom-margin 0; + overflow: hidden; + .determinate { + position: absolute; + top: 0; + left: 0; + bottom: 0; + background-color: $progress-bar-color; + transition: width .3s linear; + } + .indeterminate { + background-color: $progress-bar-color; + &:before { + content: ''; + position: absolute; + background-color: inherit; + top: 0; + left:0; + bottom: 0; + will-change: left, right; + // Custom bezier + animation: indeterminate 2.1s cubic-bezier(0.650, 0.815, 0.735, 0.395) infinite; + + } + &:after { + content: ''; + position: absolute; + background-color: inherit; + top: 0; + left:0; + bottom: 0; + will-change: left, right; + // Custom bezier + animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.840, 0.440, 1.000) infinite; + animation-delay: 1.15s; + } + } +} +@keyframes indeterminate { + 0% { + left: -35%; + right:100%; + } + 60% { + left: 100%; + right: -90%; + } + 100% { + left: 100%; + right: -90%; + } +} + +@keyframes indeterminate-short { + 0% { + left: -200%; + right: 100%; + } + 60% { + left: 107%; + right: -8%; + } + 100% { + left: 107%; + right: -8%; + } +} + + +/******************* + Utility Classes +*******************/ + +.hide { + display: none !important; +} + +// Text Align +.left-align { + text-align: left; +} +.right-align { + text-align: right +} +.center, .center-align { + text-align: center; +} + +.left { + float: left !important; +} +.right { + float: right !important; +} + +// No Text Select +.no-select { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.circle { + border-radius: 50%; +} + +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} + +.truncate { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.no-padding { + padding: 0 !important; +} diff --git a/assets/libs/materialize/sass/components/_grid.scss b/assets/libs/materialize/sass/components/_grid.scss new file mode 100644 index 0000000..4ffc3ed --- /dev/null +++ b/assets/libs/materialize/sass/components/_grid.scss @@ -0,0 +1,147 @@ +.container { + margin: 0 auto; + max-width: 1280px; + width: 90%; +} +@media #{$medium-and-up} { + .container { + width: 85%; + } +} +@media #{$large-and-up} { + .container { + width: 70%; + } +} +.container .row { + margin-left: (-1 * $gutter-width / 2); + margin-right: (-1 * $gutter-width / 2); +} + +.section { + padding-top: 1rem; + padding-bottom: 1rem; + + &.no-pad { + padding: 0; + } + &.no-pad-bot { + padding-bottom: 0; + } + &.no-pad-top { + padding-top: 0; + } +} + + +.row { + margin-left: auto; + margin-right: auto; + margin-bottom: 20px; + + // Clear floating children + &:after { + content: ""; + display: table; + clear: both; + } + + .col { + float: left; + box-sizing: border-box; + padding: 0 $gutter-width / 2; + min-height: 1px; + + &[class*="push-"], + &[class*="pull-"] { + position: relative; + } + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.s#{$i} { + width: $perc; + margin-left: auto; + left: auto; + right: auto; + } + $i: $i + 1; + } + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.offset-s#{$i} { + margin-left: $perc; + } + &.pull-s#{$i} { + right: $perc; + } + &.push-s#{$i} { + left: $perc; + } + $i: $i + 1; + } + + @media #{$medium-and-up} { + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.m#{$i} { + width: $perc; + margin-left: auto; + left: auto; + right: auto; + } + $i: $i + 1 + } + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.offset-m#{$i} { + margin-left: $perc; + } + &.pull-m#{$i} { + right: $perc; + } + &.push-m#{$i} { + left: $perc; + } + $i: $i + 1; + } + } + + @media #{$large-and-up} { + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.l#{$i} { + width: $perc; + margin-left: auto; + left: auto; + right: auto; + } + $i: $i + 1; + } + + $i: 1; + @while $i <= $num-cols { + $perc: unquote((100 / ($num-cols / $i)) + "%"); + &.offset-l#{$i} { + margin-left: $perc; + } + &.pull-l#{$i} { + right: $perc; + } + &.push-l#{$i} { + left: $perc; + } + $i: $i + 1; + } + } + } +} diff --git a/assets/libs/materialize/sass/components/_icons-material-design.scss b/assets/libs/materialize/sass/components/_icons-material-design.scss new file mode 100755 index 0000000..d8d91c1 --- /dev/null +++ b/assets/libs/materialize/sass/components/_icons-material-design.scss @@ -0,0 +1,5 @@ +/* This is needed for some mobile phones to display the Google Icon font properly */ +.material-icons { + text-rendering: optimizeLegibility; + font-feature-settings: 'liga'; +} diff --git a/assets/libs/materialize/sass/components/_materialbox.scss b/assets/libs/materialize/sass/components/_materialbox.scss new file mode 100644 index 0000000..ee37426 --- /dev/null +++ b/assets/libs/materialize/sass/components/_materialbox.scss @@ -0,0 +1,42 @@ +.materialboxed { + display: block; + cursor: zoom-in; + position: relative; + transition: opacity .4s; + + &:hover { + &:not(.active) { + opacity: .8; + } + will-change: left, top, width, height; + } +} + +.materialboxed.active { + cursor: zoom-out; +} + +#materialbox-overlay { + position:fixed; + top:0; + left:0; + right: 0; + bottom: 0; + background-color: #292929; + z-index: 1000; + + will-change: opacity; +} +.materialbox-caption { + position: fixed; + display: none; + color: #fff; + line-height: 50px; + bottom: 0; + width: 100%; + text-align: center; + padding: 0% 15%; + height: 50px; + z-index: 1000; + -webkit-font-smoothing: antialiased; +} \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/_mixins.scss b/assets/libs/materialize/sass/components/_mixins.scss new file mode 100644 index 0000000..054f8f6 --- /dev/null +++ b/assets/libs/materialize/sass/components/_mixins.scss @@ -0,0 +1,5 @@ +// @mixin box-shadow-2($args1, $args2) { +// -webkit-box-shadow: $args1, $args2; +// -moz-box-shadow: $args1, $args2; +// box-shadow: $args1, $args2; +// } \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/_modal.scss b/assets/libs/materialize/sass/components/_modal.scss new file mode 100644 index 0000000..0c540fe --- /dev/null +++ b/assets/libs/materialize/sass/components/_modal.scss @@ -0,0 +1,90 @@ +.modal { + @extend .z-depth-4; + + display: none; + position: fixed; + left: 0; + right: 0; + background-color: #fafafa; + padding: 0; + max-height: 70%; + width: 55%; + margin: auto; + overflow-y: auto; + + border-radius: 2px; + will-change: top, opacity; + + @media #{$medium-and-down} { + width: 80%; + } + + h1,h2,h3,h4 { + margin-top: 0; + } + + .modal-content { + padding: 24px; + } + .modal-close { + cursor: pointer; + } + + .modal-footer { + border-radius: 0 0 2px 2px; + background-color: #fafafa; + padding: 4px 6px; + height: 56px; + width: 100%; + + .btn, .btn-flat { + float: right; + margin: 6px 0; + } + } +} +.modal-overlay { + position: fixed; + z-index: 999; + top: -100px; + left: 0; + bottom: 0; + right: 0; + height: 125%; + width: 100%; + background: #000; + display: none; + + will-change: opacity; +} + +// Modal with fixed action footer +.modal.modal-fixed-footer { + padding: 0; + height: 70%; + + .modal-content { + position: absolute; + height: calc(100% - 56px); + max-height: 100%; + width: 100%; + overflow-y: auto; + } + + .modal-footer { + border-top: 1px solid rgba(0,0,0,.1); + position: absolute; + bottom: 0; + } +} + +// Modal Bottom Sheet Style +.modal.bottom-sheet { + top: auto; + bottom: -100%; + margin: 0; + width: 100%; + max-height: 45%; + border-radius: 0; + will-change: bottom, opacity; +} diff --git a/assets/libs/materialize/sass/components/_navbar.scss b/assets/libs/materialize/sass/components/_navbar.scss new file mode 100644 index 0000000..faf3fea --- /dev/null +++ b/assets/libs/materialize/sass/components/_navbar.scss @@ -0,0 +1,190 @@ +nav { + &.nav-extended { + height: auto; + + .nav-wrapper { + height: auto; + } + } + + color: $navbar-font-color; + @extend .z-depth-1; + background-color: $primary-color; + width: 100%; + height: $navbar-height-mobile; + line-height: $navbar-height-mobile; + + a { color: $navbar-font-color; } + + i, + [class^="mdi-"], [class*="mdi-"], + i.material-icons { + display: block; + font-size: 24px; + height: $navbar-height-mobile; + line-height: $navbar-height-mobile; + } + + .nav-wrapper { + position: relative; + height: 100%; + } + + @media #{$large-and-up} { + a.button-collapse { display: none; } + } + + + // Collapse button + .button-collapse { + float: left; + position: relative; + z-index: 1; + height: $navbar-height-mobile; + margin: 0 18px; + + i { + height: $navbar-height-mobile; + line-height: $navbar-height-mobile; + } + } + + + // Logo + .brand-logo { + position: absolute; + color: $navbar-font-color; + display: inline-block; + font-size: $navbar-brand-font-size; + padding: 0; + white-space: nowrap; + + &.center { + left: 50%; + transform: translateX(-50%); + } + + @media #{$medium-and-down} { + left: 50%; + transform: translateX(-50%); + + &.left, &.right { + padding: 0; + transform: none; + } + + &.left { left: 0.5rem; } + &.right { + right: 0.5rem; + left: auto; + } + } + + &.right { + right: 0.5rem; + padding: 0; + } + + i, + [class^="mdi-"], [class*="mdi-"], + i.material-icons { + float: left; + margin-right: 15px; + } + } + + + // Navbar Links + ul { + margin: 0; + + li { + transition: background-color .3s; + float: left; + padding: 0; + + &.active { + background-color: rgba(0,0,0,.1); + } + } + a { + transition: background-color .3s; + font-size: $navbar-font-size; + color: $navbar-font-color; + display: block; + padding: 0 15px; + cursor: pointer; + + &.btn, &.btn-large, &.btn-flat, &.btn-floating { + margin-top: -2px; + margin-left: 15px; + margin-right: 15px; + } + + &:hover { + background-color: rgba(0,0,0,.1); + } + } + + &.left { + float: left; + } + } + + // Navbar Search Form + form { + height: 100%; + } + + .input-field { + margin: 0; + height: 100%; + + input { + height: 100%; + font-size: 1.2rem; + border: none; + padding-left: 2rem; + + &:focus, &[type=text]:valid, &[type=password]:valid, + &[type=email]:valid, &[type=url]:valid, &[type=date]:valid { + border: none; + box-shadow: none; + } + } + + label { + top: 0; + left: 0; + + i { + color: rgba(255,255,255,.7); + transition: color .3s; + } + &.active i { color: $navbar-font-color; } + &.active { + transform: translateY(0); + } + } + } +} + +// Fixed Navbar +.navbar-fixed { + position: relative; + height: $navbar-height-mobile; + z-index: 997; + + nav { + position: fixed; + } +} +@media #{$medium-and-up} { + nav, nav .nav-wrapper i, nav a.button-collapse, nav a.button-collapse i { + height: $navbar-height; + line-height: $navbar-height; + } + .navbar-fixed { + height: $navbar-height; + } +} diff --git a/assets/libs/materialize/sass/components/_normalize.scss b/assets/libs/materialize/sass/components/_normalize.scss new file mode 100644 index 0000000..5e5e3c8 --- /dev/null +++ b/assets/libs/materialize/sass/components/_normalize.scss @@ -0,0 +1,424 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + box-sizing: content-box; /* 2 */ +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/assets/libs/materialize/sass/components/_prefixer.scss b/assets/libs/materialize/sass/components/_prefixer.scss new file mode 100755 index 0000000..13376de --- /dev/null +++ b/assets/libs/materialize/sass/components/_prefixer.scss @@ -0,0 +1,384 @@ +//--------------------------------------------------- +// Sass Prefixer +// ------------------------------------------------- +// TABLE OF CONTENTS +// (*) denotes a syntax-sugar helper +// ------------------------------------------------- +// +// animation($args) +// animation-delay($delay) +// animation-direction($direction) +// animation-duration($duration) +// animation-fill-mode($mode) +// animation-iteration-count($count) +// animation-name($name) +// animation-play-state($state) +// animation-timing-function($function) +// background-size($args) +// inner-shadow($args) * +// box-sizing($args) +// border-box() * +// content-box() * +// columns($args) +// column-count($count) +// column-gap($gap) +// column-rule($args) +// column-width($width) +// flexbox() +// flex($args) +// order($args) +// align($args) +// justify-content($args) +// gradient($default,$start,$stop) * +// linear-gradient-top($default,$color1,$stop1,$color2,$stop2,[$color3,$stop3,$color4,$stop4])* +// linear-gradient-left($default,$color1,$stop1,$color2,$stop2,[$color3,$stop3,$color4,$stop4])* +// perspective($pixels) +// transform($args) +// transform-origin($args) +// transform-style($style) +// rotate($deg) +// scale($factor) +// translate($x,$y) +// translate3d($x,$y,$z) +// translateHardware($x,$y) * +// text-shadow($args) +// transition($args) +// transition-delay($delay) +// transition-duration($duration) +// transition-property($property) +// transition-timing-function($function) + + +// Animation + +// @mixin animation($args) { +// -webkit-animation: $args; +// -moz-animation: $args; +// -ms-animation: $args; +// -o-animation: $args; +// animation: $args; +// } +// @mixin animation-delay($delay) { +// -webkit-animation-delay: $delay; +// -moz-animation-delay: $delay; +// -ms-animation-delay: $delay; +// -o-animation-delay: $delay; +// animation-delay: $delay; +// } +// @mixin animation-direction($direction) { +// -webkit-animation-direction: $direction; +// -moz-animation-direction: $direction; +// -ms-animation-direction: $direction; +// -o-animation-direction: $direction; +// } +// @mixin animation-duration($duration) { +// -webkit-animation-duration: $duration; +// -moz-animation-duration: $duration; +// -ms-animation-duration: $duration; +// -o-animation-duration: $duration; +// } +// @mixin animation-fill-mode($mode) { +// -webkit-animation-fill-mode: $mode; +// -moz-animation-fill-mode: $mode; +// -ms-animation-fill-mode: $mode; +// -o-animation-fill-mode: $mode; +// animation-fill-mode: $mode; +// } +// @mixin animation-iteration-count($count) { +// -webkit-animation-iteration-count: $count; +// -moz-animation-iteration-count: $count; +// -ms-animation-iteration-count: $count; +// -o-animation-iteration-count: $count; +// animation-iteration-count: $count; +// } +// @mixin animation-name($name) { +// -webkit-animation-name: $name; +// -moz-animation-name: $name; +// -ms-animation-name: $name; +// -o-animation-name: $name; +// animation-name: $name; +// } +// @mixin animation-play-state($state) { +// -webkit-animation-play-state: $state; +// -moz-animation-play-state: $state; +// -ms-animation-play-state: $state; +// -o-animation-play-state: $state; +// animation-play-state: $state; +// } +// @mixin animation-timing-function($function) { +// -webkit-animation-timing-function: $function; +// -moz-animation-timing-function: $function; +// -ms-animation-timing-function: $function; +// -o-animation-timing-function: $function; +// animation-timing-function: $function; +// } + +// Keyframes +// @mixin keyframes($animation-name) { +// @-webkit-keyframes #{$animation-name} { +// @content; +// } +// @-moz-keyframes #{$animation-name} { +// @content; +// } +// @keyframes #{$animation-name} { +// @content; +// } +// } + +// Backface-visibility + +// @mixin backface-visibility($args) { +// -webkit-backface-visibility: $args; +// -moz-backface-visibility: $args; +// -ms-backface-visibility: $args; +// backface-visibility: $args; +// } + + +// Background Size + +// @mixin background-size($args) { +// -webkit-background-size: $args; +// background-size: $args; +// } + +// Box Sizing + +// @mixin box-sizing($args) { +// -webkit-box-sizing: $args; +// -moz-box-sizing: $args; +// box-sizing: $args; +// } +// @mixin border-box(){ +// @include box-sizing(border-box); +// } +// @mixin content-box(){ +// @include box-sizing(content-box); +// } + + +// Columns + +// @mixin columns($args) { +// -webkit-columns: $args; +// -moz-columns: $args; +// columns: $args; +// } +// @mixin column-count($count) { +// -webkit-column-count: $count; +// -moz-column-count: $count; +// column-count: $count; +// } +// @mixin column-gap($gap) { +// -webkit-column-gap: $gap; +// -moz-column-gap: $gap; +// column-gap: $gap; +// } +// @mixin column-width($width) { +// -webkit-column-width: $width; +// -moz-column-width: $width; +// column-width: $width; +// } +// @mixin column-rule($args) { +// -webkit-column-rule: $args; +// -moz-column-rule: $args; +// column-rule: $args; +// } + +// Filter +// @mixin filter($args) { +// -webkit-filter: $args; +// -moz-filter: $args; +// -o-filter: $args; +// -ms-filter: $args; +// } + +// Flexbox +// @mixin flexbox() { +// display: -webkit-box; +// display: -moz-box; +// display: -ms-flexbox; +// display: -webkit-flex; +// display: flex; +// } + // @mixin flex($values) { + // -webkit-box-flex: $values; + // -moz-box-flex: $values; + // -webkit-flex: $values; + // -ms-flex: $values; + // flex: $values; + // } + // @mixin order($val) { + // -webkit-box-ordinal-group: $val; + // -moz-box-ordinal-group: $val; + // -ms-flex-order: $val; + // -webkit-order: $val; + // order: $val; + // } + // @mixin align($align) { + // -webkit-flex-align: $align; + // -ms-flex-align: $align; + // -webkit-align-items: $align; + // align-items: $align; + // } + // @mixin justify-content($val) { + // -webkit-justify-content: $val; + // justify-content: $val; + // } +// Gradients + +// @mixin gradient($default: #F5F5F5, $start: #EEE, $stop: #FFF) { +// @include linear-gradient-top($default,$start,0%,$stop,100%); +// } +// @mixin linear-gradient-top($default,$color1,$stop1,$color2,$stop2) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2)); +// background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2); +// background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2); +// background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2); +// background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2); +// background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2); +// } +// @mixin linear-gradient-top2($default,$color1,$stop1,$color2,$stop2,$color3,$stop3) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3)); +// background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// } +// @mixin linear-gradient-top3($default,$color1,$stop1,$color2,$stop2,$color3,$stop3,$color4,$stop4) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left bottom, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3), color-stop($stop4 $color4)); +// background-image: -webkit-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -moz-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -ms-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -o-linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: linear-gradient(top, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// } +// @mixin linear-gradient-left($default,$color1,$stop1,$color2,$stop2) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2)); +// background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2); +// background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2); +// background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2); +// background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2); +// background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2); +// } +// @mixin linear-gradient-left2($default,$color1,$stop1,$color2,$stop2,$color3,$stop3) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3)); +// background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3); +// } +// @mixin linear-gradient-left3($default,$color1,$stop1,$color2,$stop2,$color3,$stop3,$color4,$stop4) { +// background-color: $default; +// background-image: -webkit-gradient(linear, left top, left top, color-stop($stop1, $color1), color-stop($stop2 $color2), color-stop($stop3 $color3), color-stop($stop4 $color4)); +// background-image: -webkit-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -moz-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -ms-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: -o-linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// background-image: linear-gradient(left, $color1 $stop1, $color2 $stop2, $color3 $stop3, $color4 $stop4); +// } + +// Perspective +@mixin perspective($pixels) { + perspective: $pixels; + -webkit-perspective: $pixels; +} + + +// Text Shadow + +// @mixin text-shadow($args) { +// text-shadow: $args; +// } + + +// Transforms + +// @mixin transform($args) { +// -webkit-transform: $args; +// -moz-transform: $args; +// -ms-transform: $args; +// -o-transform: $args; +// transform: $args; +// } +// @mixin transform-origin($args) { +// -webkit-transform-origin: $args; +// -moz-transform-origin: $args; +// -ms-transform-origin: $args; +// -o-transform-origin: $args; +// transform-origin: $args; +// } +// @mixin transform-style($style) { +// -webkit-transform-style: $style; +// -moz-transform-style: $style; +// -ms-transform-style: $style; +// -o-transform-style: $style; +// transform-style: $style; +// } +// @mixin rotate($deg:45deg){ +// @include transform(rotate($deg)); +// } +// @mixin scale($factor:.5){ +// @include transform(scale($factor)); +// } +// @mixin translate($x,$y){ +// @include transform(translate($x,$y)); +// } +// @mixin translate3d($x,$y,$z) { +// @include transform(translate3d($x,$y,$z)); +// } +// @mixin translateHardware($x,$y) { +// @include translate($x,$y); +// -webkit-transform: translate3d($x,$y,0); +// -moz-transform: translate3d($x,$y,0); +// -o-transform: translate3d($x,$y,0); +// -ms-transform: translate3d($x,$y,0); +// transform: translate3d($x,$y,0); +// } + + +// Transitions + +// @mixin transition($args:200ms) { +// -webkit-transition: $args; +// -moz-transition: $args; +// -o-transition: $args; +// -ms-transition: $args; +// transition: $args; +// } +// @mixin transition-delay($delay:0) { +// -webkit-transition-delay: $delay; +// -moz-transition-delay: $delay; +// -o-transition-delay: $delay; +// -ms-transition-delay: $delay; +// transition-delay: $delay; +// } +// @mixin transition-duration($duration:200ms) { +// -webkit-transition-duration: $duration; +// -moz-transition-duration: $duration; +// -o-transition-duration: $duration; +// -ms-transition-duration: $duration; +// transition-duration: $duration; +// } +// @mixin transition-property($property:all) { +// -webkit-transition-property: $property; +// -moz-transition-property: $property; +// -o-transition-property: $property; +// -ms-transition-property: $property; +// transition-property: $property; +// } +// @mixin transition-timing-function($function:ease) { +// -webkit-transition-timing-function: $function; +// -moz-transition-timing-function: $function; +// -o-transition-timing-function: $function; +// -ms-transition-timing-function: $function; +// transition-timing-function: $function; +// } diff --git a/assets/libs/materialize/sass/components/_preloader.scss b/assets/libs/materialize/sass/components/_preloader.scss new file mode 100644 index 0000000..31e1600 --- /dev/null +++ b/assets/libs/materialize/sass/components/_preloader.scss @@ -0,0 +1,334 @@ +/* + @license + Copyright (c) 2014 The Polymer Project Authors. All rights reserved. + This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt + The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt + The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt + Code distributed by Google as part of the polymer project is also + subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt + */ + +/**************************/ +/* STYLES FOR THE SPINNER */ +/**************************/ + +/* + * Constants: + * STROKEWIDTH = 3px + * ARCSIZE = 270 degrees (amount of circle the arc takes up) + * ARCTIME = 1333ms (time it takes to expand and contract arc) + * ARCSTARTROT = 216 degrees (how much the start location of the arc + * should rotate each time, 216 gives us a + * 5 pointed star shape (it's 360/5 * 3). + * For a 7 pointed star, we might do + * 360/7 * 3 = 154.286) + * CONTAINERWIDTH = 28px + * SHRINK_TIME = 400ms + */ + + +.preloader-wrapper { + display: inline-block; + position: relative; + width: 48px; + height: 48px; + + &.small { + width: 36px; + height: 36px; + } + + &.big { + width: 64px; + height: 64px; + } + + &.active { + /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */ + -webkit-animation: container-rotate 1568ms linear infinite; + animation: container-rotate 1568ms linear infinite; + } +} + +@-webkit-keyframes container-rotate { + to { -webkit-transform: rotate(360deg) } +} + +@keyframes container-rotate { + to { transform: rotate(360deg) } +} + +.spinner-layer { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + border-color: $spinner-default-color; +} + +.spinner-blue, +.spinner-blue-only { + border-color: #4285f4; +} + +.spinner-red, +.spinner-red-only { + border-color: #db4437; +} + +.spinner-yellow, +.spinner-yellow-only { + border-color: #f4b400; +} + +.spinner-green, +.spinner-green-only { + border-color: #0f9d58; +} + +/** + * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee): + * + * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't + * guarantee that the animation will start _exactly_ after that value. So we avoid using + * animation-delay and instead set custom keyframes for each color (as redundant as it + * seems). + * + * We write out each animation in full (instead of separating animation-name, + * animation-duration, etc.) because under the polyfill, Safari does not recognize those + * specific properties properly, treats them as -webkit-animation, and overrides the + * other animation rules. See https://github.com/Polymer/platform/issues/53. + */ +.active .spinner-layer.spinner-blue { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-red { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-yellow { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-green { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +.active .spinner-layer, +.active .spinner-layer.spinner-blue-only, +.active .spinner-layer.spinner-red-only, +.active .spinner-layer.spinner-yellow-only, +.active .spinner-layer.spinner-green-only { + /* durations: 4 * ARCTIME */ + opacity: 1; + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +@-webkit-keyframes fill-unfill-rotate { + 12.5% { -webkit-transform: rotate(135deg); } /* 0.5 * ARCSIZE */ + 25% { -webkit-transform: rotate(270deg); } /* 1 * ARCSIZE */ + 37.5% { -webkit-transform: rotate(405deg); } /* 1.5 * ARCSIZE */ + 50% { -webkit-transform: rotate(540deg); } /* 2 * ARCSIZE */ + 62.5% { -webkit-transform: rotate(675deg); } /* 2.5 * ARCSIZE */ + 75% { -webkit-transform: rotate(810deg); } /* 3 * ARCSIZE */ + 87.5% { -webkit-transform: rotate(945deg); } /* 3.5 * ARCSIZE */ + to { -webkit-transform: rotate(1080deg); } /* 4 * ARCSIZE */ +} + +@keyframes fill-unfill-rotate { + 12.5% { transform: rotate(135deg); } /* 0.5 * ARCSIZE */ + 25% { transform: rotate(270deg); } /* 1 * ARCSIZE */ + 37.5% { transform: rotate(405deg); } /* 1.5 * ARCSIZE */ + 50% { transform: rotate(540deg); } /* 2 * ARCSIZE */ + 62.5% { transform: rotate(675deg); } /* 2.5 * ARCSIZE */ + 75% { transform: rotate(810deg); } /* 3 * ARCSIZE */ + 87.5% { transform: rotate(945deg); } /* 3.5 * ARCSIZE */ + to { transform: rotate(1080deg); } /* 4 * ARCSIZE */ +} + +@-webkit-keyframes blue-fade-in-out { + from { opacity: 1; } + 25% { opacity: 1; } + 26% { opacity: 0; } + 89% { opacity: 0; } + 90% { opacity: 1; } + 100% { opacity: 1; } +} + +@keyframes blue-fade-in-out { + from { opacity: 1; } + 25% { opacity: 1; } + 26% { opacity: 0; } + 89% { opacity: 0; } + 90% { opacity: 1; } + 100% { opacity: 1; } +} + +@-webkit-keyframes red-fade-in-out { + from { opacity: 0; } + 15% { opacity: 0; } + 25% { opacity: 1; } + 50% { opacity: 1; } + 51% { opacity: 0; } +} + +@keyframes red-fade-in-out { + from { opacity: 0; } + 15% { opacity: 0; } + 25% { opacity: 1; } + 50% { opacity: 1; } + 51% { opacity: 0; } +} + +@-webkit-keyframes yellow-fade-in-out { + from { opacity: 0; } + 40% { opacity: 0; } + 50% { opacity: 1; } + 75% { opacity: 1; } + 76% { opacity: 0; } +} + +@keyframes yellow-fade-in-out { + from { opacity: 0; } + 40% { opacity: 0; } + 50% { opacity: 1; } + 75% { opacity: 1; } + 76% { opacity: 0; } +} + +@-webkit-keyframes green-fade-in-out { + from { opacity: 0; } + 65% { opacity: 0; } + 75% { opacity: 1; } + 90% { opacity: 1; } + 100% { opacity: 0; } +} + +@keyframes green-fade-in-out { + from { opacity: 0; } + 65% { opacity: 0; } + 75% { opacity: 1; } + 90% { opacity: 1; } + 100% { opacity: 0; } +} + +/** + * Patch the gap that appear between the two adjacent div.circle-clipper while the + * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11). + */ +.gap-patch { + position: absolute; + top: 0; + left: 45%; + width: 10%; + height: 100%; + overflow: hidden; + border-color: inherit; +} + +.gap-patch .circle { + width: 1000%; + left: -450%; +} + +.circle-clipper { + display: inline-block; + position: relative; + width: 50%; + height: 100%; + overflow: hidden; + border-color: inherit; + + .circle { + width: 200%; + height: 100%; + border-width: 3px; /* STROKEWIDTH */ + border-style: solid; + border-color: inherit; + border-bottom-color: transparent !important; + border-radius: 50%; + -webkit-animation: none; + animation: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; + } + + &.left .circle { + left: 0; + border-right-color: transparent !important; + -webkit-transform: rotate(129deg); + transform: rotate(129deg); + } + &.right .circle { + left: -100%; + border-left-color: transparent !important; + -webkit-transform: rotate(-129deg); + transform: rotate(-129deg); + } +} + + + +.active .circle-clipper.left .circle { + /* duration: ARCTIME */ + -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +.active .circle-clipper.right .circle { + /* duration: ARCTIME */ + -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; + animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; +} + +@-webkit-keyframes left-spin { + from { -webkit-transform: rotate(130deg); } + 50% { -webkit-transform: rotate(-5deg); } + to { -webkit-transform: rotate(130deg); } +} + +@keyframes left-spin { + from { transform: rotate(130deg); } + 50% { transform: rotate(-5deg); } + to { transform: rotate(130deg); } +} + +@-webkit-keyframes right-spin { + from { -webkit-transform: rotate(-130deg); } + 50% { -webkit-transform: rotate(5deg); } + to { -webkit-transform: rotate(-130deg); } +} + +@keyframes right-spin { + from { transform: rotate(-130deg); } + 50% { transform: rotate(5deg); } + to { transform: rotate(-130deg); } +} + +#spinnerContainer.cooldown { + /* duration: SHRINK_TIME */ + -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1); + animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1); +} + +@-webkit-keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} + +@keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/_roboto.scss b/assets/libs/materialize/sass/components/_roboto.scss new file mode 100644 index 0000000..741ab5b --- /dev/null +++ b/assets/libs/materialize/sass/components/_roboto.scss @@ -0,0 +1,49 @@ +@font-face { + font-family: "Roboto"; + src: local(Roboto Thin), url('#{$roboto-font-path}Roboto-Thin.eot'); + src: url("#{$roboto-font-path}Roboto-Thin.eot?#iefix") format('embedded-opentype'), + url("#{$roboto-font-path}Roboto-Thin.woff2") format("woff2"), + url("#{$roboto-font-path}Roboto-Thin.woff") format("woff"), + url("#{$roboto-font-path}Roboto-Thin.ttf") format("truetype"); + + font-weight: 200; +} +@font-face { + font-family: "Roboto"; + src: local(Roboto Light), url('#{$roboto-font-path}Roboto-Light.eot'); + src: url("#{$roboto-font-path}Roboto-Light.eot?#iefix") format('embedded-opentype'), + url("#{$roboto-font-path}Roboto-Light.woff2") format("woff2"), + url("#{$roboto-font-path}Roboto-Light.woff") format("woff"), + url("#{$roboto-font-path}Roboto-Light.ttf") format("truetype"); + font-weight: 300; +} + +@font-face { + font-family: "Roboto"; + src: local(Roboto Regular), url('#{$roboto-font-path}Roboto-Regular.eot'); + src: url("#{$roboto-font-path}Roboto-Regular.eot?#iefix") format('embedded-opentype'), + url("#{$roboto-font-path}Roboto-Regular.woff2") format("woff2"), + url("#{$roboto-font-path}Roboto-Regular.woff") format("woff"), + url("#{$roboto-font-path}Roboto-Regular.ttf") format("truetype"); + font-weight: 400; +} + +@font-face { + font-family: "Roboto"; + src: url('#{$roboto-font-path}Roboto-Medium.eot'); + src: url("#{$roboto-font-path}Roboto-Medium.eot?#iefix") format('embedded-opentype'), + url("#{$roboto-font-path}Roboto-Medium.woff2") format("woff2"), + url("#{$roboto-font-path}Roboto-Medium.woff") format("woff"), + url("#{$roboto-font-path}Roboto-Medium.ttf") format("truetype"); + font-weight: 500; +} + +@font-face { + font-family: "Roboto"; + src: url('#{$roboto-font-path}Roboto-Bold.eot'); + src: url("#{$roboto-font-path}Roboto-Bold.eot?#iefix") format('embedded-opentype'), + url("#{$roboto-font-path}Roboto-Bold.woff2") format("woff2"), + url("#{$roboto-font-path}Roboto-Bold.woff") format("woff"), + url("#{$roboto-font-path}Roboto-Bold.ttf") format("truetype"); + font-weight: 700; +} diff --git a/assets/libs/materialize/sass/components/_sideNav.scss b/assets/libs/materialize/sass/components/_sideNav.scss new file mode 100644 index 0000000..ff51224 --- /dev/null +++ b/assets/libs/materialize/sass/components/_sideNav.scss @@ -0,0 +1,208 @@ +.side-nav { + position: fixed; + width: 300px; + left: 0; + top: 0; + margin: 0; + transform: translateX(-100%); + height: 100%; + height: calc(100% + 60px); + height: -moz-calc(100%); //Temporary Firefox Fix + padding-bottom: 60px; + background-color: $sidenav-bg-color; + z-index: 999; + overflow-y: auto; + will-change: transform; + backface-visibility: hidden; + transform: translateX(-105%); + + @extend .z-depth-1; + + // Right Align + &.right-aligned { + right: 0; + transform: translateX(105%); + left: auto; + transform: translateX(100%); + } + + .collapsible { + margin: 0; + } + + + li { + float: none; + line-height: $sidenav-item-height; + + &.active { background-color: rgba(0,0,0,.05); } + } + + a { + color: $sidenav-font-color; + display: block; + font-size: $sidenav-font-size; + font-weight: 500; + height: $sidenav-item-height; + line-height: $sidenav-item-height; + padding: 0 ($sidenav-padding * 2); + + &:hover { background-color: rgba(0,0,0,.05);} + + &.btn, &.btn-large, &.btn-flat, &.btn-floating { + margin: 10px 15px; + } + + &.btn, + &.btn-large, + &.btn-floating { color: $button-raised-color; } + &.btn-flat { color: $button-flat-color; } + + &.btn:hover, + &.btn-large:hover { background-color: lighten($button-raised-background, 5%); } + &.btn-floating:hover { background-color: $button-raised-background; } + } + + li > a > i, + li > a > [class^="mdi-"], li > a > [class*="mdi-"], + li > a > i.material-icons { + float: left; + height: $sidenav-item-height; + line-height: $sidenav-item-height; + margin: 0 ($sidenav-padding * 2) 0 0; + width: $sidenav-item-height / 2; + color: rgba(0,0,0,.54); + } + + .divider { + margin: ($sidenav-padding / 2) 0 0 0; + } + + .subheader { + &:hover { + background-color: transparent; + } + + cursor: initial; + pointer-events: none; + color: rgba(0,0,0,.54); + font-size: $sidenav-font-size; + font-weight: 500; + line-height: $sidenav-item-height; + } + + .userView { + position: relative; + padding: ($sidenav-padding * 2) ($sidenav-padding * 2) 0; + margin-bottom: $sidenav-padding / 2; + + & > a { + &:hover { background-color: transparent; } + height: auto; + padding: 0; + } + + .background { + overflow: hidden; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + } + + .circle, .name, .email { + display: block; + } + + .circle { + height: 64px; + width: 64px; + } + + .name, + .email { + font-size: $sidenav-font-size; + line-height: 24px; + } + + .name { + margin-top: 16px; + font-weight: 500; + } + + .email { + padding-bottom: 16px; + font-weight: 400; + } + } +} + + +// Touch interaction +.drag-target { + height: 100%; + width: 10px; + position: fixed; + top: 0; + z-index: 998; +} + + +// Fixed side-nav shown +.side-nav.fixed { + left: 0; + transform: translateX(0); + position: fixed; + + // Right Align + &.right-aligned { + right: 0; + left: auto; + } +} + +// Fixed sideNav hide on smaller +@media #{$medium-and-down} { + .side-nav { + &.fixed { + transform: translateX(-105%); + + &.right-aligned { + transform: translateX(105%); + } + } + + a { + padding: 0 $sidenav-padding; + } + + .userView { + padding: $sidenav-padding $sidenav-padding 0; + } + } +} + + +.side-nav .collapsible-body > ul:not(.collapsible) > li.active, +.side-nav.fixed .collapsible-body > ul:not(.collapsible) > li.active { + background-color: $primary-color; + a { + color: $sidenav-bg-color; + } +} + + +#sidenav-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + + height: 120vh; + background-color: rgba(0,0,0,.5); + z-index: 997; + + will-change: opacity; +} diff --git a/assets/libs/materialize/sass/components/_slider.scss b/assets/libs/materialize/sass/components/_slider.scss new file mode 100644 index 0000000..2265cdb --- /dev/null +++ b/assets/libs/materialize/sass/components/_slider.scss @@ -0,0 +1,92 @@ +.slider { + position: relative; + height: 400px; + width: 100%; + + // Fullscreen slider + &.fullscreen { + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + + ul.slides { + height: 100%; + } + + ul.indicators { + z-index: 2; + bottom: 30px; + } + } + + .slides { + background-color: $slider-bg-color; + margin: 0; + height: 400px; + + li { + opacity: 0; + position: absolute; + top: 0; + left: 0; + z-index: 1; + width: 100%; + height: inherit; + overflow: hidden; + + img { + height: 100%; + width: 100%; + background-size: cover; + background-position: center; + } + + .caption { + color: #fff; + position: absolute; + top: 15%; + left: 15%; + width: 70%; + opacity: 0; + + p { color: $slider-bg-color-light; } + } + + &.active { + z-index: 2; + } + } + } + + + .indicators { + position: absolute; + text-align: center; + left: 0; + right: 0; + bottom: 0; + margin: 0; + + .indicator-item { + display: inline-block; + position: relative; + cursor: pointer; + height: 16px; + width: 16px; + margin: 0 12px; + background-color: $slider-bg-color-light; + + transition: background-color .3s; + border-radius: 50%; + + &.active { + background-color: $slider-indicator-color; + } + } + } + +} \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/_table_of_contents.scss b/assets/libs/materialize/sass/components/_table_of_contents.scss new file mode 100644 index 0000000..2872bdb --- /dev/null +++ b/assets/libs/materialize/sass/components/_table_of_contents.scss @@ -0,0 +1,33 @@ +/*************** + Nav List +***************/ +.table-of-contents { + &.fixed { + position: fixed; + } + + li { + padding: 2px 0; + } + a { + display: inline-block; + font-weight: 300; + color: #757575; + padding-left: 20px; + height: 1.5rem; + line-height: 1.5rem; + letter-spacing: .4; + display: inline-block; + + &:hover { + color: lighten(#757575, 20%); + padding-left: 19px; + border-left: 1px solid lighten(color("materialize-red", "base"),10%); + } + &.active { + font-weight: 500; + padding-left: 18px; + border-left: 2px solid lighten(color("materialize-red", "base"),10%); + } + } +} diff --git a/assets/libs/materialize/sass/components/_tabs.scss b/assets/libs/materialize/sass/components/_tabs.scss new file mode 100755 index 0000000..6d79538 --- /dev/null +++ b/assets/libs/materialize/sass/components/_tabs.scss @@ -0,0 +1,99 @@ +.tabs { + &.tabs-transparent { + background-color: transparent; + + .tab a, + .tab.disabled a, + .tab.disabled a:hover { + color: rgba(255,255,255,0.7); + } + + .tab a:hover, + .tab a.active { + color: #fff; + } + + .indicator { + background-color: #fff; + } + } + + &.tabs-fixed-width { + display: flex; + + .tab { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + } + } + + position: relative; + overflow-x: auto; + overflow-y: hidden; + height: 48px; + width: 100%; + background-color: $tabs-bg-color; + margin: 0 auto; + white-space: nowrap; + + .tab { + display: inline-block; + text-align: center; + line-height: 48px; + height: 48px; + padding: 0; + margin: 0; + text-transform: uppercase; + + a { + &:hover, + &.active { + background-color: transparent; + color: $tabs-text-color; + } + + color: rgba($tabs-text-color, .7); + display: block; + width: 100%; + height: 100%; + padding: 0 24px; + font-size: 14px; + text-overflow: ellipsis; + overflow: hidden; + transition: color .28s ease; + } + + &.disabled a, + &.disabled a:hover { + color: rgba($tabs-text-color, .7); + cursor: default; + } + } + .indicator { + position: absolute; + bottom: 0; + height: 2px; + background-color: $tabs-underline-color; + will-change: left, right; + } +} + +// Fixed sideNav hide on smaller +@media #{$medium-and-down} { + .tabs { + display: flex; + + .tab { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + + a { + padding: 0 12px; + } + } + } +} diff --git a/assets/libs/materialize/sass/components/_toast.scss b/assets/libs/materialize/sass/components/_toast.scss new file mode 100644 index 0000000..7d4ef90 --- /dev/null +++ b/assets/libs/materialize/sass/components/_toast.scss @@ -0,0 +1,65 @@ +#toast-container { + display:block; + position: fixed; + z-index: 10000; + + @media #{$small-and-down} { + min-width: 100%; + bottom: 0%; + } + @media #{$medium-only} { + left: 5%; + bottom: 7%; + max-width: 90%; + } + @media #{$large-and-up} { + top: 10%; + right: 7%; + max-width: 86%; + } +} + +.toast { + @extend .z-depth-1; + border-radius: 2px; + top: 0; + width: auto; + clear: both; + margin-top: 10px; + position: relative; + max-width:100%; + height: auto; + min-height: $toast-height; + line-height: 1.5em; + word-break: break-all; + background-color: $toast-color; + padding: 10px 25px; + font-size: 1.1rem; + font-weight: 300; + color: $toast-text-color; + + display: flex; + align-items: center; + justify-content: space-between; + + .btn, .btn-flat { + margin: 0; + margin-left: 3rem; + } + + &.rounded{ + border-radius: 24px; + } + + @media #{$small-and-down} { + width:100%; + border-radius: 0; + } + @media #{$medium-only} { + float: left; + } + @media #{$large-and-up} { + float: right; + } + +} diff --git a/assets/libs/materialize/sass/components/_tooltip.scss b/assets/libs/materialize/sass/components/_tooltip.scss new file mode 100644 index 0000000..93d9764 --- /dev/null +++ b/assets/libs/materialize/sass/components/_tooltip.scss @@ -0,0 +1,32 @@ +.material-tooltip { + padding: 10px 8px; + font-size: 1rem; + z-index: 2000; + background-color: transparent; + border-radius: 2px; + color: #fff; + min-height: 36px; + line-height: 120%; + opacity: 0; + display: none; + position: absolute; + text-align: center; + max-width: calc(100% - 4px); + overflow: hidden; + left: 0; + top: 0; + pointer-events: none; +} + +.backdrop { + position: absolute; + opacity: 0; + display: none; + height: 7px; + width: 14px; + border-radius: 0 0 50% 50%; + background-color: #323232; + z-index: -1; + transform-origin: 50% 0%; + transform: translate3d(0,0,0); +} diff --git a/assets/libs/materialize/sass/components/_typography.scss b/assets/libs/materialize/sass/components/_typography.scss new file mode 100755 index 0000000..5301c80 --- /dev/null +++ b/assets/libs/materialize/sass/components/_typography.scss @@ -0,0 +1,61 @@ + +a { + text-decoration: none; +} + +html{ + line-height: 1.5; + + @media only screen and (min-width: 0) { + font-size: 14px; + } + + @media only screen and (min-width: $medium-screen) { + font-size: 14.5px; + } + + @media only screen and (min-width: $large-screen) { + font-size: 15px; + } + + font-family: "Roboto", sans-serif; + font-weight: normal; + color: $off-black; +} +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + line-height: 1.1; +} + +// Header Styles +h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } +h1 { font-size: $h1-fontsize; line-height: 110%; margin: ($h1-fontsize / 2) 0 ($h1-fontsize / 2.5) 0;} +h2 { font-size: $h2-fontsize; line-height: 110%; margin: ($h2-fontsize / 2) 0 ($h2-fontsize / 2.5) 0;} +h3 { font-size: $h3-fontsize; line-height: 110%; margin: ($h3-fontsize / 2) 0 ($h3-fontsize / 2.5) 0;} +h4 { font-size: $h4-fontsize; line-height: 110%; margin: ($h4-fontsize / 2) 0 ($h4-fontsize / 2.5) 0;} +h5 { font-size: $h5-fontsize; line-height: 110%; margin: ($h5-fontsize / 2) 0 ($h5-fontsize / 2.5) 0;} +h6 { font-size: $h6-fontsize; line-height: 110%; margin: ($h6-fontsize / 2) 0 ($h6-fontsize / 2.5) 0;} + +// Text Styles +em { font-style: italic; } +strong { font-weight: 500; } +small { font-size: 75%; } +.light { font-weight: 300; } +.thin { font-weight: 200; } + + +.flow-text{ + font-weight: 300; + $i: 0; + @while $i <= $intervals { + @media only screen and (min-width : 360 + ($i * $interval-size)) { + font-size: 1.2rem * (1 + (.02 * $i)); + } + $i: $i + 1; + } + + // Handle below 360px screen + @media only screen and (max-width: 360px) { + font-size: 1.2rem; + } +} \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/_variables.scss b/assets/libs/materialize/sass/components/_variables.scss new file mode 100644 index 0000000..351014d --- /dev/null +++ b/assets/libs/materialize/sass/components/_variables.scss @@ -0,0 +1,313 @@ +// ========================================================================== +// Materialize variables +// ========================================================================== +// +// Table of Contents: +// +// 1. Colors +// 2. Badges +// 3. Buttons +// 4. Cards +// 5. Collapsible +// 6. Chips +// 7. Date Picker +// 8. Dropdown +// 10. Forms +// 11. Global +// 12. Grid +// 13. Navigation Bar +// 14. Side Navigation +// 15. Photo Slider +// 16. Spinners | Loaders +// 17. Tabs +// 18. Tables +// 19. Toasts +// 20. Typography +// 21. Footer +// 22. Flow Text +// 23. Collections +// 24. Progress Bar + + + +// 1. Colors +// ========================================================================== + +$primary-color: color("materialize-red", "lighten-2") !default; +$primary-color-light: lighten($primary-color, 15%) !default; +$primary-color-dark: darken($primary-color, 15%) !default; + +$secondary-color: color("teal", "lighten-1") !default; +$success-color: color("green", "base") !default; +$error-color: color("red", "base") !default; +$link-color: color("light-blue", "darken-1") !default; + + +// 2. Badges +// ========================================================================== + +$badge-bg-color: $secondary-color !default; + + +// 3. Buttons +// ========================================================================== + +// Shared styles +$button-border: none !default; +$button-background-focus: lighten($secondary-color, 4%) !default; +$button-font-size: 1.3rem !default; +$button-height: 36px !default; +$button-padding: 0 2rem !default; +$button-radius: 2px !default; + +// Disabled styles +$button-disabled-background: #DFDFDF !default; +$button-disabled-color: #9F9F9F !default; + +// Raised buttons +$button-raised-background: $secondary-color !default; +$button-raised-background-hover: lighten($button-raised-background, 5%) !default; +$button-raised-color: #fff !default; + +// Large buttons +$button-large-icon-font-size: 1.6rem !default; +$button-large-height: $button-height * 1.5 !default; + +// Flat buttons +$button-flat-color: #343434 !default; +$button-flat-disabled-color: lighten(#999, 10%) !default; + +// Floating buttons +$button-floating-background: $secondary-color !default; +$button-floating-background-hover: $button-floating-background !default; +$button-floating-color: #fff !default; +$button-floating-size: 40px !default; +$button-floating-large-size: 56px !default; +$button-floating-radius: 50% !default; + + +// 4. Cards +// ========================================================================== + +$card-padding: 20px !default; +$card-bg-color: #fff !default; +$card-link-color: color("orange", "accent-2") !default; +$card-link-color-light: lighten($card-link-color, 20%) !default; + + +// 5. Collapsible +// ========================================================================== + +$collapsible-height: 3rem !default; +$collapsible-header-color: #fff !default; +$collapsible-border-color: #ddd !default; + + +// 6. Chips +// ========================================================================== + +$chip-bg-color: #e4e4e4 !default; +$chip-border-color: #9e9e9e !default; +$chip-selected-color: #26a69a !default; +$chip-margin: 5px !default; + + +// 7. Date Picker +// ========================================================================== + +$datepicker-weekday-bg: darken($secondary-color, 7%) !default; +$datepicker-date-bg: $secondary-color !default; +$datepicker-year: rgba(255, 255, 255, .4) !default; +$datepicker-focus: rgba(0,0,0, .05) !default; +$datepicker-selected: $secondary-color !default; +$datepicker-selected-outfocus: desaturate(lighten($secondary-color, 35%), 15%) !default; + + +// 8. Dropdown +// ========================================================================== + +$dropdown-bg-color: #fff !default; +$dropdown-hover-bg-color: #eee !default; +$dropdown-color: $secondary-color !default; +$dropdown-item-height: 50px !default; + + +// 9. Fonts +// ========================================================================== + +$roboto-font-path: "../fonts/roboto/" !default; + + +// 10. Forms +// ========================================================================== + +// Text Inputs + Textarea +$input-height: 3rem !default; +$input-border-color: color("grey", "base") !default; +$input-border: 1px solid $input-border-color !default; +$input-background: #fff !default; +$input-error-color: $error-color !default; +$input-success-color: $success-color !default; +$input-focus-color: $secondary-color !default; +$input-font-size: 1rem !default; +$input-margin: 0 0 20px 0 !default; +$input-padding: 0 !default; +$input-transition: all .3s !default; +$label-font-size: .8rem !default; +$input-disabled-color: rgba(0,0,0, .26) !default; +$input-disabled-solid-color: #BDBDBD !default; +$input-disabled-border: 1px dotted $input-disabled-color !default; +$input-invalid-border: 1px solid $input-error-color !default; +$placeholder-text-color: lighten($input-border-color, 20%) !default; + +// Radio Buttons +$radio-fill-color: $secondary-color !default; +$radio-empty-color: #5a5a5a !default; +$radio-border: 2px solid $radio-fill-color !default; + +// Range +$range-height: 14px !default; +$range-width: 14px !default; +$track-height: 3px !default; + +// Select +$select-border: 1px solid #f2f2f2 !default; +$select-background: rgba(255, 255, 255, 0.90) !default; +$select-focus: 1px solid lighten($secondary-color, 47%) !default; +$select-padding: 5px !default; +$select-radius: 2px !default; +$select-disabled-color: rgba(0,0,0,.3) !default; + +// Switches +$switch-bg-color: $secondary-color !default; +$switch-checked-lever-bg: desaturate(lighten($secondary-color, 25%), 25%) !default; +$switch-unchecked-bg: #F1F1F1 !default; +$switch-unchecked-lever-bg: #818181 !default; +$switch-radius: 15px !default; + + +// 11. Global +// ========================================================================== + +// Media Query Ranges +$small-screen-up: 601px !default; +$medium-screen-up: 993px !default; +$large-screen-up: 1201px !default; +$small-screen: 600px !default; +$medium-screen: 992px !default; +$large-screen: 1200px !default; + +$medium-and-up: "only screen and (min-width : #{$small-screen-up})" !default; +$large-and-up: "only screen and (min-width : #{$medium-screen-up})" !default; +$small-and-down: "only screen and (max-width : #{$small-screen})" !default; +$medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; +$medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; + + +// 12. Grid +// ========================================================================== + +$num-cols: 12 !default; +$gutter-width: 1.5rem !default; +$element-top-margin: $gutter-width/3 !default; +$element-bottom-margin: ($gutter-width*2)/3 !default; + + +// 13. Navigation Bar +// ========================================================================== + +$navbar-height: 64px !default; +$navbar-height-mobile: 56px !default; +$navbar-font-size: 1rem !default; +$navbar-font-color: #fff !default; +$navbar-brand-font-size: 2.1rem !default; + +// 14. Side Navigation +// ========================================================================== + +$sidenav-font-size: 14px !default; +$sidenav-font-color: rgba(0,0,0,.87) !default; +$sidenav-bg-color: #fff !default; +$sidenav-padding: 16px !default; +$sidenav-item-height: 48px !default; + + +// 15. Photo Slider +// ========================================================================== + +$slider-bg-color: color('grey', 'base') !default; +$slider-bg-color-light: color('grey', 'lighten-2') !default; +$slider-indicator-color: color('green', 'base') !default; + + +// 16. Spinners | Loaders +// ========================================================================== + +$spinner-default-color: $secondary-color !default; + + +// 17. Tabs +// ========================================================================== + +$tabs-underline-color: $primary-color-light !default; +$tabs-text-color: $primary-color !default; +$tabs-bg-color: #fff !default; + + +// 18. Tables +// ========================================================================== + +$table-border-color: #d0d0d0 !default; +$table-striped-color: #f2f2f2 !default; + + +// 19. Toasts +// ========================================================================== + +$toast-height: 48px !default; +$toast-color: #323232 !default; +$toast-text-color: #fff !default; + + +// 20. Typography +// ========================================================================== + +$off-black: rgba(0, 0, 0, 0.87) !default; +// Header Styles +$h1-fontsize: 4.2rem !default; +$h2-fontsize: 3.56rem !default; +$h3-fontsize: 2.92rem !default; +$h4-fontsize: 2.28rem !default; +$h5-fontsize: 1.64rem !default; +$h6-fontsize: 1rem !default; + + +// 21. Footer +// ========================================================================== + +$footer-bg-color: $primary-color !default; + + +// 22. Flow Text +// ========================================================================== + +$range : $large-screen - $small-screen !default; +$intervals: 20 !default; +$interval-size: $range / $intervals !default; + + +// 23. Collections +// ========================================================================== + +$collection-border-color: #e0e0e0 !default; +$collection-bg-color: #fff !default; +$collection-active-bg-color: $secondary-color !default; +$collection-active-color: lighten($secondary-color, 55%) !default; +$collection-hover-bg-color: #ddd !default; +$collection-link-color: $secondary-color !default; + + +// 24. Progress Bar +// ========================================================================== + +$progress-bar-color: $secondary-color !default; diff --git a/assets/libs/materialize/sass/components/_waves.scss b/assets/libs/materialize/sass/components/_waves.scss new file mode 100644 index 0000000..c569ab1 --- /dev/null +++ b/assets/libs/materialize/sass/components/_waves.scss @@ -0,0 +1,177 @@ + +/*! + * Waves v0.6.0 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */ + + +.waves-effect { + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + // white-space: nowrap; + // outline: 0; + + vertical-align: middle; + // cursor: pointer; + // border: none; + // outline: none; + // color: inherit; + // background-color: rgba(0, 0, 0, 0); + // font-size: 1em; + // line-height:1em; + // text-align: center; + // text-decoration: none; + z-index: 1; + will-change: opacity, transform; + transition: .3s ease-out; + + .waves-ripple { + position: absolute; + border-radius: 50%; + width: 20px; + height: 20px; + margin-top:-10px; + margin-left:-10px; + opacity: 0; + + background: rgba(0,0,0,0.2); + // $gradient: rgba(0,0,0,0.2) 0,rgba(0,0,0,.3) 40%,rgba(0,0,0,.4) 50%,rgba(0,0,0,.5) 60%,rgba(255,255,255,0) 70%; + // background: -webkit-radial-gradient($gradient); + // background: -o-radial-gradient($gradient); + // background: -moz-radial-gradient($gradient); + // background: radial-gradient($gradient); + transition: all 0.7s ease-out; + transition-property: transform, opacity; + transform: scale(0); + pointer-events: none; + } + + // Waves Colors + &.waves-light .waves-ripple { + background-color: rgba(255, 255, 255, 0.45); + } + + &.waves-red .waves-ripple { + background-color: rgba(244, 67, 54, .70); + } + &.waves-yellow .waves-ripple { + background-color: rgba(255, 235, 59, .70); + } + &.waves-orange .waves-ripple { + background-color: rgba(255, 152, 0, .70); + } + &.waves-purple .waves-ripple { + background-color: rgba(156, 39, 176, 0.70); + } + &.waves-green .waves-ripple { + background-color: rgba(76, 175, 80, 0.70); + } + &.waves-teal .waves-ripple { + background-color: rgba(0, 150, 136, 0.70); + } + + // Style input button bug. + input[type="button"], input[type="reset"], input[type="submit"] { + border: 0; + font-style: normal; + font-size: inherit; + text-transform: inherit; + background: none; + } + + img { + position: relative; + z-index: -1; + } +} + +.waves-notransition { + transition: none #{"!important"}; +} + +.waves-circle { + transform: translateZ(0); + -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); +} + +// .waves-button, +// .waves-button:hover, +// .waves-button:visited, +// .waves-button-input { +// white-space: nowrap; +// vertical-align: middle; +// cursor: pointer; +// border: none; +// outline: none; +// color: inherit; +// background-color: rgba(0, 0, 0, 0); +// font-size: 1em; +// line-height:1em; +// text-align: center; +// text-decoration: none; +// z-index: 1; +// } + +// .waves-button { +// padding: 0.85em 1.1em; +// border-radius: 0.2em; +// } + +// .waves-button-input { +// margin: 0; +// padding: 0.85em 1.1em; +// } + +.waves-input-wrapper { + border-radius: 0.2em; + vertical-align: bottom; + + // &.waves-button { + // padding: 0; + // } + + .waves-button-input { + position: relative; + top: 0; + left: 0; + z-index: 1; + } +} + +.waves-circle { + text-align: center; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; + border-radius: 50%; + -webkit-mask-image: none; +} + +// .waves-float { + // -webkit-mask-image: none; + // @include box-shadow(0px 1px 1.5px 1px rgba(0, 0, 0, 0.12)); + + // &:active { + // @include box-shadow(0px 8px 20px 1px rgba(0, 0, 0, 0.30)); +// } +// } + +.waves-block { + display: block; +} + +/* Firefox Bug: link not triggered */ +.waves-effect .waves-ripple { + z-index: -1; +} \ No newline at end of file diff --git a/assets/libs/materialize/sass/components/date_picker/_default.date.scss b/assets/libs/materialize/sass/components/date_picker/_default.date.scss new file mode 100755 index 0000000..84e96b5 --- /dev/null +++ b/assets/libs/materialize/sass/components/date_picker/_default.date.scss @@ -0,0 +1,435 @@ +/* ========================================================================== + $BASE-DATE-PICKER + ========================================================================== */ +/** + * The picker box. + */ +.picker__box { + padding: 0 1em; +} +/** + * The header containing the month and year stuff. + */ +.picker__header { + text-align: center; + position: relative; + margin-top: .75em; +} +/** + * The month and year labels. + */ +.picker__month, +.picker__year { +// font-weight: 500; + display: inline-block; + margin-left: .25em; + margin-right: .25em; +} +/** + * The month and year selectors. + */ +.picker__select--month, +.picker__select--year { + + height: 2em; + padding: 0; + margin-left: .25em; + margin-right: .25em; +} + +// Modified +.picker__select--month.browser-default { + display: inline; + background-color: #FFFFFF; + width: 40%; +} +.picker__select--year.browser-default { + display: inline; + background-color: #FFFFFF; + width: 26%; +} +.picker__select--month:focus, +.picker__select--year:focus { + border-color: $datepicker-focus; +} +/** + * The month navigation buttons. + */ +.picker__nav--prev, +.picker__nav--next { + position: absolute; + padding: .5em 1.25em; + width: 1em; + height: 1em; + box-sizing: content-box; + top: -0.25em; +} +//@media (min-width: 24.5em) { +// .picker__nav--prev, +// .picker__nav--next { +// top: -0.33em; +// } +//} +.picker__nav--prev { + left: -1em; + padding-right: 1.25em; +} +//@media (min-width: 24.5em) { +// .picker__nav--prev { +// padding-right: 1.5em; +// } +//} +.picker__nav--next { + right: -1em; + padding-left: 1.25em; +} +//@media (min-width: 24.5em) { +// .picker__nav--next { +// padding-left: 1.5em; +// } +//} + +.picker__nav--disabled, +.picker__nav--disabled:hover, +.picker__nav--disabled:before, +.picker__nav--disabled:before:hover { + cursor: default; + background: none; + border-right-color: #f5f5f5; + border-left-color: #f5f5f5; +} +/** + * The calendar table of dates + */ +.picker__table { + text-align: center; + border-collapse: collapse; + border-spacing: 0; + table-layout: fixed; + font-size: 1rem; + width: 100%; + margin-top: .75em; + margin-bottom: .5em; +} + + + +.picker__table th, .picker__table td { + text-align: center; +} + + + + + + +.picker__table td { + margin: 0; + padding: 0; +} +/** + * The weekday labels + */ +.picker__weekday { + width: 14.285714286%; + font-size: .75em; + padding-bottom: .25em; + color: #999999; + font-weight: 500; + /* Increase the spacing a tad */ +} +@media (min-height: 33.875em) { + .picker__weekday { + padding-bottom: .5em; + } +} +/** + * The days on the calendar + */ + +.picker__day--today { + position: relative; + color: #595959; + letter-spacing: -.3; + padding: .75rem 0; + font-weight: 400; + border: 1px solid transparent; + +} + +//.picker__day--today:before { +// content: " "; +// position: absolute; +// top: 2px; +// right: 2px; +// width: 0; +// height: 0; +// border-top: 0.5em solid #0059bc; +// border-left: .5em solid transparent; +//} +.picker__day--disabled:before { + border-top-color: #aaaaaa; +} + + +.picker__day--infocus:hover{ + cursor: pointer; + color: #000; + font-weight: 500; +} + +.picker__day--outfocus { + display: none; + padding: .75rem 0; + color: #fff; + +} +.picker__day--outfocus:hover { + cursor: pointer; + color: #dddddd; +// background: #b1dcfb; + font-weight: 500; +} + + +.picker__day--highlighted { +// border-color: #0089ec; +} +.picker__day--highlighted:hover, +.picker--focused .picker__day--highlighted { + cursor: pointer; +// color: #000000; +// background: #b1dcfb; +// font-weight: 500; +} +.picker__day--selected, +.picker__day--selected:hover, +.picker--focused .picker__day--selected { + + +// Circle background + border-radius: 50%; + transform: scale(.75); + background: #0089ec; + color: #ffffff; +} +.picker__day--disabled, +.picker__day--disabled:hover, +.picker--focused .picker__day--disabled { + background: #f5f5f5; + border-color: #f5f5f5; + color: #dddddd; + cursor: default; +} +.picker__day--highlighted.picker__day--disabled, +.picker__day--highlighted.picker__day--disabled:hover { + background: #bbbbbb; +} +/** + * The footer containing the "today", "clear", and "close" buttons. + */ +.picker__footer { + text-align: center; + display: flex; + align-items: center; + justify-content: space-between; +} +.picker__button--today, +.picker__button--clear, +.picker__button--close { + border: 1px solid #ffffff; + background: #ffffff; + font-size: .8em; + padding: .66em 0; + font-weight: bold; + width: 33%; + display: inline-block; + vertical-align: bottom; +} +.picker__button--today:hover, +.picker__button--clear:hover, +.picker__button--close:hover { + cursor: pointer; + color: #000000; + background: #b1dcfb; + border-bottom-color: #b1dcfb; +} +.picker__button--today:focus, +.picker__button--clear:focus, +.picker__button--close:focus { + background: #b1dcfb; + border-color: $datepicker-focus; + outline: none; +} +.picker__button--today:before, +.picker__button--clear:before, +.picker__button--close:before { + position: relative; + display: inline-block; + height: 0; +} +.picker__button--today:before, +.picker__button--clear:before { + content: " "; + margin-right: .45em; +} +.picker__button--today:before { + top: -0.05em; + width: 0; + border-top: 0.66em solid #0059bc; + border-left: .66em solid transparent; +} +.picker__button--clear:before { + top: -0.25em; + width: .66em; + border-top: 3px solid #ee2200; +} +.picker__button--close:before { + content: "\D7"; + top: -0.1em; + vertical-align: top; + font-size: 1.1em; + margin-right: .35em; + color: #777777; +} +.picker__button--today[disabled], +.picker__button--today[disabled]:hover { + background: #f5f5f5; + border-color: #f5f5f5; + color: #dddddd; + cursor: default; +} +.picker__button--today[disabled]:before { + border-top-color: #aaaaaa; +} + +/* ========================================================================== + CUSTOM MATERIALIZE STYLES + ========================================================================== */ +.picker__box { + border-radius: 2px; + overflow: hidden; +} + +.picker__date-display { + text-align: center; + background-color: $datepicker-date-bg; + color: #fff; + padding-bottom: 15px; + font-weight: 300; +} + +.picker__nav--prev:hover, +.picker__nav--next:hover { + cursor: pointer; + color: #000000; + background: $datepicker-selected-outfocus; +} + +.picker__weekday-display { + background-color: $datepicker-weekday-bg; + padding: 10px; + font-weight: 200; + letter-spacing: .5; + font-size: 1rem; + margin-bottom: 15px; +} + +.picker__month-display { + text-transform: uppercase; + font-size: 2rem; +} +.picker__day-display { + + font-size: 4.5rem; + font-weight: 400; +} +.picker__year-display { + font-size: 1.8rem; + color: $datepicker-year; +} + +.picker__box { + padding: 0; +} +.picker__calendar-container { + padding: 0 1rem; + + thead { + border: none; + } +} + +// Calendar +.picker__table { + margin-top: 0; + margin-bottom: .5em; +} + +.picker__day--infocus { + color: #595959; + letter-spacing: -.3; + padding: .75rem 0; + font-weight: 400; + border: 1px solid transparent; +} + +//Today style +.picker__day.picker__day--today { + color: $datepicker-selected; +} + +.picker__day.picker__day--today.picker__day--selected { + color: #fff; +} + +// Table Header +.picker__weekday { + font-size: .9rem; +} + + +.picker__day--selected, +.picker__day--selected:hover, +.picker--focused .picker__day--selected { + // Circle background + border-radius: 50%; + transform: scale(.9); + background-color: $datepicker-selected; + &.picker__day--outfocus { + background-color: $datepicker-selected-outfocus; + } + color: #ffffff; +} + +.picker__footer { + text-align: right; + padding: 5px 10px; +} + +// Materialize modified +.picker__close, .picker__today { + font-size: 1.1rem; + padding: 0 1rem; + color: $datepicker-selected; +} + +//month nav buttons +.picker__nav--prev:before, +.picker__nav--next:before { + content: " "; + border-top: .5em solid transparent; + border-bottom: .5em solid transparent; + border-right: 0.75em solid #676767; + width: 0; + height: 0; + display: block; + margin: 0 auto; +} +.picker__nav--next:before { + border-right: 0; + border-left: 0.75em solid #676767; +} +button.picker__today:focus, button.picker__clear:focus, button.picker__close:focus { + background-color: $datepicker-selected-outfocus; +} diff --git a/assets/libs/materialize/sass/components/date_picker/_default.scss b/assets/libs/materialize/sass/components/date_picker/_default.scss new file mode 100755 index 0000000..971fbc7 --- /dev/null +++ b/assets/libs/materialize/sass/components/date_picker/_default.scss @@ -0,0 +1,201 @@ +/* ========================================================================== + $BASE-PICKER + ========================================================================== */ +/** + * Note: the root picker element should *NOT* be styled more than what's here. + */ +.picker { + font-size: 16px; + text-align: left; + line-height: 1.2; + color: #000000; + position: absolute; + z-index: 10000; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +/** + * The picker input element. + */ +.picker__input { + cursor: default; +} +/** + * When the picker is opened, the input element is "activated". + */ +.picker__input.picker__input--active { + border-color: #0089ec; +} +/** + * The holder is the only "scrollable" top-level container element. + */ +.picker__holder { + width: 100%; + overflow-y: auto; + -webkit-overflow-scrolling: touch; +} + +/*! + * Default mobile-first, responsive styling for pickadate.js + * Demo: http://amsul.github.io/pickadate.js + */ +/** + * Note: the root picker element should *NOT* be styled more than what's here. + */ +/** + * Make the holder and frame fullscreen. + */ +.picker__holder, +.picker__frame { + bottom: 0; + left: 0; + right: 0; + top: 100%; +} +/** + * The holder should overlay the entire screen. + */ +.picker__holder { + position: fixed; + -webkit-transition: background 0.15s ease-out, top 0s 0.15s; + -moz-transition: background 0.15s ease-out, top 0s 0.15s; + transition: background 0.15s ease-out, top 0s 0.15s; + -webkit-backface-visibility: hidden; +} +/** + * The frame that bounds the box contents of the picker. + */ +.picker__frame { + position: absolute; + margin: 0 auto; + min-width: 256px; + +// picker width + width: 300px; + max-height: 350px; + + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -moz-opacity: 0; + opacity: 0; + -webkit-transition: all 0.15s ease-out; + -moz-transition: all 0.15s ease-out; + transition: all 0.15s ease-out; +} +@media (min-height: 28.875em) { + .picker__frame { + overflow: visible; + top: auto; + bottom: -100%; + max-height: 80%; + } +} +@media (min-height: 40.125em) { + .picker__frame { + margin-bottom: 7.5%; + } +} +/** + * The wrapper sets the stage to vertically align the box contents. + */ +.picker__wrap { + display: table; + width: 100%; + height: 100%; +} +@media (min-height: 28.875em) { + .picker__wrap { + display: block; + } +} +/** + * The box contains all the picker contents. + */ +.picker__box { + background: #ffffff; + display: table-cell; + vertical-align: middle; +} +//@media (min-height: 26.5em) { +// .picker__box { +//// font-size: 1.25em; +// } +//} +@media (min-height: 28.875em) { + .picker__box { + display: block; + +// picker header font-size +// font-size: 1rem; + + border: 1px solid #777777; + border-top-color: #898989; + border-bottom-width: 0; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; + -webkit-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); + -moz-box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); + box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); + } +} +//@media (min-height: 40.125em) { +// .picker__box { +// font-size: 1.1rem; +// border-bottom-width: 1px; +// -webkit-border-radius: 5px; +// -moz-border-radius: 5px; +// border-radius: 5px; +// } +//} +/** + * When the picker opens... + */ +.picker--opened .picker__holder { + top: 0; + background: transparent; + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)"; + zoom: 1; + background: rgba(0, 0, 0, 0.32); + -webkit-transition: background 0.15s ease-out; + -moz-transition: background 0.15s ease-out; + transition: background 0.15s ease-out; +} +.picker--opened .picker__frame { + top: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + -moz-opacity: 1; + opacity: 1; +} +@media (min-height: 35.875em) { + .picker--opened .picker__frame { + top: 10%; + bottom: auto; + } +} +/** + * For `large` screens, transform into an inline picker. + */ + +/* ========================================================================== + CUSTOM MATERIALIZE STYLES + ========================================================================== */ + +.picker__input.picker__input--active { + border-color: color("blue", "lighten-5"); +} + +.picker__frame { + margin: 0 auto; + max-width: 325px; +} + +@media (min-height: 38.875em) { + .picker--opened .picker__frame { + top: 10%; + bottom: auto; + } +} diff --git a/assets/libs/materialize/sass/components/date_picker/_default.time.scss b/assets/libs/materialize/sass/components/date_picker/_default.time.scss new file mode 100755 index 0000000..0b159c8 --- /dev/null +++ b/assets/libs/materialize/sass/components/date_picker/_default.time.scss @@ -0,0 +1,125 @@ +/* ========================================================================== + $BASE-TIME-PICKER + ========================================================================== */ +/** + * The list of times. + */ +.picker__list { + list-style: none; + padding: 0.75em 0 4.2em; + margin: 0; +} +/** + * The times on the clock. + */ +.picker__list-item { + border-bottom: 1px solid #dddddd; + border-top: 1px solid #dddddd; + margin-bottom: -1px; + position: relative; + background: #ffffff; + padding: .75em 1.25em; +} +@media (min-height: 46.75em) { + .picker__list-item { + padding: .5em 1em; + } +} +/* Hovered time */ +.picker__list-item:hover { + cursor: pointer; + color: #000000; + background: #b1dcfb; + border-color: #0089ec; + z-index: 10; +} +/* Highlighted and hovered/focused time */ +.picker__list-item--highlighted { + border-color: #0089ec; + z-index: 10; +} +.picker__list-item--highlighted:hover, +.picker--focused .picker__list-item--highlighted { + cursor: pointer; + color: #000000; + background: #b1dcfb; +} +/* Selected and hovered/focused time */ +.picker__list-item--selected, +.picker__list-item--selected:hover, +.picker--focused .picker__list-item--selected { + background: #0089ec; + color: #ffffff; + z-index: 10; +} +/* Disabled time */ +.picker__list-item--disabled, +.picker__list-item--disabled:hover, +.picker--focused .picker__list-item--disabled { + background: #f5f5f5; + border-color: #f5f5f5; + color: #dddddd; + cursor: default; + border-color: #dddddd; + z-index: auto; +} +/** + * The clear button + */ +.picker--time .picker__button--clear { + display: block; + width: 80%; + margin: 1em auto 0; + padding: 1em 1.25em; + background: none; + border: 0; + font-weight: 500; + font-size: .67em; + text-align: center; + text-transform: uppercase; + color: #666; +} +.picker--time .picker__button--clear:hover, +.picker--time .picker__button--clear:focus { + color: #000000; + background: #b1dcfb; + background: #ee2200; + border-color: #ee2200; + cursor: pointer; + color: #ffffff; + outline: none; +} +.picker--time .picker__button--clear:before { + top: -0.25em; + color: #666; + font-size: 1.25em; + font-weight: bold; +} +.picker--time .picker__button--clear:hover:before, +.picker--time .picker__button--clear:focus:before { + color: #ffffff; +} + +/* ========================================================================== + $DEFAULT-TIME-PICKER + ========================================================================== */ +/** + * The frame the bounds the time picker. + */ +.picker--time .picker__frame { + min-width: 256px; + max-width: 320px; +} +/** + * The picker box. + */ +.picker--time .picker__box { + font-size: 1em; + background: #f2f2f2; + padding: 0; +} +@media (min-height: 40.125em) { + .picker--time .picker__box { + margin-bottom: 5em; + } +} diff --git a/assets/libs/materialize/sass/components/forms/_checkboxes.scss b/assets/libs/materialize/sass/components/forms/_checkboxes.scss new file mode 100644 index 0000000..a8743c1 --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_checkboxes.scss @@ -0,0 +1,220 @@ +/* Checkboxes + ========================================================================== */ + +/* CUSTOM CSS CHECKBOXES */ +form p { + margin-bottom: 10px; + text-align: left; +} + +form p:last-child { + margin-bottom: 0; +} + +/* Remove default checkbox */ +[type="checkbox"]:not(:checked), +[type="checkbox"]:checked { + position: absolute; + left: -9999px; + opacity: 0; +} + +// Checkbox Styles +[type="checkbox"] { + // Text Label Style + + label { + position: relative; + padding-left: 35px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 1rem; + + -webkit-user-select: none; /* webkit (safari, chrome) browsers */ + -moz-user-select: none; /* mozilla browsers */ + -khtml-user-select: none; /* webkit (konqueror) browsers */ + -ms-user-select: none; /* IE10+ */ + } + + /* checkbox aspect */ + + label:before, + &:not(.filled-in) + label:after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; + z-index: 0; + border: 2px solid $radio-empty-color; + border-radius: 1px; + margin-top: 2px; + transition: .2s; + } + + &:not(.filled-in) + label:after { + border: 0; + transform: scale(0); + } + + &:not(:checked):disabled + label:before { + border: none; + background-color: $input-disabled-color; + } + + // Focused styles + &.tabbed:focus + label:after { + transform: scale(1); + border: 0; + border-radius: 50%; + box-shadow: 0 0 0 10px rgba(0,0,0,.1); + background-color: rgba(0,0,0,.1); + } +} + +[type="checkbox"]:checked { + + label:before { + top: -4px; + left: -5px; + width: 12px; + height: 22px; + border-top: 2px solid transparent; + border-left: 2px solid transparent; + border-right: $radio-border; + border-bottom: $radio-border; + transform: rotate(40deg); + backface-visibility: hidden; + transform-origin: 100% 100%; + } + + &:disabled + label:before { + border-right: 2px solid $input-disabled-color; + border-bottom: 2px solid $input-disabled-color; + } +} + +/* Indeterminate checkbox */ +[type="checkbox"]:indeterminate { + +label:before { + top: -11px; + left: -12px; + width: 10px; + height: 22px; + border-top: none; + border-left: none; + border-right: $radio-border; + border-bottom: none; + transform: rotate(90deg); + backface-visibility: hidden; + transform-origin: 100% 100%; + } + + // Disabled indeterminate + &:disabled + label:before { + border-right: 2px solid $input-disabled-color; + background-color: transparent; + } +} + +// Filled in Style +[type="checkbox"].filled-in { + // General + + label:after { + border-radius: 2px; + } + + + label:before, + + label:after { + content: ''; + left: 0; + position: absolute; + /* .1s delay is for check animation */ + transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s; + z-index: 1; + } + + // Unchecked style + &:not(:checked) + label:before { + width: 0; + height: 0; + border: 3px solid transparent; + left: 6px; + top: 10px; + + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + -webkit-transform-origin: 20% 40%; + transform-origin: 100% 100%; + } + + &:not(:checked) + label:after { + height: 20px; + width: 20px; + background-color: transparent; + border: 2px solid $radio-empty-color; + top: 0px; + z-index: 0; + } + + // Checked style + &:checked { + + label:before { + top: 0; + left: 1px; + width: 8px; + height: 13px; + border-top: 2px solid transparent; + border-left: 2px solid transparent; + border-right: 2px solid $input-background; + border-bottom: 2px solid $input-background; + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; + } + + + label:after { + top: 0; + width: 20px; + height: 20px; + border: 2px solid $secondary-color; + background-color: $secondary-color; + z-index: 0; + } + } + + // Focused styles + &.tabbed:focus + label:after { + border-radius: 2px; + border-color: $radio-empty-color; + background-color: rgba(0,0,0,.1); + } + + &.tabbed:checked:focus + label:after { + border-radius: 2px; + background-color: $secondary-color; + border-color: $secondary-color; + } + + // Disabled style + &:disabled:not(:checked) + label:before { + background-color: transparent; + border: 2px solid transparent; + } + + &:disabled:not(:checked) + label:after { + border-color: transparent; + background-color: $input-disabled-solid-color; + } + + &:disabled:checked + label:before { + background-color: transparent; + } + + &:disabled:checked + label:after { + background-color: $input-disabled-solid-color; + border-color: $input-disabled-solid-color; + } +} diff --git a/assets/libs/materialize/sass/components/forms/_file-input.scss b/assets/libs/materialize/sass/components/forms/_file-input.scss new file mode 100644 index 0000000..3b3fe55 --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_file-input.scss @@ -0,0 +1,38 @@ +/* File Input + ========================================================================== */ + +.file-field { + position: relative; + + .file-path-wrapper { + overflow: hidden; + padding-left: 10px; + } + + input.file-path { width: 100%; } + + .btn { + float: left; + height: $input-height; + line-height: $input-height; + } + + span { + cursor: pointer; + } + + input[type=file] { + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + width: 100%; + margin: 0; + padding: 0; + font-size: 20px; + cursor: pointer; + opacity: 0; + filter: alpha(opacity=0); + } +} diff --git a/assets/libs/materialize/sass/components/forms/_forms.scss b/assets/libs/materialize/sass/components/forms/_forms.scss new file mode 100644 index 0000000..e9b65b4 --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_forms.scss @@ -0,0 +1,22 @@ +// Remove Focus Boxes +select:focus { + outline: $select-focus; +} + +button:focus { + outline: none; + background-color: $button-background-focus; +} + +label { + font-size: $label-font-size; + color: $input-border-color; +} + +@import 'input-fields'; +@import 'radio-buttons'; +@import 'checkboxes'; +@import 'switches'; +@import 'select'; +@import 'file-input'; +@import 'range'; diff --git a/assets/libs/materialize/sass/components/forms/_input-fields.scss b/assets/libs/materialize/sass/components/forms/_input-fields.scss new file mode 100644 index 0000000..ef7451b --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_input-fields.scss @@ -0,0 +1,286 @@ +/* Text Inputs + Textarea + ========================================================================== */ + +/* Style Placeholders */ + +::-webkit-input-placeholder { + color: $placeholder-text-color; +} + +:-moz-placeholder { /* Firefox 18- */ + color: $placeholder-text-color; +} + +::-moz-placeholder { /* Firefox 19+ */ + color: $placeholder-text-color; +} + +:-ms-input-placeholder { + color: $placeholder-text-color; +} + +/* Text inputs */ + +input:not([type]), +input[type=text], +input[type=password], +input[type=email], +input[type=url], +input[type=time], +input[type=date], +input[type=datetime], +input[type=datetime-local], +input[type=tel], +input[type=number], +input[type=search], +textarea.materialize-textarea { + + // General Styles + background-color: transparent; + border: none; + border-bottom: $input-border; + border-radius: 0; + outline: none; + height: $input-height; + width: 100%; + font-size: $input-font-size; + margin: $input-margin; + padding: $input-padding; + box-shadow: none; + box-sizing: content-box; + transition: $input-transition; + + // Disabled input style + &:disabled, + &[readonly="readonly"] { + color: $input-disabled-color; + border-bottom: $input-disabled-border; + } + + // Disabled label style + &:disabled+label, + &[readonly="readonly"]+label { + color: $input-disabled-color; + } + + // Focused input style + &:focus:not([readonly]) { + border-bottom: 1px solid $input-focus-color; + box-shadow: 0 1px 0 0 $input-focus-color; + } + + // Focused label style + &:focus:not([readonly])+label { + color: $input-focus-color; + } + + // Valid Input Style + &.valid, + &:focus.valid { + border-bottom: 1px solid $input-success-color; + box-shadow: 0 1px 0 0 $input-success-color; + } + + // Custom Success Message + &.valid + label:after, + &:focus.valid + label:after { + content: attr(data-success); + color: $input-success-color; + opacity: 1; + } + + // Invalid Input Style + &.invalid, + &:focus.invalid { + border-bottom: $input-invalid-border; + box-shadow: 0 1px 0 0 $input-error-color; + } + + // Custom Error message + &.invalid + label:after, + &:focus.invalid + label:after { + content: attr(data-error); + color: $input-error-color; + opacity: 1; + } + + // Full width label when using validate for error messages + &.validate + label { + width: 100%; + pointer-events: none; + } + + // Form Message Shared Styles + & + label:after { + display: block; + content: ""; + position: absolute; + top: 60px; + opacity: 0; + transition: .2s opacity ease-out, .2s color ease-out; + } +} + +// Styling for input field wrapper +.input-field { + // Inline styles + &.inline { + display: inline-block; + vertical-align: middle; + margin-left: 5px; + + input, + .select-dropdown { + margin-bottom: 1rem; + } + } + + // Gutter spacing + &.col { + label { + left: $gutter-width / 2; + } + + .prefix ~ label, + .prefix ~ .validate ~ label { + width: calc(100% - 3rem - #{$gutter-width}); + } + } + + position: relative; + margin-top: 1rem; + + label { + color: $input-border-color; + position: absolute; + top: 0.8rem; + left: 0; + font-size: 1rem; + cursor: text; + transition: .2s ease-out; + } + + label.active { + font-size: $label-font-size; + transform: translateY(-140%); + } + + // Prefix Icons + .prefix { + position: absolute; + width: $input-height; + font-size: 2rem; + transition: color .2s; + + &.active { color: $input-focus-color; } + } + + .prefix ~ input, + .prefix ~ textarea, + .prefix ~ label, + .prefix ~ .validate ~ label, + .prefix ~ .autocomplete-content { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); + } + + .prefix ~ label { margin-left: 3rem; } + + @media #{$medium-and-down} { + .prefix ~ input { + width: 86%; + width: calc(100% - 3rem); + } + } + + @media #{$small-and-down} { + .prefix ~ input { + width: 80%; + width: calc(100% - 3rem); + } + } +} + + +/* Search Field */ + +.input-field input[type=search] { + display: block; + line-height: inherit; + padding-left: 4rem; + width: calc(100% - 4rem); + + &:focus { + background-color: $input-background; + border: 0; + box-shadow: none; + color: #444; + + & + label i, + & ~ .mdi-navigation-close, + & ~ .material-icons { + color: #444; + } + } + + & + label { + left: 1rem; + } + + & ~ .mdi-navigation-close, + & ~ .material-icons { + position: absolute; + top: 0; + right: 1rem; + color: transparent; + cursor: pointer; + font-size: 2rem; + transition: .3s color; + } +} + + +/* Textarea */ + +// Default textarea +textarea { + width: 100%; + height: $input-height; + background-color: transparent; + + &.materialize-textarea { + overflow-y: hidden; /* prevents scroll bar flash */ + padding: .8rem 0 1.6rem 0; /* prevents text jump on Enter keypress */ + resize: none; + min-height: $input-height; + } +} + +// For textarea autoresize +.hiddendiv { + display: none; + white-space: pre-wrap; + word-wrap: break-word; + overflow-wrap: break-word; /* future version of deprecated 'word-wrap' */ + padding-top: 1.2rem; /* prevents text jump on Enter keypress */ +} + + +/* Autocomplete */ +.autocomplete-content { + margin-top: -15px; + display: block; + opacity: 1; + position: static; + + li { + .highlight { color: #444; } + + img { + height: $dropdown-item-height - 10; + width: $dropdown-item-height - 10; + margin: 5px 15px; + } + } +} diff --git a/assets/libs/materialize/sass/components/forms/_radio-buttons.scss b/assets/libs/materialize/sass/components/forms/_radio-buttons.scss new file mode 100644 index 0000000..b59dbfb --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_radio-buttons.scss @@ -0,0 +1,117 @@ +/* Radio Buttons + ========================================================================== */ + +// Remove default Radio Buttons +[type="radio"]:not(:checked), +[type="radio"]:checked { + position: absolute; + left: -9999px; + opacity: 0; +} + +[type="radio"]:not(:checked) + label, +[type="radio"]:checked + label { + position: relative; + padding-left: 35px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 1rem; + transition: .28s ease; + + -khtml-user-select: none; /* webkit (konqueror) browsers */ + user-select: none; +} + +[type="radio"] + label:before, +[type="radio"] + label:after { + content: ''; + position: absolute; + left: 0; + top: 0; + margin: 4px; + width: 16px; + height: 16px; + z-index: 0; + transition: .28s ease; +} + +/* Unchecked styles */ +[type="radio"]:not(:checked) + label:before, +[type="radio"]:not(:checked) + label:after, +[type="radio"]:checked + label:before, +[type="radio"]:checked + label:after, +[type="radio"].with-gap:checked + label:before, +[type="radio"].with-gap:checked + label:after { + border-radius: 50%; +} + +[type="radio"]:not(:checked) + label:before, +[type="radio"]:not(:checked) + label:after { + border: 2px solid $radio-empty-color; +} + +[type="radio"]:not(:checked) + label:after { + transform: scale(0); +} + +/* Checked styles */ +[type="radio"]:checked + label:before { + border: 2px solid transparent; +} + +[type="radio"]:checked + label:after, +[type="radio"].with-gap:checked + label:before, +[type="radio"].with-gap:checked + label:after { + border: $radio-border; +} + +[type="radio"]:checked + label:after, +[type="radio"].with-gap:checked + label:after { + background-color: $radio-fill-color; +} + +[type="radio"]:checked + label:after { + transform: scale(1.02); +} + +/* Radio With gap */ +[type="radio"].with-gap:checked + label:after { + transform: scale(.5); +} + +/* Focused styles */ +[type="radio"].tabbed:focus + label:before { + box-shadow: 0 0 0 10px rgba(0,0,0,.1); +} + +/* Disabled Radio With gap */ +[type="radio"].with-gap:disabled:checked + label:before { + border: 2px solid $input-disabled-color; +} + +[type="radio"].with-gap:disabled:checked + label:after { + border: none; + background-color: $input-disabled-color; +} + +/* Disabled style */ +[type="radio"]:disabled:not(:checked) + label:before, +[type="radio"]:disabled:checked + label:before { + background-color: transparent; + border-color: $input-disabled-color; +} + +[type="radio"]:disabled + label { + color: $input-disabled-color; +} + +[type="radio"]:disabled:not(:checked) + label:before { + border-color: $input-disabled-color; +} + +[type="radio"]:disabled:checked + label:after { + background-color: $input-disabled-color; + border-color: $input-disabled-solid-color; +} diff --git a/assets/libs/materialize/sass/components/forms/_range.scss b/assets/libs/materialize/sass/components/forms/_range.scss new file mode 100644 index 0000000..7947375 --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_range.scss @@ -0,0 +1,159 @@ +/* Range + ========================================================================== */ + +.range-field { + position: relative; +} + +input[type=range], +input[type=range] + .thumb { + @extend .no-select; + cursor: pointer; +} + +input[type=range] { + position: relative; + background-color: transparent; + border: none; + outline: none; + width: 100%; + margin: 15px 0; + padding: 0; + + &:focus { + outline: none; + } +} + +input[type=range] + .thumb { + position: absolute; + border: none; + height: 0; + width: 0; + border-radius: 50%; + background-color: $radio-fill-color; + top: 10px; + margin-left: -6px; + + transform-origin: 50% 50%; + transform: rotate(-45deg); + + .value { + display: block; + width: 30px; + text-align: center; + color: $radio-fill-color; + font-size: 0; + transform: rotate(45deg); + } + + &.active { + border-radius: 50% 50% 50% 0; + + .value { + color: $input-background; + margin-left: -1px; + margin-top: 8px; + font-size: 10px; + } + } +} + +// WebKit +input[type=range] { + -webkit-appearance: none; +} + +input[type=range]::-webkit-slider-runnable-track { + height: $track-height; + background: #c2c0c2; + border: none; +} + +input[type=range]::-webkit-slider-thumb { + -webkit-appearance: none; + border: none; + height: $range-height; + width: $range-width; + border-radius: 50%; + background-color: $radio-fill-color; + transform-origin: 50% 50%; + margin: -5px 0 0 0; + transition: .3s; +} + +input[type=range]:focus::-webkit-slider-runnable-track { + background: #ccc; +} + +// FireFox +input[type=range] { + /* fix for FF unable to apply focus style bug */ + border: 1px solid white; + + /*required for proper track sizing in FF*/ +} + +input[type=range]::-moz-range-track { + height: $track-height; + background: #ddd; + border: none; +} + +input[type=range]::-moz-range-thumb { + border: none; + height: $range-height; + width: $range-width; + border-radius: 50%; + background: $radio-fill-color; + margin-top: -5px; +} + +// hide the outline behind the border +input[type=range]:-moz-focusring { + outline: 1px solid #fff; + outline-offset: -1px; +} + +input[type=range]:focus::-moz-range-track { + background: #ccc; +} + +// IE 10+ +input[type=range]::-ms-track { + height: $track-height; + + // remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead + background: transparent; + + // leave room for the larger thumb to overflow with a transparent border */ + border-color: transparent; + border-width: 6px 0; + + /*remove default tick marks*/ + color: transparent; +} + +input[type=range]::-ms-fill-lower { + background: #777; +} + +input[type=range]::-ms-fill-upper { + background: #ddd; +} + +input[type=range]::-ms-thumb { + border: none; + height: $range-height; + width: $range-width; + border-radius: 50%; + background: $radio-fill-color; +} + +input[type=range]:focus::-ms-fill-lower { + background: #888; +} + +input[type=range]:focus::-ms-fill-upper { + background: #ccc; +} diff --git a/assets/libs/materialize/sass/components/forms/_select.scss b/assets/libs/materialize/sass/components/forms/_select.scss new file mode 100644 index 0000000..687d497 --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_select.scss @@ -0,0 +1,121 @@ +/* Select Field + ========================================================================== */ + +select { display: none; } +select.browser-default { display: block; } + +select { + background-color: $select-background; + width: 100%; + padding: $select-padding; + border: $select-border; + border-radius: $select-radius; + height: $input-height; +} + +.select-label { + position: absolute; +} + +.select-wrapper { + position: relative; + + input.select-dropdown { + position: relative; + cursor: pointer; + background-color: transparent; + border: none; + border-bottom: $input-border; + outline: none; + height: $input-height; + line-height: $input-height; + width: 100%; + font-size: $input-font-size; + margin: $input-margin; + padding: 0; + display: block; + } + + span.caret { + color: initial; + position: absolute; + right: 0; + top: 0; + bottom: 0; + height: 10px; + margin: auto 0; + font-size: 10px; + line-height: 10px; + + &.disabled { + color: $input-disabled-color; + } + } + + & + label { + position: absolute; + top: -14px; + font-size: $label-font-size; + } +} + +// Disabled styles +select:disabled { + color: rgba(0,0,0,.3); +} + +.select-wrapper input.select-dropdown:disabled { + color: rgba(0,0,0,.3); + cursor: default; + -webkit-user-select: none; /* webkit (safari, chrome) browsers */ + -moz-user-select: none; /* mozilla browsers */ + -ms-user-select: none; /* IE10+ */ + border-bottom: 1px solid rgba(0,0,0,.3); +} + +.select-wrapper i { + color: $select-disabled-color; +} + +.select-dropdown li.disabled, +.select-dropdown li.disabled > span, +.select-dropdown li.optgroup { + color: $select-disabled-color; + background-color: transparent; +} + +// Prefix Icons +.prefix ~ .select-wrapper { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); +} + +.prefix ~ label { margin-left: 3rem; } + +// Icons +.select-dropdown li { + img { + height: $dropdown-item-height - 10; + width: $dropdown-item-height - 10; + margin: 5px 15px; + float: right; + } +} + +// Optgroup styles +.select-dropdown li.optgroup { + border-top: 1px solid $dropdown-hover-bg-color; + + &.selected > span { + color: rgba(0, 0, 0, .7); + } + + & > span { + color: rgba(0, 0, 0, .4); + } + + & ~ li.optgroup-option { + padding-left: 1rem; + } +} diff --git a/assets/libs/materialize/sass/components/forms/_switches.scss b/assets/libs/materialize/sass/components/forms/_switches.scss new file mode 100644 index 0000000..2c6655a --- /dev/null +++ b/assets/libs/materialize/sass/components/forms/_switches.scss @@ -0,0 +1,78 @@ +/* Switch + ========================================================================== */ + +.switch, +.switch * { + -webkit-user-select: none; + -moz-user-select: none; + -khtml-user-select: none; + -ms-user-select: none; +} + +.switch label { + cursor: pointer; +} + +.switch label input[type=checkbox] { + opacity: 0; + width: 0; + height: 0; + + &:checked + .lever { + background-color: $switch-checked-lever-bg; + + &:after { + background-color: $switch-bg-color; + left: 24px; + } + } +} + +.switch label .lever { + content: ""; + display: inline-block; + position: relative; + width: 40px; + height: 15px; + background-color: $switch-unchecked-lever-bg; + border-radius: $switch-radius; + margin-right: 10px; + transition: background 0.3s ease; + vertical-align: middle; + margin: 0 16px; + + &:after { + content: ""; + position: absolute; + display: inline-block; + width: 21px; + height: 21px; + background-color: $switch-unchecked-bg; + border-radius: 21px; + box-shadow: 0 1px 3px 1px rgba(0,0,0,.4); + left: -5px; + top: -3px; + transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease; + } +} + +// Switch active style +input[type=checkbox]:checked:not(:disabled) ~ .lever:active::after, +input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::after { + box-shadow: 0 1px 3px 1px rgba(0,0,0,.4), 0 0 0 15px transparentize($switch-bg-color, .9); +} + +input[type=checkbox]:not(:disabled) ~ .lever:active:after, +input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::after { + box-shadow: 0 1px 3px 1px rgba(0,0,0,.4), 0 0 0 15px rgba(0, 0, 0, .08); +} + +// Disabled Styles +.switch input[type=checkbox][disabled] + .lever { + cursor: default; +} + +.switch label input[type=checkbox][disabled] + .lever:after, +.switch label input[type=checkbox][disabled]:checked + .lever:after { + background-color: $input-disabled-solid-color; +} diff --git a/assets/libs/materialize/sass/materialize.scss b/assets/libs/materialize/sass/materialize.scss new file mode 100644 index 0000000..2bc0473 --- /dev/null +++ b/assets/libs/materialize/sass/materialize.scss @@ -0,0 +1,40 @@ +@charset "UTF-8"; + +// Mixins +// @import "components/prefixer"; +@import "components/mixins"; +@import "components/color"; + +// Variables; +@import "components/variables"; + +// Reset +@import "components/normalize"; + +// components +@import "components/global"; +@import "components/icons-material-design"; +@import "components/grid"; +@import "components/navbar"; +@import "components/roboto"; +@import "components/typography"; +@import "components/cards"; +@import "components/toast"; +@import "components/tabs"; +@import "components/tooltip"; +@import "components/buttons"; +@import "components/dropdown"; +@import "components/waves"; +@import "components/modal"; +@import "components/collapsible"; +@import "components/chips"; +@import "components/materialbox"; +@import "components/forms/forms"; +@import "components/table_of_contents"; +@import "components/sideNav"; +@import "components/preloader"; +@import "components/slider"; +@import "components/carousel"; +@import "components/date_picker/default"; +@import "components/date_picker/default.date"; +@import "components/date_picker/default.time"; diff --git a/assets/styl/main.styl b/assets/styl/main.styl new file mode 100644 index 0000000..f835eb3 --- /dev/null +++ b/assets/styl/main.styl @@ -0,0 +1,16 @@ +// Fonts + +// Variables +red = #FD7B7B +yellow = #FDDF7B +green = #7AE076 +teal = #67E6A7 +blue = #4BA8F8 +lightgray = #F0F0F0 +lightergray = #F5F5F5 + +// Imports +@import 'reset' +@import 'mixins' + +@import '../../app/**/*.styl' diff --git a/assets/styl/mixins.styl b/assets/styl/mixins.styl new file mode 100644 index 0000000..a097045 --- /dev/null +++ b/assets/styl/mixins.styl @@ -0,0 +1,21 @@ +// Properties +my-box-shadow() + box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) + +// Responsive +below($width) + $width = $width - 1 + media = 'all and (max-width: %s)' % $width + @media media + {block} + +above($width) + media = 'all and (min-width: %s)' % $width + @media media + {block} + +between($min-width, $max-width) + $max-width = $max-width - 1 + media = 'all and (min-width: %s) and (max-width: %s)' % ($min-width $max-width) + @media media + {block} diff --git a/assets/styl/reset.styl b/assets/styl/reset.styl new file mode 100644 index 0000000..1b9926f --- /dev/null +++ b/assets/styl/reset.styl @@ -0,0 +1,28 @@ +// Normal Resets +a + cursor: pointer + +.show + display: block !important + +::-webkit-scrollbar + display: none + + +// Angular Resets +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +// Materialize Resets +.input-field .prefix ~ input, .input-field .prefix ~ textarea, .input-field .prefix ~ label, .input-field .prefix ~ .validate ~ label, .input-field .prefix ~ .autocomplete-content + margin-left: 0 + width: 100% + position: absolute + +ul.tabs + background: none + .tab a + color: inherit + &:hover + color: inherit diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..840bb8c --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,76 @@ +// Requires +////////////////////////////// +var gulp = require('gulp'), + stylus = require('gulp-stylus'), + autoprefixer = require('autoprefixer-stylus'), + concat = require('gulp-concat'), + kit = require('gulp-kit'), + plumber = require('gulp-plumber'), + notify = require('gulp-notify'), + browserSync = require('browser-sync'), + reload = browserSync.reload; + + + +// Styles +////////////////////////////// +gulp.task('styles', function () { +gulp.src('assets/styl/main.styl') + .pipe(plumber({errorHandler: notify.onError({ + title: 'Stylus Error', + message: '<%= error.message %>'})})) + .pipe(stylus({ use: [autoprefixer('> 5% in US')] })) + .pipe(gulp.dest('assets/css')) + .pipe(reload({stream:true})); +}); + +// Scripts +////////////////////////////// +gulp.task('scripts', function () { +gulp.src(['app/app.js', 'app/**/!(app).js']) + .pipe(concat('bundle.js')) + .pipe(gulp.dest('assets/js')) + .pipe(reload({stream:true})); +}); + +// Kit +////////////////////////////// +gulp.task('kit', function () { +gulp.src('app/root/index.kit') + .pipe(plumber({errorHandler: notify.onError({ + title: 'Kit Error', + message: '<%= error.message %>'})})) + .pipe(kit()) + .pipe(gulp.dest('')) + .pipe(reload({stream:true})); +}); + +// HTML Live Reload +////////////////////////////// +gulp.task('html-reload', function () { +gulp.src(['app/**/*.html']) + .pipe(reload({stream:true})); +}); + + + +// Browser Sync +////////////////////////////// +gulp.task('browser-sync', function () { + browserSync({ + server:{ baseDir: './' } + }) +}); + +// Watch +////////////////////////////// +gulp.task('watch', function () { + gulp.watch(['app/**/*.styl', 'assets/styl/**/*.styl', 'app/root/*.styl'], ['styles']); + gulp.watch('app/**/*.js', ['scripts']); + gulp.watch('app/**/*.kit', ['kit']); + gulp.watch('app/**/*.html', ['html-reload']); +}); + +// Default +////////////////////////////// +gulp.task('default', ['styles', 'scripts', 'kit', 'browser-sync', 'watch']); diff --git a/index.html b/index.html new file mode 100644 index 0000000..bc643e1 --- /dev/null +++ b/index.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..2082e31 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "angular-spa", + "version": "1.0.0", + "description": "Gabe's Angular SPA Boilerplate", + "main": "app/app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Gabe Rogan", + "license": "ISC", + "devDependencies": { + "autoprefixer-stylus": "^0.11.0", + "browser-sync": "^2.17.6", + "gulp": "^3.9.1", + "gulp-concat": "^2.6.1", + "gulp-kit": "^0.3.0", + "gulp-notify": "^2.2.0", + "gulp-plumber": "^1.1.0", + "gulp-stylus": "^2.6.0" + } +} diff --git a/pseudo-app.md b/pseudo-app.md new file mode 100644 index 0000000..f0eca8a --- /dev/null +++ b/pseudo-app.md @@ -0,0 +1,133 @@ +