diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..91ba58f --- /dev/null +++ b/.env.example @@ -0,0 +1,34 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_LOG_LEVEL=debug +APP_URL=http://localhost + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=homestead +DB_USERNAME=homestead +DB_PASSWORD=secret + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +SESSION_DRIVER=file +SESSION_LIFETIME=120 +QUEUE_DRIVER=sync + +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_DRIVER=smtp +MAIL_HOST=smtp.mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null + +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..967315d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto +*.css linguist-vendored +*.scss linguist-vendored +*.js linguist-vendored +CHANGELOG.md export-ignore diff --git a/.gitignore b/.gitignore index a4854be..ec2dd0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,13 @@ -vendor/ -node_modules/ +.DS_Store +/node_modules +/public/hot +/public/storage +/storage/*.key +/vendor +/.idea +/.vagrant +Homestead.json +Homestead.yaml npm-debug.log - -# Laravel 4 specific -bootstrap/compiled.php -app/storage/ - -# Laravel 5 & Lumen specific -public/storage -public/hot -storage/*.key -.env.*.php -.env.php +yarn-error.log .env -Homestead.yaml -Homestead.json - -# Rocketeer PHP task runner and deployment package. https://github.com/rocketeers/rocketeer -.rocketeer/ diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php new file mode 100644 index 0000000..a8c5158 --- /dev/null +++ b/app/Console/Kernel.php @@ -0,0 +1,42 @@ +command('inspire') + // ->hourly(); + } + + /** + * Register the commands for the application. + * + * @return void + */ + protected function commands() + { + $this->load(__DIR__.'/Commands'); + + require base_path('routes/console.php'); + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php new file mode 100644 index 0000000..7e2563a --- /dev/null +++ b/app/Exceptions/Handler.php @@ -0,0 +1,53 @@ +middleware('guest'); + } +} diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php new file mode 100644 index 0000000..b2ea669 --- /dev/null +++ b/app/Http/Controllers/Auth/LoginController.php @@ -0,0 +1,39 @@ +middleware('guest')->except('logout'); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php new file mode 100644 index 0000000..f77265a --- /dev/null +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -0,0 +1,71 @@ +middleware('guest'); + } + + /** + * Get a validator for an incoming registration request. + * + * @param array $data + * @return \Illuminate\Contracts\Validation\Validator + */ + protected function validator(array $data) + { + return Validator::make($data, [ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:6|confirmed', + ]); + } + + /** + * Create a new user instance after a valid registration. + * + * @param array $data + * @return \App\User + */ + protected function create(array $data) + { + return User::create([ + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => bcrypt($data['password']), + ]); + } +} diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php new file mode 100644 index 0000000..cf726ee --- /dev/null +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -0,0 +1,39 @@ +middleware('guest'); + } +} diff --git a/app/Http/Controllers/CommentsController.php b/app/Http/Controllers/CommentsController.php new file mode 100644 index 0000000..11cea7d --- /dev/null +++ b/app/Http/Controllers/CommentsController.php @@ -0,0 +1,15 @@ +all()); + return back(); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..03e02a2 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,13 @@ +paginate(5); + return view('issues.index')->with('issues', $issues); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + return view('issues.create'); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + Issue::create($request->all()); + return redirect('/'); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + $issue = Issue::find($id); + //当前issue的comments + $comments = $issue->comments; + return view('issues.show', compact('issue', 'comments')); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + $issue = Issue::find($id); + return view('issues.edit')->with('issue', $issue); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $issue = Issue::find($id); + $issue->update($request->all()); + return redirect(route('issues.show', $id)); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + Issue::destroy($id); + return redirect('/'); + } +} diff --git a/app/Http/Controllers/WelcomeController.php b/app/Http/Controllers/WelcomeController.php new file mode 100644 index 0000000..3e1fc46 --- /dev/null +++ b/app/Http/Controllers/WelcomeController.php @@ -0,0 +1,20 @@ +take(2)->get(); + return view('welcome.index')->with('issues', $issues); + } + + public function about() + { + return view('welcome.about'); + } +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php new file mode 100644 index 0000000..93bf68b --- /dev/null +++ b/app/Http/Kernel.php @@ -0,0 +1,61 @@ + [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + // \Illuminate\Session\Middleware\AuthenticateSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \App\Http\Middleware\VerifyCsrfToken::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + + 'api' => [ + 'throttle:60,1', + 'bindings', + ], + ]; + + /** + * The application's route middleware. + * + * These middleware may be assigned to groups or used individually. + * + * @var array + */ + protected $routeMiddleware = [ + 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + ]; +} diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php new file mode 100644 index 0000000..033136a --- /dev/null +++ b/app/Http/Middleware/EncryptCookies.php @@ -0,0 +1,17 @@ +check()) { + return redirect('/home'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/TrimStrings.php b/app/Http/Middleware/TrimStrings.php new file mode 100644 index 0000000..5a50e7b --- /dev/null +++ b/app/Http/Middleware/TrimStrings.php @@ -0,0 +1,18 @@ + 'FORWARDED', + Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', + Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', + Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', + Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', + ]; +} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php new file mode 100644 index 0000000..0c13b85 --- /dev/null +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -0,0 +1,17 @@ +belongsTo('App\Models\Issue'); + } + + public function avatar() + { + return "https://www.gravatar.com/avatar/" . md5(strtolower($this->email)) . "?d=retro&s=48"; + } +} diff --git a/app/Models/Issue.php b/app/Models/Issue.php new file mode 100644 index 0000000..d4dd023 --- /dev/null +++ b/app/Models/Issue.php @@ -0,0 +1,15 @@ +hasMany('App\Models\Comment'); + } +} \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..35471f6 --- /dev/null +++ b/app/Providers/AppServiceProvider.php @@ -0,0 +1,28 @@ + 'App\Policies\ModelPolicy', + ]; + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + // + } +} diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php new file mode 100644 index 0000000..352cce4 --- /dev/null +++ b/app/Providers/BroadcastServiceProvider.php @@ -0,0 +1,21 @@ + [ + 'App\Listeners\EventListener', + ], + ]; + + /** + * Register any events for your application. + * + * @return void + */ + public function boot() + { + parent::boot(); + + // + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..5ea48d3 --- /dev/null +++ b/app/Providers/RouteServiceProvider.php @@ -0,0 +1,73 @@ +mapApiRoutes(); + + $this->mapWebRoutes(); + + // + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + * + * @return void + */ + protected function mapWebRoutes() + { + Route::middleware('web') + ->namespace($this->namespace) + ->group(base_path('routes/web.php')); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + * + * @return void + */ + protected function mapApiRoutes() + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->namespace) + ->group(base_path('routes/api.php')); + } +} diff --git a/app/User.php b/app/User.php new file mode 100644 index 0000000..bfd96a6 --- /dev/null +++ b/app/User.php @@ -0,0 +1,29 @@ +make(Illuminate\Contracts\Console\Kernel::class); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); + +/* +|-------------------------------------------------------------------------- +| Shutdown The Application +|-------------------------------------------------------------------------- +| +| Once Artisan has finished running, we will fire off the shutdown events +| so that any final work may be done by the application before we shut +| down the process. This is the last thing to happen to the request. +| +*/ + +$kernel->terminate($input, $status); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..f2801ad --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,55 @@ +singleton( + Illuminate\Contracts\Http\Kernel::class, + App\Http\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Console\Kernel::class, + App\Console\Kernel::class +); + +$app->singleton( + Illuminate\Contracts\Debug\ExceptionHandler::class, + App\Exceptions\Handler::class +); + +/* +|-------------------------------------------------------------------------- +| Return The Application +|-------------------------------------------------------------------------- +| +| This script returns the application instance. The instance is given to +| the calling script so we can separate the building of the instances +| from the actual running of the application and sending responses. +| +*/ + +return $app; diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..dcb4cd3 --- /dev/null +++ b/composer.json @@ -0,0 +1,56 @@ +{ + "name": "laravel/laravel", + "description": "The Laravel Framework.", + "keywords": ["framework", "laravel"], + "license": "MIT", + "type": "project", + "require": { + "php": ">=7.0.0", + "fideloper/proxy": "~3.3", + "laravel/framework": "5.5.*", + "laravel/tinker": "~1.0" + }, + "require-dev": { + "filp/whoops": "~2.0", + "fzaninotto/faker": "~1.4", + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~6.0" + }, + "autoload": { + "classmap": [ + "database/seeds", + "database/factories" + ], + "psr-4": { + "App\\": "app/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "extra": { + "laravel": { + "dont-discover": [ + ] + } + }, + "scripts": { + "post-root-package-install": [ + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + ], + "post-create-project-cmd": [ + "@php artisan key:generate" + ], + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover" + ] + }, + "config": { + "preferred-install": "dist", + "sort-packages": true, + "optimize-autoloader": true + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..da869d1 --- /dev/null +++ b/composer.lock @@ -0,0 +1,3848 @@ +{ + "_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": "5eba86da256ddeb8084c32d3d10e18d3", + "packages": [ + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24T07:27:01+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2017-07-22T12:18:28+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "egulias/email-validator", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">= 5.5" + }, + "require-dev": { + "dominicsayers/isemail": "dev-master", + "phpunit/phpunit": "^4.8.35", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "time": "2017-11-15T23:40:40+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.6.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/fbe3fe878f4fe69048bb8a52783a09802004f548", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "time": "2017-11-14T20:44:03+00:00" + }, + { + "name": "fideloper/proxy", + "version": "3.3.4", + "source": { + "type": "git", + "url": "https://github.com/fideloper/TrustedProxy.git", + "reference": "9cdf6f118af58d89764249bbcc7bb260c132924f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/9cdf6f118af58d89764249bbcc7bb260c132924f", + "reference": "9cdf6f118af58d89764249bbcc7bb260c132924f", + "shasum": "" + }, + "require": { + "illuminate/contracts": "~5.0", + "php": ">=5.4.0" + }, + "require-dev": { + "illuminate/http": "~5.0", + "mockery/mockery": "~0.9.3", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + }, + "laravel": { + "providers": [ + "Fideloper\\Proxy\\TrustedProxyServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Fideloper\\Proxy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Fidao", + "email": "fideloper@gmail.com" + } + ], + "description": "Set trusted proxies for Laravel", + "keywords": [ + "load balancing", + "proxy", + "trusted proxy" + ], + "time": "2017-06-15T17:19:42+00:00" + }, + { + "name": "jakub-onderka/php-console-color", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleColor": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com", + "homepage": "http://www.acci.cz" + } + ], + "time": "2014-04-08T15:00:19+00:00" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.3.2", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", + "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", + "shasum": "" + }, + "require": { + "jakub-onderka/php-console-color": "~0.1", + "php": ">=5.3.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~0.5", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleHighlighter": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "time": "2015-04-20T18:58:01+00:00" + }, + { + "name": "laravel/framework", + "version": "v5.5.22", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "2404af887ca8272d721628a99bbc721ac3b692e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/2404af887ca8272d721628a99bbc721ac3b692e7", + "reference": "2404af887ca8272d721628a99bbc721ac3b692e7", + "shasum": "" + }, + "require": { + "doctrine/inflector": "~1.1", + "erusev/parsedown": "~1.6", + "ext-mbstring": "*", + "ext-openssl": "*", + "league/flysystem": "~1.0", + "monolog/monolog": "~1.12", + "mtdowling/cron-expression": "~1.0", + "nesbot/carbon": "~1.20", + "php": ">=7.0", + "psr/container": "~1.0", + "psr/simple-cache": "^1.0", + "ramsey/uuid": "~3.0", + "swiftmailer/swiftmailer": "~6.0", + "symfony/console": "~3.3", + "symfony/debug": "~3.3", + "symfony/finder": "~3.3", + "symfony/http-foundation": "~3.3", + "symfony/http-kernel": "~3.3", + "symfony/process": "~3.3", + "symfony/routing": "~3.3", + "symfony/var-dumper": "~3.3", + "tijsverkoyen/css-to-inline-styles": "~2.2", + "vlucas/phpdotenv": "~2.2" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "tightenco/collect": "self.version" + }, + "require-dev": { + "aws/aws-sdk-php": "~3.0", + "doctrine/dbal": "~2.5", + "filp/whoops": "^2.1.4", + "mockery/mockery": "~1.0", + "orchestra/testbench-core": "3.5.*", + "pda/pheanstalk": "~3.0", + "phpunit/phpunit": "~6.0", + "predis/predis": "^1.1.1", + "symfony/css-selector": "~3.3", + "symfony/dom-crawler": "~3.3" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.5).", + "ext-pcntl": "Required to use all features of the queue worker.", + "ext-posix": "Required to use all features of the queue worker.", + "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).", + "laravel/tinker": "Required to use the tinker console command (~1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", + "nexmo/client": "Required to use the Nexmo transport (~1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", + "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.3).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.3).", + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.5-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "time": "2017-11-27T15:29:55+00:00" + }, + { + "name": "laravel/tinker", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "203978fd67f118902acff95925847e70b72e3daf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/203978fd67f118902acff95925847e70b72e3daf", + "reference": "203978fd67f118902acff95925847e70b72e3daf", + "shasum": "" + }, + "require": { + "illuminate/console": "~5.1", + "illuminate/contracts": "~5.1", + "illuminate/support": "~5.1", + "php": ">=5.5.9", + "psy/psysh": "0.7.*|0.8.*", + "symfony/var-dumper": "~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (~5.1)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "time": "2017-07-13T13:11:05+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.41", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "f400aa98912c561ba625ea4065031b7a41e5a155" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f400aa98912c561ba625ea4065031b7a41e5a155", + "reference": "f400aa98912c561ba625ea4065031b7a41e5a155", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "ext-fileinfo": "*", + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^2.2", + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2017-08-06T17:41:04+00:00" + }, + { + "name": "monolog/monolog", + "version": "1.23.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "^5.3|^6.0" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2017-06-19T01:22:40+00:00" + }, + { + "name": "mtdowling/cron-expression", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/mtdowling/cron-expression.git", + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad", + "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2017-01-23T04:29:33+00:00" + }, + { + "name": "nesbot/carbon", + "version": "1.22.1", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc", + "reference": "7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "symfony/translation": "~2.6 || ~3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~4.0 || ~5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.23-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2017-01-16T07:55:07+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08131e7ff29de6bb9f12275c7d35df71f25f4d89", + "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2017-11-04T11:48:34+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.11", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2017-09-27T21:40:39+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+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": "psr/simple-cache", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/753fa598e8f3b9966c886fe13f370baa45ef0e24", + "reference": "753fa598e8f3b9966c886fe13f370baa45ef0e24", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "time": "2017-01-02T13:31:39+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.8.15", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "b1d289c2cb03a2f8249912c53e96ced38f879926" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/b1d289c2cb03a2f8249912c53e96ced38f879926", + "reference": "b1d289c2cb03a2f8249912c53e96ced38f879926", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "jakub-onderka/php-console-highlighter": "0.3.*", + "nikic/php-parser": "~1.3|~2.0|~3.0", + "php": ">=5.3.9", + "symfony/console": "~2.3.10|^2.4.2|~3.0", + "symfony/var-dumper": "~2.7|~3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.11", + "hoa/console": "~3.16|~1.14", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "symfony/finder": "~2.1|~3.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.8.x-dev" + } + }, + "autoload": { + "files": [ + "src/Psy/functions.php" + ], + "psr-4": { + "Psy\\": "src/Psy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2017-11-16T14:29:51+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/45cffe822057a09e05f7bd09ec5fb88eeecd2334", + "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.0|^2.0", + "php": "^5.4 || ^7.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "apigen/apigen": "^4.1", + "codeception/aspect-mock": "^1.0 | ^2.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.4", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "satooshi/php-coveralls": "^0.6.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2017-09-22T20:46:04+00:00" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.0.2", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc", + "shasum": "" + }, + "require": { + "egulias/email-validator": "~2.0", + "php": ">=7.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2017-09-30T22:39:41+00:00" + }, + { + "name": "symfony/console", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "63cd7960a0a522c3537f6326706d7f3b8de65805" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/63cd7960a0a522c3537f6326706d7f3b8de65805", + "reference": "63cd7960a0a522c3537f6326706d7f3b8de65805", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.3", + "symfony/dependency-injection": "~3.3", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/filesystem": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/filesystem": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-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": "2017-11-16T15:24:32+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "66e6e046032ebdf1f562c26928549f613d428bd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/66e6e046032ebdf1f562c26928549f613d428bd1", + "reference": "66e6e046032ebdf1f562c26928549f613d428bd1", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2017-11-05T15:47:03+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "74557880e2846b5c84029faa96b834da37e29810" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/74557880e2846b5c84029faa96b834da37e29810", + "reference": "74557880e2846b5c84029faa96b834da37e29810", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "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/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-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": "2017-11-10T16:38:39+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~3.3", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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 EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2017-11-05T15:47:03+00:00" + }, + { + "name": "symfony/finder", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/138af5ec075d4b1d1bd19de08c38a34bb2d7d880", + "reference": "138af5ec075d4b1d1bd19de08c38a34bb2d7d880", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-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": "2017-11-05T15:47:03+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "5943f0f19817a7e05992d20a90729b0dc93faf36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5943f0f19817a7e05992d20a90729b0dc93faf36", + "reference": "5943f0f19817a7e05992d20a90729b0dc93faf36", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "symfony/expression-language": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "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 HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2017-11-13T18:13:16+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "a2a942172b742217ab2ccd9399494af2aa17c766" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a2a942172b742217ab2ccd9399494af2aa17c766", + "reference": "a2a942172b742217ab2ccd9399494af2aa17c766", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0", + "symfony/debug": "~2.8|~3.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/http-foundation": "^3.3.11" + }, + "conflict": { + "symfony/config": "<2.8", + "symfony/dependency-injection": "<3.3", + "symfony/var-dumper": "<3.3", + "twig/twig": "<1.34|<2.4,>=2" + }, + "require-dev": { + "psr/cache": "~1.0", + "symfony/browser-kit": "~2.8|~3.0", + "symfony/class-loader": "~2.8|~3.0", + "symfony/config": "~2.8|~3.0", + "symfony/console": "~2.8|~3.0", + "symfony/css-selector": "~2.8|~3.0", + "symfony/dependency-injection": "~3.3", + "symfony/dom-crawler": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/finder": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0", + "symfony/routing": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0", + "symfony/templating": "~2.8|~3.0", + "symfony/translation": "~2.8|~3.0", + "symfony/var-dumper": "~3.3" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "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 HttpKernel Component", + "homepage": "https://symfony.com", + "time": "2017-11-16T18:14:43+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-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": "2017-10-11T12:05:26+00:00" + }, + { + "name": "symfony/process", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d", + "reference": "a56a3989fb762d7b19a0cf8e7693ee99a6ffb78d", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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 Process Component", + "homepage": "https://symfony.com", + "time": "2017-11-13T15:31:11+00:00" + }, + { + "name": "symfony/routing", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95", + "reference": "cf7fa1dfcfee2c96969bfa1c0341e5627ecb1e95", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/config": "<2.8", + "symfony/dependency-injection": "<3.3", + "symfony/yaml": "<3.3" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~3.3", + "symfony/expression-language": "~2.8|~3.0", + "symfony/http-foundation": "~2.8|~3.0", + "symfony/yaml": "~3.3" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/dependency-injection": "For loading routes from a service", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "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 Routing Component", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2017-11-07T14:16:22+00:00" + }, + { + "name": "symfony/translation", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "373e553477e55cd08f8b86b74db766c75b987fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/373e553477e55cd08f8b86b74db766c75b987fdb", + "reference": "373e553477e55cd08f8b86b74db766c75b987fdb", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8", + "symfony/yaml": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/intl": "^2.8.18|^3.2.5", + "symfony/yaml": "~3.3" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-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": "2017-11-07T14:12:55+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v3.3.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "805de6bd6869073e60610df1b14ab7d969c61b01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/805de6bd6869073e60610df1b14ab7d969c61b01", + "reference": "805de6bd6869073e60610df1b14ab7d969c61b01", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, + "require-dev": { + "ext-iconv": "*", + "twig/twig": "~1.34|~2.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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 mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2017-11-07T14:16:22+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b", + "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7", + "symfony/css-selector": "^2.7|~3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|5.1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "time": "2016-09-20T12:50:39+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause-Attribution" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2016-09-01T10:05:43+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "filp/whoops", + "version": "2.1.14", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/c6081b8838686aa04f1e83ba7e91f78b7b2a23e6", + "reference": "c6081b8838686aa04f1e83ba7e91f78b7b2a23e6", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "symfony/var-dumper": "^2.6 || ^3.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "time": "2017-11-23T18:22:44+00:00" + }, + { + "name": "fzaninotto/faker", + "version": "v1.7.1", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "reference": "d3ed4cc37051c1ca52d22d76b437d14809fc7e0d", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "squizlabs/php_codesniffer": "^1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2017-08-15T16:48:10+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2016-01-20T08:20:44+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1bac8c362b12f522fdd1f1fa3556284c91affa38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1bac8c362b12f522fdd1f1fa3556284c91affa38", + "reference": "1bac8c362b12f522fdd1f1fa3556284c91affa38", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~2.0", + "lib-pcre": ">=7.0", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "~5.7|~6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2017-10-06T16:20:43+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2", + "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-08-30T18:51:59+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2017-11-24T13:59:53+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "033ec97498cf530cc1be4199264cad568b19be26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/033ec97498cf530cc1be4199264cad568b19be26", + "reference": "033ec97498cf530cc1be4199264cad568b19be26", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^2.0.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "ext-xdebug": "^2.5", + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-11-27T09:00:30+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "791198a2c6254db10131eecfe8c06670700904db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-11-27T05:48:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "6.4.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/562f7dc75d46510a4ed5d16189ae57fbe45a9932", + "reference": "562f7dc75d46510a4ed5d16189ae57fbe45a9932", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.2.2", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^4.0.3", + "sebastian/comparator": "^2.0.2", + "sebastian/diff": "^2.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-11-08T11:26:09+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "2f789b59ab89669015ad984afa350c4ec577ade0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0", + "reference": "2f789b59ab89669015ad984afa350c4ec577ade0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.0" + }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2017-08-03T14:08:16+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1174d9018191e93cb9d719edec01257fc05f8158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158", + "reference": "1174d9018191e93cb9d719edec01257fc05f8158", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^2.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-11-03T07:16:52+00:00" + }, + { + "name": "sebastian/diff", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-08-03T08:09:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-11-23T20:04:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.0.0" + }, + "platform-dev": [] +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..0e4ebed --- /dev/null +++ b/config/app.php @@ -0,0 +1,231 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services your application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Application Fallback Locale + |-------------------------------------------------------------------------- + | + | The fallback locale determines the locale to use when the current one + | is not available. You may change the value to correspond to any of + | the language folders that are provided through your application. + | + */ + + 'fallback_locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => env('APP_KEY'), + + 'cipher' => 'AES-256-CBC', + + /* + |-------------------------------------------------------------------------- + | Logging Configuration + |-------------------------------------------------------------------------- + | + | Here you may configure the log settings for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Settings: "single", "daily", "syslog", "errorlog" + | + */ + + 'log' => env('APP_LOG', 'single'), + + 'log_level' => env('APP_LOG_LEVEL', 'debug'), + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => [ + + /* + * Laravel Framework Service Providers... + */ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + + /* + * Package Service Providers... + */ + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + App\Providers\AuthServiceProvider::class, + // App\Providers\BroadcastServiceProvider::class, + App\Providers\EventServiceProvider::class, + App\Providers\RouteServiceProvider::class, + + ], + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => [ + + 'App' => Illuminate\Support\Facades\App::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, + 'Bus' => Illuminate\Support\Facades\Bus::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Notification' => Illuminate\Support\Facades\Notification::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Redis' => Illuminate\Support\Facades\Redis::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + + ], + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..7817501 --- /dev/null +++ b/config/auth.php @@ -0,0 +1,102 @@ + [ + 'guard' => 'web', + 'passwords' => 'users', + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | here which uses session storage and the Eloquent user provider. + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | Supported: "session", "token" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + + 'api' => [ + 'driver' => 'token', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication drivers have a user provider. This defines how the + | users are actually retrieved out of your database or other storage + | mechanisms used by this application to persist your user's data. + | + | If you have multiple user tables or models you may configure multiple + | sources which represent each model / table. These sources may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => App\User::class, + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | You may specify multiple password reset configurations if you have more + | than one user table or model in the application and you want to have + | separate password reset settings based on the specific user types. + | + | The expire time is the number of minutes that the reset token should be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => 'password_resets', + 'expire' => 60, + ], + ], + +]; diff --git a/config/broadcasting.php b/config/broadcasting.php new file mode 100644 index 0000000..5eecd2b --- /dev/null +++ b/config/broadcasting.php @@ -0,0 +1,58 @@ + env('BROADCAST_DRIVER', 'null'), + + /* + |-------------------------------------------------------------------------- + | Broadcast Connections + |-------------------------------------------------------------------------- + | + | Here you may define all of the broadcast connections that will be used + | to broadcast events to other systems or over websockets. Samples of + | each available type of connection are provided inside this array. + | + */ + + 'connections' => [ + + 'pusher' => [ + 'driver' => 'pusher', + 'key' => env('PUSHER_APP_KEY'), + 'secret' => env('PUSHER_APP_SECRET'), + 'app_id' => env('PUSHER_APP_ID'), + 'options' => [ + // + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + 'log' => [ + 'driver' => 'log', + ], + + 'null' => [ + 'driver' => 'null', + ], + + ], + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..fa12e5e --- /dev/null +++ b/config/cache.php @@ -0,0 +1,94 @@ + env('CACHE_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + */ + + 'stores' => [ + + 'apc' => [ + 'driver' => 'apc', + ], + + 'array' => [ + 'driver' => 'array', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'cache', + 'connection' => null, + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => env( + 'CACHE_PREFIX', + str_slug(env('APP_NAME', 'laravel'), '_').'_cache' + ), + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..cab5d06 --- /dev/null +++ b/config/database.php @@ -0,0 +1,120 @@ + env('DB_CONNECTION', 'mysql'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'strict' => true, + 'engine' => null, + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => '', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run in the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer set of commands than a typical key-value systems + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => [ + + 'client' => 'predis', + + 'default' => [ + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => 0, + ], + + ], + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000..9568e02 --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,68 @@ + env('FILESYSTEM_DRIVER', 'local'), + + /* + |-------------------------------------------------------------------------- + | Default Cloud Filesystem Disk + |-------------------------------------------------------------------------- + | + | Many applications store files both locally and in the cloud. For this + | reason, you may specify a default "cloud" driver here. This driver + | will be bound as the Cloud disk implementation in the container. + | + */ + + 'cloud' => env('FILESYSTEM_CLOUD', 's3'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Here you may configure as many filesystem "disks" as you wish, and you + | may even configure multiple disks of the same driver. Defaults have + | been setup for each driver as an example of the required options. + | + | Supported Drivers: "local", "ftp", "s3", "rackspace" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app'), + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + ], + + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..bb92224 --- /dev/null +++ b/config/mail.php @@ -0,0 +1,123 @@ + env('MAIL_DRIVER', 'smtp'), + + /* + |-------------------------------------------------------------------------- + | SMTP Host Address + |-------------------------------------------------------------------------- + | + | Here you may provide the host address of the SMTP server used by your + | applications. A default option is provided that is compatible with + | the Mailgun mail service which will provide reliable deliveries. + | + */ + + 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), + + /* + |-------------------------------------------------------------------------- + | SMTP Host Port + |-------------------------------------------------------------------------- + | + | This is the SMTP port used by your application to deliver e-mails to + | users of the application. Like the host we have set this value to + | stay compatible with the Mailgun e-mail application by default. + | + */ + + 'port' => env('MAIL_PORT', 587), + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + + /* + |-------------------------------------------------------------------------- + | E-Mail Encryption Protocol + |-------------------------------------------------------------------------- + | + | Here you may specify the encryption protocol that should be used when + | the application send e-mail messages. A sensible default using the + | transport layer security protocol should provide great security. + | + */ + + 'encryption' => env('MAIL_ENCRYPTION', 'tls'), + + /* + |-------------------------------------------------------------------------- + | SMTP Server Username + |-------------------------------------------------------------------------- + | + | If your SMTP server requires a username for authentication, you should + | set it here. This will get used to authenticate with your server on + | connection. You may also set the "password" value below this one. + | + */ + + 'username' => env('MAIL_USERNAME'), + + 'password' => env('MAIL_PASSWORD'), + + /* + |-------------------------------------------------------------------------- + | Sendmail System Path + |-------------------------------------------------------------------------- + | + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. + | + */ + + 'sendmail' => '/usr/sbin/sendmail -bs', + + /* + |-------------------------------------------------------------------------- + | Markdown Mail Settings + |-------------------------------------------------------------------------- + | + | If you are using Markdown based email rendering, you may configure your + | theme and component paths here, allowing you to customize the design + | of the emails. Or, you may simply stick with the Laravel defaults! + | + */ + + 'markdown' => [ + 'theme' => 'default', + + 'paths' => [ + resource_path('views/vendor/mail'), + ], + ], + +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..4d83ebd --- /dev/null +++ b/config/queue.php @@ -0,0 +1,85 @@ + env('QUEUE_DRIVER', 'sync'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'retry_after' => 90, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'retry_after' => 90, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => 'your-public-key', + 'secret' => 'your-secret-key', + 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id', + 'queue' => 'your-queue-name', + 'region' => 'us-east-1', + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => 'default', + 'retry_after' => 90, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => [ + 'database' => env('DB_CONNECTION', 'mysql'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..4460f0e --- /dev/null +++ b/config/services.php @@ -0,0 +1,38 @@ + [ + 'domain' => env('MAILGUN_DOMAIN'), + 'secret' => env('MAILGUN_SECRET'), + ], + + 'ses' => [ + 'key' => env('SES_KEY'), + 'secret' => env('SES_SECRET'), + 'region' => 'us-east-1', + ], + + 'sparkpost' => [ + 'secret' => env('SPARKPOST_SECRET'), + ], + + 'stripe' => [ + 'model' => App\User::class, + 'key' => env('STRIPE_KEY'), + 'secret' => env('STRIPE_SECRET'), + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..736fb3c --- /dev/null +++ b/config/session.php @@ -0,0 +1,197 @@ + env('SESSION_DRIVER', 'file'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to immediately expire on the browser closing, set that option. + | + */ + + 'lifetime' => env('SESSION_LIFETIME', 120), + + 'expire_on_close' => false, + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it is stored. All encryption will be run + | automatically by Laravel and you can use the Session like normal. + | + */ + + 'encrypt' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file sessions. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using the "apc" or "memcached" session drivers, you may specify a + | cache store that should be used for these sessions. This value must + | correspond with one of the application's configured cache stores. + | + */ + + 'store' => null, + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + str_slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => env('SESSION_DOMAIN', null), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE', false), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. You are free to modify this option if needed. + | + */ + + 'http_only' => true, + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | do not enable this as other CSRF protection services are in place. + | + | Supported: "lax", "strict" + | + */ + + 'same_site' => null, + +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..2acfd9c --- /dev/null +++ b/config/view.php @@ -0,0 +1,33 @@ + [ + resource_path('views'), + ], + + /* + |-------------------------------------------------------------------------- + | Compiled View Path + |-------------------------------------------------------------------------- + | + | This option determines where all the compiled Blade templates will be + | stored for your application. Typically, this is within the storage + | directory. However, as usual, you are free to change this value. + | + */ + + 'compiled' => realpath(storage_path('framework/views')), + +]; diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000..9b1dffd --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +*.sqlite diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 0000000..061d75a --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,25 @@ +define(App\User::class, function (Faker $faker) { + static $password; + + return [ + 'name' => $faker->name, + 'email' => $faker->unique()->safeEmail, + 'password' => $password ?: $password = bcrypt('secret'), + 'remember_token' => str_random(10), + ]; +}); diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php new file mode 100644 index 0000000..689cbee --- /dev/null +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('users'); + } +} diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php new file mode 100644 index 0000000..0d5cb84 --- /dev/null +++ b/database/migrations/2014_10_12_100000_create_password_resets_table.php @@ -0,0 +1,32 @@ +string('email')->index(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('password_resets'); + } +} diff --git a/database/migrations/2017_11_28_160623_create_issues_table.php b/database/migrations/2017_11_28_160623_create_issues_table.php new file mode 100644 index 0000000..c6ca8dd --- /dev/null +++ b/database/migrations/2017_11_28_160623_create_issues_table.php @@ -0,0 +1,32 @@ +increments('id'); + $table->string('title'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('issues'); + } +} diff --git a/database/migrations/2017_11_30_144257_add_content_to_issues_table.php b/database/migrations/2017_11_30_144257_add_content_to_issues_table.php new file mode 100644 index 0000000..6d7775b --- /dev/null +++ b/database/migrations/2017_11_30_144257_add_content_to_issues_table.php @@ -0,0 +1,32 @@ +text('content'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('issues', function (Blueprint $table) { + $table->dropColumn('content'); + }); + } +} diff --git a/database/migrations/2017_12_08_165026_create_comments_table.php b/database/migrations/2017_12_08_165026_create_comments_table.php new file mode 100644 index 0000000..4b06d91 --- /dev/null +++ b/database/migrations/2017_12_08_165026_create_comments_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->integer('issue_id'); + $table->string('name'); + $table->string('email'); + $table->text('content'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('comments'); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php new file mode 100644 index 0000000..e119db6 --- /dev/null +++ b/database/seeds/DatabaseSeeder.php @@ -0,0 +1,16 @@ +call(UsersTableSeeder::class); + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7ceac0e --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "private": true, + "scripts": { + "dev": "npm run development", + "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch-poll": "npm run watch -- --watch-poll", + "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", + "prod": "npm run production", + "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" + }, + "devDependencies": { + "axios": "^0.17", + "bootstrap-sass": "^3.3.7", + "cross-env": "^5.1", + "jquery": "^3.2", + "laravel-mix": "^1.0", + "lodash": "^4.17.4", + "vue": "^2.5.7" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..bb9c4a7 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,31 @@ + + + + + ./tests/Feature + + + + ./tests/Unit + + + + + ./app + + + + + + + + + diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..4df299c --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,21 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Handle Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/assets/css/common.css b/public/assets/css/common.css new file mode 100644 index 0000000..daca849 --- /dev/null +++ b/public/assets/css/common.css @@ -0,0 +1,255 @@ +/* Write your styles */ +a { + color: #7EB6AD; +} + +a:hover { + color: teal; +} + +.am-topbar .am-topbar-right a { + color: #fff; +} + +.am-badge-secondary { + background-color: teal; +} + +.am-btn-secondary { + background-color: #7EB6AD; + border-color: #7EB6AD; +} + +.am-btn-secondary:focus, .am-btn-secondary:hover { + background-color: teal; +} + +.am-btn-secondary.am-active, .am-btn-secondary:active, .am-btn-secondary:focus, .am-btn-secondary:hover, .am-dropdown.am-active .am-btn-secondary.am-dropdown-toggle { + border-color: teal; +} + +.am-pagination > .am-active > a, .am-pagination > .am-active > a:focus, .am-pagination > .am-active > a:hover, .am-pagination > .am-active > span, .am-pagination > .am-active > span:focus, .am-pagination > .am-active > span:hover { + border-color: teal; + background-color: teal; +} + +.page-404 { + text-align: center; + padding: 100px 0; +} + +.header h1 { + font-size: 200%; + color: #333; + margin-top: 30px; +} + +.get { + background: url("../img/bg.jpg") no-repeat right center; + background-size: cover; + color: #fff; + text-align: center; + padding: 100px 0; +} + +.get-title { + font-size: 200%; + border: 2px solid #fff; + padding: 20px; + display: inline-block; +} + +.get-btn { + background: #fff; +} + +.detail { + border-bottom: 1px solid #ddd; + margin-top: 0; + margin-bottom: 35px; + background: #7EB6AD; + color: #fff; +} + +.detail-h1 { + text-align: center; + font-size: 200%; + margin: 40px 0; +} + +.detail-h2 { + text-align: center; + font-size: 150%; + margin: 40px 0; +} + +.issue-comment-count a { + font-size: 45px; +} + +.meta-data { + color: #999; + font-size: 12px; +} + +.footer p { + color: #7f8c8d; + margin: 0; + padding: 15px 0; + text-align: center; + background: #2d3e50; +} + +.am-icon-comments { + font-size: 25px; + position: relative; + top: -20px; + color: #c9c9c9; +} + +.am-icon-heart { + color: #dd514c; +} + +#nprogress .nprogress-bar { + background: #dd514c; +} + +#nprogress .nprogress-spinner-icon { + border-top-color: #dd514c; + border-left-color: #dd514c; +} + +#nprogress .nprogress-peg { + -webkit-box-shadow: 0 0 10px #dd514c, 0 0 5px #dd514c; + box-shadow: 0 0 10px #dd514c, 0 0 5px #dd514c; +} + +.issue-heading { + border-bottom: 1px solid #ddd; + padding-bottom: 30px; + padding-top: 30px; + margin-top: 0; + margin-bottom: 35px; + background: #7EB6AD; + color: #fff; + font-size: 2em; +} + +.issue-heading a { + margin-right: 30px; +} + +.notice { + position: absolute; + z-index: 9999; + bottom: 60px; + right: 20px; + background: teal; + color: white; + padding: 20px; + -webkit-box-shadow: 6px 7px 9px -1px rgba(0, 0, 0, 0.68); + -moz-box-shadow: 6px 7px 9px -1px rgba(0, 0, 0, 0.68); + box-shadow: 6px 7px 9px -1px rgba(0, 0, 0, 0.68); +} + +/* ========================================================================== + Component: Pagination + ============================================================================ */ +.pagination { + margin: 1.5rem 0; + list-style: none; + color: #999999; + text-align: center; + padding: 24px 0; +} + +.pagination:before, +.pagination:after { + content: " "; + display: table; +} + +.pagination:after { + clear: both; +} + +.pagination > li { + display: inline-block; +} + +.pagination > li > a, +.pagination > li > span { + position: relative; + display: block; + padding: 0.5em 1em; + text-decoration: none; + line-height: 1.2; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 0; + margin-bottom: 5px; + margin-right: 5px; +} + +.pagination > li:last-child > a, +.pagination > li:last-child > span { + margin-right: 0; +} + +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} + +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + background-color: #7EB6AD; + border-color: #7EB6AD; + cursor: default; +} + +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + background-color: #fff; + border-color: #ddd; + cursor: not-allowed; + pointer-events: none; +} + +.pagination .pagination-prev { + float: left; +} + +.pagination .pagination-prev a { + border-radius: 0; +} + +.pagination .pagination-next { + float: right; +} + +.pagination .pagination-next a { + border-radius: 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} \ No newline at end of file diff --git a/public/assets/img/404.jpg b/public/assets/img/404.jpg new file mode 100644 index 0000000..f94eef6 Binary files /dev/null and b/public/assets/img/404.jpg differ diff --git a/public/assets/img/avatar1.png b/public/assets/img/avatar1.png new file mode 100644 index 0000000..91994a1 Binary files /dev/null and b/public/assets/img/avatar1.png differ diff --git a/public/assets/img/avatar2.png b/public/assets/img/avatar2.png new file mode 100644 index 0000000..d9cdbb2 Binary files /dev/null and b/public/assets/img/avatar2.png differ diff --git a/public/assets/img/bg.jpg b/public/assets/img/bg.jpg new file mode 100755 index 0000000..e63e8f8 Binary files /dev/null and b/public/assets/img/bg.jpg differ diff --git a/public/assets/img/captcha.png b/public/assets/img/captcha.png new file mode 100644 index 0000000..fb07828 Binary files /dev/null and b/public/assets/img/captcha.png differ diff --git a/public/assets/js/common.js b/public/assets/js/common.js new file mode 100644 index 0000000..433927f --- /dev/null +++ b/public/assets/js/common.js @@ -0,0 +1,5 @@ +$.AMUI.progress.start(); + +$(window).on("load", function () { + $.AMUI.progress.done(); +}) \ No newline at end of file diff --git a/public/assets/js/common_notice.js b/public/assets/js/common_notice.js new file mode 100644 index 0000000..788b2c7 --- /dev/null +++ b/public/assets/js/common_notice.js @@ -0,0 +1,10 @@ +$.AMUI.progress.start(); + +$(window).on("load", function () { + $.AMUI.progress.done(); +}) + +var hideNotice = function () { + $(".notice").fadeOut("slow"); +} +setTimeout(hideNotice, 4000); \ No newline at end of file diff --git a/public/assets/js/jquery.min.js b/public/assets/js/jquery.min.js new file mode 100644 index 0000000..c66b6f4 --- /dev/null +++ b/public/assets/js/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r(""),t.close(),e=t.parentWindow.Object.prototype,t=null,e},m=function(){var e,t=document.createElement("iframe"),n=document.body||document.documentElement;return t.style.display="none",n.appendChild(t),t.src="javascript:",e=t.contentWindow.Object.prototype,n.removeChild(t),t=null,e};y=g||"undefined"==typeof document?function(){return{__proto__:null}}:function(){var e=v()?b():m();delete e.constructor,delete e.hasOwnProperty,delete e.propertyIsEnumerable,delete e.isPrototypeOf,delete e.toLocaleString,delete e.toString,delete e.valueOf;var t=function(){};return t.prototype=e,y=function(){return new t},new t},Object.create=function(e,t){var n,r=function(){};if(null===e)n=y();else{if("object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object prototype may only be an Object or null");r.prototype=e,n=new r,n.__proto__=e}return void 0!==t&&Object.defineProperties(n,t),n}}var w=function(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){return!1}};if(Object.defineProperty){var O=w({}),T="undefined"==typeof document||w(document.createElement("div"));if(!O||!T)var j=Object.defineProperty,x=Object.defineProperties}if(!Object.defineProperty||j){var E="Property description must be an object: ",S="Object.defineProperty called on non-object: ",D="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(o,a,c){if("object"!=typeof o&&"function"!=typeof o||null===o)throw new TypeError(S+o);if("object"!=typeof c&&"function"!=typeof c||null===c)throw new TypeError(E+c);if(j)try{return j.call(Object,o,a,c)}catch(s){}if("value"in c)if(u&&(n(o,a)||r(o,a))){var l=o.__proto__;o.__proto__=i,delete o[a],o[a]=c.value,o.__proto__=l}else o[a]=c.value;else{if(!u&&("get"in c||"set"in c))throw new TypeError(D);"get"in c&&e(o,a,c.get),"set"in c&&t(o,a,c.set)}return o}}Object.defineProperties&&!x||(Object.defineProperties=function(e,t){if(x)try{return x.call(Object,e,t)}catch(n){}return Object.keys(t).forEach(function(n){"__proto__"!==n&&Object.defineProperty(e,n,t[n])}),e}),Object.seal||(Object.seal=function(e){if(Object(e)!==e)throw new TypeError("Object.seal can only be called on Objects.");return e}),Object.freeze||(Object.freeze=function(e){if(Object(e)!==e)throw new TypeError("Object.freeze can only be called on Objects.");return e});try{Object.freeze(function(){})}catch(_){Object.freeze=function(e){return function(t){return"function"==typeof t?t:e(t)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(e){if(Object(e)!==e)throw new TypeError("Object.preventExtensions can only be called on Objects.");return e}),Object.isSealed||(Object.isSealed=function(e){if(Object(e)!==e)throw new TypeError("Object.isSealed can only be called on Objects.");return!1}),Object.isFrozen||(Object.isFrozen=function(e){if(Object(e)!==e)throw new TypeError("Object.isFrozen can only be called on Objects.");return!1}),Object.isExtensible||(Object.isExtensible=function(e){if(Object(e)!==e)throw new TypeError("Object.isExtensible can only be called on Objects.");for(var t="";a(e,t);)t+="?";e[t]=!0;var n=a(e,t);return delete e[t],n})}),function(e){"use strict";e.console=e.console||{};for(var t,n,r=e.console,o={},i=function(){},a="memory".split(","),c="assert,clear,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn".split(",");t=a.pop();)r[t]||(r[t]=o);for(;n=c.pop();)"function"!=typeof r[n]&&(r[n]=i)}("undefined"==typeof window?this:window),!window.addEventListener&&function(e,t,n,r,o,i,a){e[r]=t[r]=n[r]=function(e,t){var n=this;a.unshift([n,e,t,function(e){e.currentTarget=n,e.preventDefault=function(){e.returnValue=!1},e.stopPropagation=function(){e.cancelBubble=!0},e.target=e.srcElement||n,t.call(n,e)}]),this.attachEvent("on"+e,a[0][3])},e[o]=t[o]=n[o]=function(e,t){for(var n,r=0;n=a[r];++r)if(n[0]==this&&n[1]==e&&n[2]==t)return this.detachEvent("on"+e,a.splice(r,1)[0][3])},e[i]=t[i]=n[i]=function(e){return this.fireEvent("on"+e.type,e)}}(Window.prototype,HTMLDocument.prototype,Element.prototype,"addEventListener","removeEventListener","dispatchEvent",[]),function(e,t){"use strict";var n=function(){var e=document.createElement("div");return e.style.cssText="font-size: 1rem;",/rem/.test(e.style.fontSize)},r=function(){for(var e=document.getElementsByTagName("link"),t=[],n=0;n0?(b=[],v=[],d=[],o()):c()}},a=function(e,t){for(var n,r=f(e).replace(/\/\*[\s\S]*?\*\//g,""),o=/[\w\d\s\-\/\\\[\]:,.'"*()<>+~%#^$_=|@]+\{[\w\d\s\-\/\\%#:!;,.'"*()]+\d*\.?\d+rem[\w\d\s\-\/\\%#:!;,.'"*()]*\}/g,i=r.match(o),a=/\d*\.?\d+rem/g,c=r.match(a),s=/(.*\/)/,u=s.exec(t)[0],l=/@import (?:url\()?['"]?([^'\)"]*)['"]?\)?[^;]*/gm;null!==(n=l.exec(e));)0===n[1].indexOf("/")?d.push(n[1]):d.push(u+n[1]);null!==i&&0!==i.length&&(y=y.concat(i),g=g.concat(c))},c=function(){for(var e=/[\w\d\s\-\/\\%#:,.'"*()]+\d*\.?\d+rem[\w\d\s\-\/\\%#:!,.'"*()]*[;}]/g,t=0;t #mq-test-1 { width: 42px; }',n.insertBefore(o,r),t=42===i.offsetWidth,n.removeChild(o),{matches:t,media:e}}}(e.document)}(this),function(e){"use strict";function t(){O(!0)}var n={};e.respond=n,n.update=function(){};var r=[],o=function(){var t=!1;try{t=new e.XMLHttpRequest}catch(n){t=new e.ActiveXObject("Microsoft.XMLHTTP")}return function(){return t; +}}(),i=function(e,t){var n=o();n&&(n.open("GET",e,!0),n.onreadystatechange=function(){4!==n.readyState||200!==n.status&&304!==n.status||t(n.responseText)},4!==n.readyState&&n.send(null))},a=function(e){return e.replace(n.regex.minmaxwh,"").match(n.regex.other)};if(n.ajax=i,n.queue=r,n.unsupportedmq=a,n.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^\/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},n.mediaQueriesSupported=e.matchMedia&&null!==e.matchMedia("only all")&&e.matchMedia("only all").matches,!n.mediaQueriesSupported){var c,s,u,l=e.document,f=l.documentElement,p=[],h=[],d=[],y={},g=30,v=l.getElementsByTagName("head")[0]||f,b=l.getElementsByTagName("base")[0],m=v.getElementsByTagName("link"),w=function(){var e,t=l.createElement("div"),n=l.body,r=f.style.fontSize,o=n&&n.style.fontSize,i=!1;return t.style.cssText="position:absolute;font-size:1em;width:1em",n||(n=i=l.createElement("body"),n.style.background="none"),f.style.fontSize="100%",n.style.fontSize="100%",n.appendChild(t),i&&f.insertBefore(n,f.firstChild),e=t.offsetWidth,i?f.removeChild(n):n.removeChild(t),f.style.fontSize=r,o&&(n.style.fontSize=o),e=u=parseFloat(e)},O=function(t){var n="clientWidth",r=f[n],o="assets/css1Compat"===l.compatMode&&r||l.body[n]||r,i={},a=m[m.length-1],y=(new Date).getTime();if(t&&c&&g>y-c)return e.clearTimeout(s),void(s=e.setTimeout(O,g));c=y;for(var b in p)if(p.hasOwnProperty(b)){var T=p[b],j=T.minw,x=T.maxw,E=null===j,S=null===x,D="em";j&&(j=parseFloat(j)*(j.indexOf(D)>-1?u||w():1)),x&&(x=parseFloat(x)*(x.indexOf(D)>-1?u||w():1)),T.hasquery&&(E&&S||!(E||o>=j)||!(S||x>=o))||(i[T.media]||(i[T.media]=[]),i[T.media].push(h[T.rules]))}for(var _ in d)d.hasOwnProperty(_)&&d[_]&&d[_].parentNode===v&&v.removeChild(d[_]);d.length=0;for(var M in i)if(i.hasOwnProperty(M)){var P=l.createElement("style"),I=i[M].join("\n");P.type="text/css",P.media=M,v.insertBefore(P,a.nextSibling),P.styleSheet?P.styleSheet.cssText=I:P.appendChild(l.createTextNode(I)),d.push(P)}},T=function(e,t,r){var o=e.replace(n.regex.comments,"").replace(n.regex.keyframes,"").match(n.regex.media),i=o&&o.length||0;t=t.substring(0,t.lastIndexOf("/"));var c=function(e){return e.replace(n.regex.urls,"$1"+t+"$2$3")},s=!i&&r;t.length&&(t+="/"),s&&(i=1);for(var u=0;i>u;u++){var l,f,d,y;s?(l=r,h.push(c(e))):(l=o[u].match(n.regex.findStyles)&&RegExp.$1,h.push(RegExp.$2&&c(RegExp.$2))),d=l.split(","),y=d.length;for(var g=0;y>g;g++)f=d[g],a(f)||p.push({media:f.split("(")[0].match(n.regex.only)&&RegExp.$2||"all",rules:h.length-1,hasquery:f.indexOf("(")>-1,minw:f.match(n.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:f.match(n.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}O()},j=function(){if(r.length){var t=r.shift();i(t.href,function(n){T(n,t.href,t.media),y[t.href]=!0,e.setTimeout(function(){j()},0)})}},x=function(){for(var t=0;t 0) || // IE 10 + (window.navigator['pointerEnabled'] && + window.navigator['maxTouchPoints'] > 0) || // IE >=11 + false); + /* eslint-enable dot-notation */ + + // https://developer.mozilla.org/zh-CN/docs/DOM/MutationObserver + UI.support.mutationobserver = (window.MutationObserver || + window.WebKitMutationObserver || null); + + // https://github.com/Modernizr/Modernizr/blob/924c7611c170ef2dc502582e5079507aff61e388/feature-detects/forms/validation.js#L20 + UI.support.formValidation = (typeof document.createElement('form'). + checkValidity === 'function'); + + UI.utils = {}; + + /** + * Debounce function + * + * @param {function} func Function to be debounced + * @param {number} wait Function execution threshold in milliseconds + * @param {bool} immediate Whether the function should be called at + * the beginning of the delay instead of the + * end. Default is false. + * @description Executes a function when it stops being invoked for n seconds + * @see _.debounce() http://underscorejs.org + */ + UI.utils.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this; + var args = arguments; + var later = function() { + timeout = null; + if (!immediate) { + func.apply(context, args); + } + }; + var callNow = immediate && !timeout; + + clearTimeout(timeout); + timeout = setTimeout(later, wait); + + if (callNow) { + func.apply(context, args); + } + }; + }; + + UI.utils.isInView = function(element, options) { + var $element = $(element); + var visible = !!($element.width() || $element.height()) && + $element.css('display') !== 'none'; + + if (!visible) { + return false; + } + + var windowLeft = $win.scrollLeft(); + var windowTop = $win.scrollTop(); + var offset = $element.offset(); + var left = offset.left; + var top = offset.top; + + options = $.extend({topOffset: 0, leftOffset: 0}, options); + + return (top + $element.height() >= windowTop && + top - options.topOffset <= windowTop + $win.height() && + left + $element.width() >= windowLeft && + left - options.leftOffset <= windowLeft + $win.width()); + }; + + UI.utils.parseOptions = UI.utils.options = function(string) { + if ($.isPlainObject(string)) { + return string; + } + + var start = (string ? string.indexOf('{') : -1); + var options = {}; + + if (start != -1) { + try { + options = (new Function('', + 'var json = ' + string.substr(start) + + '; return JSON.parse(JSON.stringify(json));'))(); + } catch (e) { + } + } + + return options; + }; + + UI.utils.generateGUID = function(namespace) { + var uid = namespace + '-' || 'am-'; + + do { + uid += Math.random().toString(36).substring(2, 7); + } while (document.getElementById(uid)); + + return uid; + }; + + // @see https://davidwalsh.name/get-absolute-url + UI.utils.getAbsoluteUrl = (function() { + var a; + + return function(url) { + if (!a) { + a = document.createElement('a'); + } + + a.href = url; + + return a.href; + }; + })(); + + /** + * Plugin AMUI Component to jQuery + * + * @param {String} name - plugin name + * @param {Function} Component - plugin constructor + * @param {Object} [pluginOption] + * @param {String} pluginOption.dataOptions + * @param {Function} pluginOption.methodCall - custom method call + * @param {Function} pluginOption.before + * @param {Function} pluginOption.after + * @since v2.4.1 + */ + UI.plugin = function UIPlugin(name, Component, pluginOption) { + var old = $.fn[name]; + pluginOption = pluginOption || {}; + + $.fn[name] = function(option) { + var allArgs = Array.prototype.slice.call(arguments, 0); + var args = allArgs.slice(1); + var propReturn; + var $set = this.each(function() { + var $this = $(this); + var dataName = 'amui.' + name; + var dataOptionsName = pluginOption.dataOptions || ('data-am-' + name); + var instance = $this.data(dataName); + var options = $.extend({}, + UI.utils.parseOptions($this.attr(dataOptionsName)), + typeof option === 'object' && option); + + if (!instance && option === 'destroy') { + return; + } + + if (!instance) { + $this.data(dataName, (instance = new Component(this, options))); + } + + // custom method call + if (pluginOption.methodCall) { + pluginOption.methodCall.call($this, allArgs, instance); + } else { + // before method call + pluginOption.before && + pluginOption.before.call($this, allArgs, instance); + + if (typeof option === 'string') { + propReturn = typeof instance[option] === 'function' ? + instance[option].apply(instance, args) : instance[option]; + } + + // after method call + pluginOption.after && pluginOption.after.call($this, allArgs, instance); + } + }); + + return (propReturn === undefined) ? $set : propReturn; + }; + + $.fn[name].Constructor = Component; + + // no conflict + $.fn[name].noConflict = function() { + $.fn[name] = old; + return this; + }; + + UI[name] = Component; + }; + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function(duration) { + var called = false; + var $el = this; + + $(this).one(UI.support.transition.end, function() { + called = true; + }); + + var callback = function() { + if (!called) { + $($el).trigger(UI.support.transition.end); + } + $el.transitionEndTimmer = undefined; + }; + this.transitionEndTimmer = setTimeout(callback, duration); + return this; + }; + + $.fn.redraw = function() { + return this.each(function() { + /* eslint-disable */ + var redraw = this.offsetHeight; + /* eslint-enable */ + }); + }; + + $.fn.transitionEnd = function(callback) { + var endEvent = UI.support.transition.end; + var dom = this; + + function fireCallBack(e) { + callback.call(this, e); + endEvent && dom.off(endEvent, fireCallBack); + } + + if (callback && endEvent) { + dom.on(endEvent, fireCallBack); + } + + return this; + }; + + $.fn.removeClassRegEx = function() { + return this.each(function(regex) { + var classes = $(this).attr('class'); + + if (!classes || !regex) { + return false; + } + + var classArray = []; + classes = classes.split(' '); + + for (var i = 0, len = classes.length; i < len; i++) { + if (!classes[i].match(regex)) { + classArray.push(classes[i]); + } + } + + $(this).attr('class', classArray.join(' ')); + }); + }; + + // + $.fn.alterClass = function(removals, additions) { + var self = this; + + if (removals.indexOf('*') === -1) { + // Use native jQuery methods if there is no wildcard matching + self.removeClass(removals); + return !additions ? self : self.addClass(additions); + } + + var classPattern = new RegExp('\\s' + + removals. + replace(/\*/g, '[A-Za-z0-9-_]+'). + split(' '). + join('\\s|\\s') + + '\\s', 'g'); + + self.each(function(i, it) { + var cn = ' ' + it.className + ' '; + while (classPattern.test(cn)) { + cn = cn.replace(classPattern, ' '); + } + it.className = $.trim(cn); + }); + + return !additions ? self : self.addClass(additions); + }; + + // handle multiple browsers for requestAnimationFrame() + // http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ + // https://github.com/gnarf/jquery-requestAnimationFrame + UI.utils.rAF = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + // if all else fails, use setTimeout + function(callback) { + return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps + }; + })(); + + // handle multiple browsers for cancelAnimationFrame() + UI.utils.cancelAF = (function() { + return window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.oCancelAnimationFrame || + function(id) { + window.clearTimeout(id); + }; + })(); + + // via http://davidwalsh.name/detect-scrollbar-width + UI.utils.measureScrollbar = function() { + if (document.body.clientWidth >= window.innerWidth) { + return 0; + } + + // if ($html.width() >= window.innerWidth) return; + // var scrollbarWidth = window.innerWidth - $html.width(); + var $measure = $('
'); + + $(document.body).append($measure); + + var scrollbarWidth = $measure[0].offsetWidth - $measure[0].clientWidth; + + $measure.remove(); + + return scrollbarWidth; + }; + + UI.utils.imageLoader = function($image, callback) { + function loaded() { + callback($image[0]); + } + + function bindLoad() { + this.one('load', loaded); + if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { + var src = this.attr('src'); + var param = src.match(/\?/) ? '&' : '?'; + + param += 'random=' + (new Date()).getTime(); + this.attr('src', src + param); + } + } + + if (!$image.attr('src')) { + loaded(); + return; + } + + if ($image[0].complete || $image[0].readyState === 4) { + loaded(); + } else { + bindLoad.call($image); + } + }; + + /** + * @see https://github.com/cho45/micro-template.js + * (c) cho45 http://cho45.github.com/mit-license + */ + UI.template = function(id, data) { + var me = UI.template; + + if (!me.cache[id]) { + me.cache[id] = (function() { + var name = id; + var string = /^[\w\-]+$/.test(id) ? + me.get(id) : (name = 'template(string)', id); // no warnings + + var line = 1; + /* eslint-disable max-len, quotes */ + var body = ('try { ' + (me.variable ? + 'var ' + me.variable + ' = this.stash;' : 'with (this.stash) { ') + + "this.ret += '" + + string. + replace(/<%/g, '\x11').replace(/%>/g, '\x13'). // if you want other tag, just edit this line + replace(/'(?![^\x11\x13]+?\x13)/g, '\\x27'). + replace(/^\s*|\s*$/g, ''). + replace(/\n/g, function() { + return "';\nthis.line = " + (++line) + "; this.ret += '\\n"; + }). + replace(/\x11-(.+?)\x13/g, "' + ($1) + '"). + replace(/\x11=(.+?)\x13/g, "' + this.escapeHTML($1) + '"). + replace(/\x11(.+?)\x13/g, "'; $1; this.ret += '") + + "'; " + (me.variable ? "" : "}") + "return this.ret;" + + "} catch (e) { throw 'TemplateError: ' + e + ' (on " + name + + "' + ' line ' + this.line + ')'; } " + + "//@ sourceURL=" + name + "\n" // source map + ).replace(/this\.ret \+= '';/g, ''); + /* eslint-enable max-len, quotes */ + var func = new Function(body); + var map = { + '&': '&', + '<': '<', + '>': '>', + '\x22': '"', + '\x27': ''' + }; + var escapeHTML = function(string) { + return ('' + string).replace(/[&<>\'\"]/g, function(_) { + return map[_]; + }); + }; + + return function(stash) { + return func.call(me.context = { + escapeHTML: escapeHTML, + line: 1, + ret: '', + stash: stash + }); + }; + })(); + } + + return data ? me.cache[id](data) : me.cache[id]; + }; + + UI.template.cache = {}; + + UI.template.get = function(id) { + if (id) { + var element = document.getElementById(id); + return element && element.innerHTML || ''; + } + }; + + // Dom mutation watchers + UI.DOMWatchers = []; + UI.DOMReady = false; + UI.ready = function(callback) { + UI.DOMWatchers.push(callback); + if (UI.DOMReady) { + // console.log('Ready call'); + callback(document); + } + }; + + UI.DOMObserve = function(elements, options, callback) { + var Observer = UI.support.mutationobserver; + if (!Observer) { + return; + } + + options = $.isPlainObject(options) ? + options : {childList: true, subtree: true}; + + callback = typeof callback === 'function' && callback || function() { + }; + + $(elements).each(function() { + var element = this; + var $element = $(element); + + if ($element.data('am.observer')) { + return; + } + + try { + var observer = new Observer(UI.utils.debounce( + function(mutations, instance) { + callback.call(element, mutations, instance); + // trigger this event manually if MutationObserver not supported + $element.trigger('changed.dom.amui'); + }, 50)); + + observer.observe(element, options); + + $element.data('am.observer', observer); + } catch (e) { + } + }); + }; + + $.fn.DOMObserve = function(options, callback) { + return this.each(function() { + /* eslint-disable new-cap */ + UI.DOMObserve(this, options, callback); + /* eslint-enable new-cap */ + }); + }; + + if (UI.support.touch) { + $html.addClass('am-touch'); + } + + $(document).on('changed.dom.amui', function(e) { + var element = e.target; + + // TODO: just call changed element's watcher + // every watcher callback should have a key + // use like this:
+ // get keys via $(element).data('amObserve') + // call functions store with these keys + $.each(UI.DOMWatchers, function(i, watcher) { + watcher(element); + }); + }); + + $(function() { + var $body = $(document.body); + + UI.DOMReady = true; + + // Run default init + $.each(UI.DOMWatchers, function(i, watcher) { + watcher(document); + }); + + // watches DOM + /* eslint-disable new-cap */ + UI.DOMObserve('[data-am-observe]'); + /* eslint-enable */ + + $html.removeClass('no-js').addClass('js'); + + UI.support.animation && $html.addClass('cssanimations'); + + // iOS standalone mode + if (window.navigator.standalone) { + $html.addClass('am-standalone'); + } + + $('.am-topbar-fixed-top').length && + $body.addClass('am-with-topbar-fixed-top'); + + $('.am-topbar-fixed-bottom').length && + $body.addClass('am-with-topbar-fixed-bottom'); + + // Remove responsive classes in .am-layout + var $layout = $('.am-layout'); + $layout.find('[class*="md-block-grid"]').alterClass('md-block-grid-*'); + $layout.find('[class*="lg-block-grid"]').alterClass('lg-block-grid'); + + // widgets not in .am-layout + $('[data-am-widget]').each(function() { + var $widget = $(this); + // console.log($widget.parents('.am-layout').length) + if ($widget.parents('.am-layout').length === 0) { + $widget.addClass('am-no-layout'); + } + }); + }); + + module.exports = UI; + + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + /*! Hammer.JS - v2.0.8 - 2016-04-22 + * http://hammerjs.github.io/ + * + * Copyright (c) 2016 Jorik Tangelder; + * Licensed under the MIT license */ + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o']; + var TEST_ELEMENT = document.createElement('div'); + + var TYPE_FUNCTION = 'function'; + + var round = Math.round; + var abs = Math.abs; + var now = Date.now; + + /** + * set a timeout with a given scope + * @param {Function} fn + * @param {Number} timeout + * @param {Object} context + * @returns {number} + */ + function setTimeoutContext(fn, timeout, context) { + return setTimeout(bindFn(fn, context), timeout); + } + + /** + * if the argument is an array, we want to execute the fn on each entry + * if it aint an array we don't want to do a thing. + * this is used by all the methods that accept a single and array argument. + * @param {*|Array} arg + * @param {String} fn + * @param {Object} [context] + * @returns {Boolean} + */ + function invokeArrayArg(arg, fn, context) { + if (Array.isArray(arg)) { + each(arg, context[fn], context); + return true; + } + return false; + } + + /** + * walk objects and arrays + * @param {Object} obj + * @param {Function} iterator + * @param {Object} context + */ + function each(obj, iterator, context) { + var i; + + if (!obj) { + return; + } + + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length !== undefined) { + i = 0; + while (i < obj.length) { + iterator.call(context, obj[i], i, obj); + i++; + } + } else { + for (i in obj) { + obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj); + } + } + } + + /** + * wrap a method with a deprecation warning and stack trace + * @param {Function} method + * @param {String} name + * @param {String} message + * @returns {Function} A new function wrapping the supplied method. + */ + function deprecate(method, name, message) { + var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n'; + return function() { + var e = new Error('get-stack-trace'); + var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '') + .replace(/^\s+at\s+/gm, '') + .replace(/^Object.\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace'; + + var log = window.console && (window.console.warn || window.console.log); + if (log) { + log.call(window.console, deprecationMessage, stack); + } + return method.apply(this, arguments); + }; + } + + /** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} target + * @param {...Object} objects_to_assign + * @returns {Object} target + */ + var assign; + if (typeof Object.assign !== 'function') { + assign = function assign(target) { + if (target === undefined || target === null) { + throw new TypeError('Cannot convert undefined or null to object'); + } + + var output = Object(target); + for (var index = 1; index < arguments.length; index++) { + var source = arguments[index]; + if (source !== undefined && source !== null) { + for (var nextKey in source) { + if (source.hasOwnProperty(nextKey)) { + output[nextKey] = source[nextKey]; + } + } + } + } + return output; + }; + } else { + assign = Object.assign; + } + + /** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] + * @returns {Object} dest + */ + var extend = deprecate(function extend(dest, src, merge) { + var keys = Object.keys(src); + var i = 0; + while (i < keys.length) { + if (!merge || (merge && dest[keys[i]] === undefined)) { + dest[keys[i]] = src[keys[i]]; + } + i++; + } + return dest; + }, 'extend', 'Use `assign`.'); + + /** + * merge the values from src in the dest. + * means that properties that exist in dest will not be overwritten by src + * @param {Object} dest + * @param {Object} src + * @returns {Object} dest + */ + var merge = deprecate(function merge(dest, src) { + return extend(dest, src, true); + }, 'merge', 'Use `assign`.'); + + /** + * simple class inheritance + * @param {Function} child + * @param {Function} base + * @param {Object} [properties] + */ + function inherit(child, base, properties) { + var baseP = base.prototype, + childP; + + childP = child.prototype = Object.create(baseP); + childP.constructor = child; + childP._super = baseP; + + if (properties) { + assign(childP, properties); + } + } + + /** + * simple function bind + * @param {Function} fn + * @param {Object} context + * @returns {Function} + */ + function bindFn(fn, context) { + return function boundFn() { + return fn.apply(context, arguments); + }; + } + + /** + * let a boolean value also be a function that must return a boolean + * this first item in args will be used as the context + * @param {Boolean|Function} val + * @param {Array} [args] + * @returns {Boolean} + */ + function boolOrFn(val, args) { + if (typeof val == TYPE_FUNCTION) { + return val.apply(args ? args[0] || undefined : undefined, args); + } + return val; + } + + /** + * use the val2 when val1 is undefined + * @param {*} val1 + * @param {*} val2 + * @returns {*} + */ + function ifUndefined(val1, val2) { + return (val1 === undefined) ? val2 : val1; + } + + /** + * addEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ + function addEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.addEventListener(type, handler, false); + }); + } + + /** + * removeEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ + function removeEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.removeEventListener(type, handler, false); + }); + } + + /** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ + function hasParent(node, parent) { + while (node) { + if (node == parent) { + return true; + } + node = node.parentNode; + } + return false; + } + + /** + * small indexOf wrapper + * @param {String} str + * @param {String} find + * @returns {Boolean} found + */ + function inStr(str, find) { + return str.indexOf(find) > -1; + } + + /** + * split string on whitespace + * @param {String} str + * @returns {Array} words + */ + function splitStr(str) { + return str.trim().split(/\s+/g); + } + + /** + * find if a array contains the object using indexOf or a simple polyFill + * @param {Array} src + * @param {String} find + * @param {String} [findByKey] + * @return {Boolean|Number} false when not found, or the index + */ + function inArray(src, find, findByKey) { + if (src.indexOf && !findByKey) { + return src.indexOf(find); + } else { + var i = 0; + while (i < src.length) { + if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) { + return i; + } + i++; + } + return -1; + } + } + + /** + * convert array-like objects to real arrays + * @param {Object} obj + * @returns {Array} + */ + function toArray(obj) { + return Array.prototype.slice.call(obj, 0); + } + + /** + * unique array with objects based on a key (like 'id') or just by the array's value + * @param {Array} src [{id:1},{id:2},{id:1}] + * @param {String} [key] + * @param {Boolean} [sort=False] + * @returns {Array} [{id:1},{id:2}] + */ + function uniqueArray(src, key, sort) { + var results = []; + var values = []; + var i = 0; + + while (i < src.length) { + var val = key ? src[i][key] : src[i]; + if (inArray(values, val) < 0) { + results.push(src[i]); + } + values[i] = val; + i++; + } + + if (sort) { + if (!key) { + results = results.sort(); + } else { + results = results.sort(function sortUniqueArray(a, b) { + return a[key] > b[key]; + }); + } + } + + return results; + } + + /** + * get the prefixed property + * @param {Object} obj + * @param {String} property + * @returns {String|Undefined} prefixed + */ + function prefixed(obj, property) { + var prefix, prop; + var camelProp = property[0].toUpperCase() + property.slice(1); + + var i = 0; + while (i < VENDOR_PREFIXES.length) { + prefix = VENDOR_PREFIXES[i]; + prop = (prefix) ? prefix + camelProp : property; + + if (prop in obj) { + return prop; + } + i++; + } + return undefined; + } + + /** + * get a unique id + * @returns {number} uniqueId + */ + var _uniqueId = 1; + function uniqueId() { + return _uniqueId++; + } + + /** + * get the window object of an element + * @param {HTMLElement} element + * @returns {DocumentView|Window} + */ + function getWindowForElement(element) { + var doc = element.ownerDocument || element; + return (doc.defaultView || doc.parentWindow || window); + } + + var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; + + var SUPPORT_TOUCH = ('ontouchstart' in window); + var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined; + var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent); + + var INPUT_TYPE_TOUCH = 'touch'; + var INPUT_TYPE_PEN = 'pen'; + var INPUT_TYPE_MOUSE = 'mouse'; + var INPUT_TYPE_KINECT = 'kinect'; + + var COMPUTE_INTERVAL = 25; + + var INPUT_START = 1; + var INPUT_MOVE = 2; + var INPUT_END = 4; + var INPUT_CANCEL = 8; + + var DIRECTION_NONE = 1; + var DIRECTION_LEFT = 2; + var DIRECTION_RIGHT = 4; + var DIRECTION_UP = 8; + var DIRECTION_DOWN = 16; + + var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT; + var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN; + var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + + var PROPS_XY = ['x', 'y']; + var PROPS_CLIENT_XY = ['clientX', 'clientY']; + + /** + * create new input type manager + * @param {Manager} manager + * @param {Function} callback + * @returns {Input} + * @constructor + */ + function Input(manager, callback) { + var self = this; + this.manager = manager; + this.callback = callback; + this.element = manager.element; + this.target = manager.options.inputTarget; + + // smaller wrapper around the handler, for the scope and the enabled state of the manager, + // so when disabled the input events are completely bypassed. + this.domHandler = function(ev) { + if (boolOrFn(manager.options.enable, [manager])) { + self.handler(ev); + } + }; + + this.init(); + + } + + Input.prototype = { + /** + * should handle the inputEvent data and trigger the callback + * @virtual + */ + handler: function() { }, + + /** + * bind the events + */ + init: function() { + this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + }, + + /** + * unbind the events + */ + destroy: function() { + this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + } + }; + + /** + * create new input type manager + * called by the Manager constructor + * @param {Hammer} manager + * @returns {Input} + */ + function createInputInstance(manager) { + var Type; + var inputClass = manager.options.inputClass; + + if (inputClass) { + Type = inputClass; + } else if (SUPPORT_POINTER_EVENTS) { + Type = PointerEventInput; + } else if (SUPPORT_ONLY_TOUCH) { + Type = TouchInput; + } else if (!SUPPORT_TOUCH) { + Type = MouseInput; + } else { + Type = TouchMouseInput; + } + return new (Type)(manager, inputHandler); + } + + /** + * handle input events + * @param {Manager} manager + * @param {String} eventType + * @param {Object} input + */ + function inputHandler(manager, eventType, input) { + var pointersLen = input.pointers.length; + var changedPointersLen = input.changedPointers.length; + var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0)); + var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0)); + + input.isFirst = !!isFirst; + input.isFinal = !!isFinal; + + if (isFirst) { + manager.session = {}; + } + + // source event is the normalized value of the domEvents + // like 'touchstart, mouseup, pointerdown' + input.eventType = eventType; + + // compute scale, rotation etc + computeInputData(manager, input); + + // emit secret event + manager.emit('hammer.input', input); + + manager.recognize(input); + manager.session.prevInput = input; + } + + /** + * extend the data with some usable properties like scale, rotate, velocity etc + * @param {Object} manager + * @param {Object} input + */ + function computeInputData(manager, input) { + var session = manager.session; + var pointers = input.pointers; + var pointersLength = pointers.length; + + // store the first input to calculate the distance and direction + if (!session.firstInput) { + session.firstInput = simpleCloneInputData(input); + } + + // to compute scale and rotation we need to store the multiple touches + if (pointersLength > 1 && !session.firstMultiple) { + session.firstMultiple = simpleCloneInputData(input); + } else if (pointersLength === 1) { + session.firstMultiple = false; + } + + var firstInput = session.firstInput; + var firstMultiple = session.firstMultiple; + var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center; + + var center = input.center = getCenter(pointers); + input.timeStamp = now(); + input.deltaTime = input.timeStamp - firstInput.timeStamp; + + input.angle = getAngle(offsetCenter, center); + input.distance = getDistance(offsetCenter, center); + + computeDeltaXY(session, input); + input.offsetDirection = getDirection(input.deltaX, input.deltaY); + + var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY); + input.overallVelocityX = overallVelocity.x; + input.overallVelocityY = overallVelocity.y; + input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y; + + input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1; + input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0; + + input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length > + session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers); + + computeIntervalInputData(session, input); + + // find the correct target + var target = manager.element; + if (hasParent(input.srcEvent.target, target)) { + target = input.srcEvent.target; + } + input.target = target; + } + + function computeDeltaXY(session, input) { + var center = input.center; + var offset = session.offsetDelta || {}; + var prevDelta = session.prevDelta || {}; + var prevInput = session.prevInput || {}; + + if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) { + prevDelta = session.prevDelta = { + x: prevInput.deltaX || 0, + y: prevInput.deltaY || 0 + }; + + offset = session.offsetDelta = { + x: center.x, + y: center.y + }; + } + + input.deltaX = prevDelta.x + (center.x - offset.x); + input.deltaY = prevDelta.y + (center.y - offset.y); + } + + /** + * velocity is calculated every x ms + * @param {Object} session + * @param {Object} input + */ + function computeIntervalInputData(session, input) { + var last = session.lastInterval || input, + deltaTime = input.timeStamp - last.timeStamp, + velocity, velocityX, velocityY, direction; + + if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) { + var deltaX = input.deltaX - last.deltaX; + var deltaY = input.deltaY - last.deltaY; + + var v = getVelocity(deltaTime, deltaX, deltaY); + velocityX = v.x; + velocityY = v.y; + velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; + direction = getDirection(deltaX, deltaY); + + session.lastInterval = input; + } else { + // use latest velocity info if it doesn't overtake a minimum period + velocity = last.velocity; + velocityX = last.velocityX; + velocityY = last.velocityY; + direction = last.direction; + } + + input.velocity = velocity; + input.velocityX = velocityX; + input.velocityY = velocityY; + input.direction = direction; + } + + /** + * create a simple clone from the input used for storage of firstInput and firstMultiple + * @param {Object} input + * @returns {Object} clonedInputData + */ + function simpleCloneInputData(input) { + // make a simple copy of the pointers because we will get a reference if we don't + // we only need clientXY for the calculations + var pointers = []; + var i = 0; + while (i < input.pointers.length) { + pointers[i] = { + clientX: round(input.pointers[i].clientX), + clientY: round(input.pointers[i].clientY) + }; + i++; + } + + return { + timeStamp: now(), + pointers: pointers, + center: getCenter(pointers), + deltaX: input.deltaX, + deltaY: input.deltaY + }; + } + + /** + * get the center of all the pointers + * @param {Array} pointers + * @return {Object} center contains `x` and `y` properties + */ + function getCenter(pointers) { + var pointersLength = pointers.length; + + // no need to loop when only one touch + if (pointersLength === 1) { + return { + x: round(pointers[0].clientX), + y: round(pointers[0].clientY) + }; + } + + var x = 0, y = 0, i = 0; + while (i < pointersLength) { + x += pointers[i].clientX; + y += pointers[i].clientY; + i++; + } + + return { + x: round(x / pointersLength), + y: round(y / pointersLength) + }; + } + + /** + * calculate the velocity between two points. unit is in px per ms. + * @param {Number} deltaTime + * @param {Number} x + * @param {Number} y + * @return {Object} velocity `x` and `y` + */ + function getVelocity(deltaTime, x, y) { + return { + x: x / deltaTime || 0, + y: y / deltaTime || 0 + }; + } + + /** + * get the direction between two points + * @param {Number} x + * @param {Number} y + * @return {Number} direction + */ + function getDirection(x, y) { + if (x === y) { + return DIRECTION_NONE; + } + + if (abs(x) >= abs(y)) { + return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return y < 0 ? DIRECTION_UP : DIRECTION_DOWN; + } + + /** + * calculate the absolute distance between two points + * @param {Object} p1 {x, y} + * @param {Object} p2 {x, y} + * @param {Array} [props] containing x and y keys + * @return {Number} distance + */ + function getDistance(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + + return Math.sqrt((x * x) + (y * y)); + } + + /** + * calculate the angle between two coordinates + * @param {Object} p1 + * @param {Object} p2 + * @param {Array} [props] containing x and y keys + * @return {Number} angle + */ + function getAngle(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.atan2(y, x) * 180 / Math.PI; + } + + /** + * calculate the rotation degrees between two pointersets + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} rotation + */ + function getRotation(start, end) { + return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY); + } + + /** + * calculate the scale factor between two pointersets + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} scale + */ + function getScale(start, end) { + return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY); + } + + var MOUSE_INPUT_MAP = { + mousedown: INPUT_START, + mousemove: INPUT_MOVE, + mouseup: INPUT_END + }; + + var MOUSE_ELEMENT_EVENTS = 'mousedown'; + var MOUSE_WINDOW_EVENTS = 'mousemove mouseup'; + + /** + * Mouse events input + * @constructor + * @extends Input + */ + function MouseInput() { + this.evEl = MOUSE_ELEMENT_EVENTS; + this.evWin = MOUSE_WINDOW_EVENTS; + + this.pressed = false; // mousedown state + + Input.apply(this, arguments); + } + + inherit(MouseInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function MEhandler(ev) { + var eventType = MOUSE_INPUT_MAP[ev.type]; + + // on start we want to have the left mouse button down + if (eventType & INPUT_START && ev.button === 0) { + this.pressed = true; + } + + if (eventType & INPUT_MOVE && ev.which !== 1) { + eventType = INPUT_END; + } + + // mouse must be down + if (!this.pressed) { + return; + } + + if (eventType & INPUT_END) { + this.pressed = false; + } + + this.callback(this.manager, eventType, { + pointers: [ev], + changedPointers: [ev], + pointerType: INPUT_TYPE_MOUSE, + srcEvent: ev + }); + } + }); + + var POINTER_INPUT_MAP = { + pointerdown: INPUT_START, + pointermove: INPUT_MOVE, + pointerup: INPUT_END, + pointercancel: INPUT_CANCEL, + pointerout: INPUT_CANCEL + }; + + // in IE10 the pointer types is defined as an enum + var IE10_POINTER_TYPE_ENUM = { + 2: INPUT_TYPE_TOUCH, + 3: INPUT_TYPE_PEN, + 4: INPUT_TYPE_MOUSE, + 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816 + }; + + var POINTER_ELEMENT_EVENTS = 'pointerdown'; + var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; + + // IE10 has prefixed support, and case-sensitive + if (window.MSPointerEvent && !window.PointerEvent) { + POINTER_ELEMENT_EVENTS = 'MSPointerDown'; + POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel'; + } + + /** + * Pointer events input + * @constructor + * @extends Input + */ + function PointerEventInput() { + this.evEl = POINTER_ELEMENT_EVENTS; + this.evWin = POINTER_WINDOW_EVENTS; + + Input.apply(this, arguments); + + this.store = (this.manager.session.pointerEvents = []); + } + + inherit(PointerEventInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function PEhandler(ev) { + var store = this.store; + var removePointer = false; + + var eventTypeNormalized = ev.type.toLowerCase().replace('ms', ''); + var eventType = POINTER_INPUT_MAP[eventTypeNormalized]; + var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType; + + var isTouch = (pointerType == INPUT_TYPE_TOUCH); + + // get index of the event in the store + var storeIndex = inArray(store, ev.pointerId, 'pointerId'); + + // start and mouse must be down + if (eventType & INPUT_START && (ev.button === 0 || isTouch)) { + if (storeIndex < 0) { + store.push(ev); + storeIndex = store.length - 1; + } + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + removePointer = true; + } + + // it not found, so the pointer hasn't been down (so it's probably a hover) + if (storeIndex < 0) { + return; + } + + // update the event in the store + store[storeIndex] = ev; + + this.callback(this.manager, eventType, { + pointers: store, + changedPointers: [ev], + pointerType: pointerType, + srcEvent: ev + }); + + if (removePointer) { + // remove from the store + store.splice(storeIndex, 1); + } + } + }); + + var SINGLE_TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart'; + var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Touch events input + * @constructor + * @extends Input + */ + function SingleTouchInput() { + this.evTarget = SINGLE_TOUCH_TARGET_EVENTS; + this.evWin = SINGLE_TOUCH_WINDOW_EVENTS; + this.started = false; + + Input.apply(this, arguments); + } + + inherit(SingleTouchInput, Input, { + handler: function TEhandler(ev) { + var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; + + // should we handle the touch events? + if (type === INPUT_START) { + this.started = true; + } + + if (!this.started) { + return; + } + + var touches = normalizeSingleTouches.call(this, ev, type); + + // when done, reset the started state + if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) { + this.started = false; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); + + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function normalizeSingleTouches(ev, type) { + var all = toArray(ev.touches); + var changed = toArray(ev.changedTouches); + + if (type & (INPUT_END | INPUT_CANCEL)) { + all = uniqueArray(all.concat(changed), 'identifier', true); + } + + return [all, changed]; + } + + var TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL + }; + + var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel'; + + /** + * Multi-user touch events input + * @constructor + * @extends Input + */ + function TouchInput() { + this.evTarget = TOUCH_TARGET_EVENTS; + this.targetIds = {}; + + Input.apply(this, arguments); + } + + inherit(TouchInput, Input, { + handler: function MTEhandler(ev) { + var type = TOUCH_INPUT_MAP[ev.type]; + var touches = getTouches.call(this, ev, type); + if (!touches) { + return; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } + }); + + /** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ + function getTouches(ev, type) { + var allTouches = toArray(ev.touches); + var targetIds = this.targetIds; + + // when there is only one touch, the process can be simplified + if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) { + targetIds[allTouches[0].identifier] = true; + return [allTouches, allTouches]; + } + + var i, + targetTouches, + changedTouches = toArray(ev.changedTouches), + changedTargetTouches = [], + target = this.target; + + // get target touches from touches + targetTouches = allTouches.filter(function(touch) { + return hasParent(touch.target, target); + }); + + // collect touches + if (type === INPUT_START) { + i = 0; + while (i < targetTouches.length) { + targetIds[targetTouches[i].identifier] = true; + i++; + } + } + + // filter changed touches to only contain touches that exist in the collected target ids + i = 0; + while (i < changedTouches.length) { + if (targetIds[changedTouches[i].identifier]) { + changedTargetTouches.push(changedTouches[i]); + } + + // cleanup removed touches + if (type & (INPUT_END | INPUT_CANCEL)) { + delete targetIds[changedTouches[i].identifier]; + } + i++; + } + + if (!changedTargetTouches.length) { + return; + } + + return [ + // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel' + uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), + changedTargetTouches + ]; + } + + /** + * Combined touch and mouse input + * + * Touch has a higher priority then mouse, and while touching no mouse events are allowed. + * This because touch devices also emit mouse events while doing a touch. + * + * @constructor + * @extends Input + */ + + var DEDUP_TIMEOUT = 2500; + var DEDUP_DISTANCE = 25; + + function TouchMouseInput() { + Input.apply(this, arguments); + + var handler = bindFn(this.handler, this); + this.touch = new TouchInput(this.manager, handler); + this.mouse = new MouseInput(this.manager, handler); + + this.primaryTouch = null; + this.lastTouches = []; + } + + inherit(TouchMouseInput, Input, { + /** + * handle mouse and touch events + * @param {Hammer} manager + * @param {String} inputEvent + * @param {Object} inputData + */ + handler: function TMEhandler(manager, inputEvent, inputData) { + var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), + isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE); + + if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) { + return; + } + + // when we're in a touch event, record touches to de-dupe synthetic mouse event + if (isTouch) { + recordTouches.call(this, inputEvent, inputData); + } else if (isMouse && isSyntheticEvent.call(this, inputData)) { + return; + } + + this.callback(manager, inputEvent, inputData); + }, + + /** + * remove the event listeners + */ + destroy: function destroy() { + this.touch.destroy(); + this.mouse.destroy(); + } + }); + + function recordTouches(eventType, eventData) { + if (eventType & INPUT_START) { + this.primaryTouch = eventData.changedPointers[0].identifier; + setLastTouch.call(this, eventData); + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + setLastTouch.call(this, eventData); + } + } + + function setLastTouch(eventData) { + var touch = eventData.changedPointers[0]; + + if (touch.identifier === this.primaryTouch) { + var lastTouch = {x: touch.clientX, y: touch.clientY}; + this.lastTouches.push(lastTouch); + var lts = this.lastTouches; + var removeLastTouch = function() { + var i = lts.indexOf(lastTouch); + if (i > -1) { + lts.splice(i, 1); + } + }; + setTimeout(removeLastTouch, DEDUP_TIMEOUT); + } + } + + function isSyntheticEvent(eventData) { + var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY; + for (var i = 0; i < this.lastTouches.length; i++) { + var t = this.lastTouches[i]; + var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y); + if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) { + return true; + } + } + return false; + } + + var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction'); + var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined; + + // magical touchAction value + var TOUCH_ACTION_COMPUTE = 'compute'; + var TOUCH_ACTION_AUTO = 'auto'; + var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented + var TOUCH_ACTION_NONE = 'none'; + var TOUCH_ACTION_PAN_X = 'pan-x'; + var TOUCH_ACTION_PAN_Y = 'pan-y'; + var TOUCH_ACTION_MAP = getTouchActionProps(); + + /** + * Touch Action + * sets the touchAction property or uses the js alternative + * @param {Manager} manager + * @param {String} value + * @constructor + */ + function TouchAction(manager, value) { + this.manager = manager; + this.set(value); + } + + TouchAction.prototype = { + /** + * set the touchAction value on the element or enable the polyfill + * @param {String} value + */ + set: function(value) { + // find out the touch-action by the event handlers + if (value == TOUCH_ACTION_COMPUTE) { + value = this.compute(); + } + + if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) { + this.manager.element.style[PREFIXED_TOUCH_ACTION] = value; + } + this.actions = value.toLowerCase().trim(); + }, + + /** + * just re-set the touchAction value + */ + update: function() { + this.set(this.manager.options.touchAction); + }, + + /** + * compute the value for the touchAction property based on the recognizer's settings + * @returns {String} value + */ + compute: function() { + var actions = []; + each(this.manager.recognizers, function(recognizer) { + if (boolOrFn(recognizer.options.enable, [recognizer])) { + actions = actions.concat(recognizer.getTouchAction()); + } + }); + return cleanTouchActions(actions.join(' ')); + }, + + /** + * this method is called on each input cycle and provides the preventing of the browser behavior + * @param {Object} input + */ + preventDefaults: function(input) { + var srcEvent = input.srcEvent; + var direction = input.offsetDirection; + + // if the touch action did prevented once this session + if (this.manager.session.prevented) { + srcEvent.preventDefault(); + return; + } + + var actions = this.actions; + var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE]; + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y]; + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X]; + + if (hasNone) { + //do not prevent defaults if this is a tap gesture + + var isTapPointer = input.pointers.length === 1; + var isTapMovement = input.distance < 2; + var isTapTouchTime = input.deltaTime < 250; + + if (isTapPointer && isTapMovement && isTapTouchTime) { + return; + } + } + + if (hasPanX && hasPanY) { + // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent + return; + } + + if (hasNone || + (hasPanY && direction & DIRECTION_HORIZONTAL) || + (hasPanX && direction & DIRECTION_VERTICAL)) { + return this.preventSrc(srcEvent); + } + }, + + /** + * call preventDefault to prevent the browser's default behavior (scrolling in most cases) + * @param {Object} srcEvent + */ + preventSrc: function(srcEvent) { + this.manager.session.prevented = true; + srcEvent.preventDefault(); + } + }; + + /** + * when the touchActions are collected they are not a valid value, so we need to clean things up. * + * @param {String} actions + * @returns {*} + */ + function cleanTouchActions(actions) { + // none + if (inStr(actions, TOUCH_ACTION_NONE)) { + return TOUCH_ACTION_NONE; + } + + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + + // if both pan-x and pan-y are set (different recognizers + // for different directions, e.g. horizontal pan but vertical swipe?) + // we need none (as otherwise with pan-x pan-y combined none of these + // recognizers will work, since the browser would handle all panning + if (hasPanX && hasPanY) { + return TOUCH_ACTION_NONE; + } + + // pan-x OR pan-y + if (hasPanX || hasPanY) { + return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y; + } + + // manipulation + if (inStr(actions, TOUCH_ACTION_MANIPULATION)) { + return TOUCH_ACTION_MANIPULATION; + } + + return TOUCH_ACTION_AUTO; + } + + function getTouchActionProps() { + if (!NATIVE_TOUCH_ACTION) { + return false; + } + var touchMap = {}; + var cssSupports = window.CSS && window.CSS.supports; + ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) { + + // If css.supports is not supported but there is native touch-action assume it supports + // all values. This is the case for IE 10 and 11. + touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true; + }); + return touchMap; + } + + /** + * Recognizer flow explained; * + * All recognizers have the initial state of POSSIBLE when a input session starts. + * The definition of a input session is from the first input until the last input, with all it's movement in it. * + * Example session for mouse-input: mousedown -> mousemove -> mouseup + * + * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed + * which determines with state it should be. + * + * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to + * POSSIBLE to give it another change on the next cycle. + * + * Possible + * | + * +-----+---------------+ + * | | + * +-----+-----+ | + * | | | + * Failed Cancelled | + * +-------+------+ + * | | + * Recognized Began + * | + * Changed + * | + * Ended/Recognized + */ + var STATE_POSSIBLE = 1; + var STATE_BEGAN = 2; + var STATE_CHANGED = 4; + var STATE_ENDED = 8; + var STATE_RECOGNIZED = STATE_ENDED; + var STATE_CANCELLED = 16; + var STATE_FAILED = 32; + + /** + * Recognizer + * Every recognizer needs to extend from this class. + * @constructor + * @param {Object} options + */ + function Recognizer(options) { + this.options = assign({}, this.defaults, options || {}); + + this.id = uniqueId(); + + this.manager = null; + + // default is enable true + this.options.enable = ifUndefined(this.options.enable, true); + + this.state = STATE_POSSIBLE; + + this.simultaneous = {}; + this.requireFail = []; + } + + Recognizer.prototype = { + /** + * @virtual + * @type {Object} + */ + defaults: {}, + + /** + * set options + * @param {Object} options + * @return {Recognizer} + */ + set: function(options) { + assign(this.options, options); + + // also update the touchAction, in case something changed about the directions/enabled state + this.manager && this.manager.touchAction.update(); + return this; + }, + + /** + * recognize simultaneous with an other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + recognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) { + return this; + } + + var simultaneous = this.simultaneous; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (!simultaneous[otherRecognizer.id]) { + simultaneous[otherRecognizer.id] = otherRecognizer; + otherRecognizer.recognizeWith(this); + } + return this; + }, + + /** + * drop the simultaneous link. it doesnt remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRecognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + delete this.simultaneous[otherRecognizer.id]; + return this; + }, + + /** + * recognizer can only run when an other is failing + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + requireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) { + return this; + } + + var requireFail = this.requireFail; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (inArray(requireFail, otherRecognizer) === -1) { + requireFail.push(otherRecognizer); + otherRecognizer.requireFailure(this); + } + return this; + }, + + /** + * drop the requireFailure link. it does not remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRequireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + var index = inArray(this.requireFail, otherRecognizer); + if (index > -1) { + this.requireFail.splice(index, 1); + } + return this; + }, + + /** + * has require failures boolean + * @returns {boolean} + */ + hasRequireFailures: function() { + return this.requireFail.length > 0; + }, + + /** + * if the recognizer can recognize simultaneous with an other recognizer + * @param {Recognizer} otherRecognizer + * @returns {Boolean} + */ + canRecognizeWith: function(otherRecognizer) { + return !!this.simultaneous[otherRecognizer.id]; + }, + + /** + * You should use `tryEmit` instead of `emit` directly to check + * that all the needed recognizers has failed before emitting. + * @param {Object} input + */ + emit: function(input) { + var self = this; + var state = this.state; + + function emit(event) { + self.manager.emit(event, input); + } + + // 'panstart' and 'panmove' + if (state < STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + + emit(self.options.event); // simple 'eventName' events + + if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...) + emit(input.additionalEvent); + } + + // panend and pancancel + if (state >= STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + }, + + /** + * Check that all the require failure recognizers has failed, + * if true, it emits a gesture event, + * otherwise, setup the state to FAILED. + * @param {Object} input + */ + tryEmit: function(input) { + if (this.canEmit()) { + return this.emit(input); + } + // it's failing anyway + this.state = STATE_FAILED; + }, + + /** + * can we emit? + * @returns {boolean} + */ + canEmit: function() { + var i = 0; + while (i < this.requireFail.length) { + if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) { + return false; + } + i++; + } + return true; + }, + + /** + * update the recognizer + * @param {Object} inputData + */ + recognize: function(inputData) { + // make a new copy of the inputData + // so we can change the inputData without messing up the other recognizers + var inputDataClone = assign({}, inputData); + + // is is enabled and allow recognizing? + if (!boolOrFn(this.options.enable, [this, inputDataClone])) { + this.reset(); + this.state = STATE_FAILED; + return; + } + + // reset when we've reached the end + if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) { + this.state = STATE_POSSIBLE; + } + + this.state = this.process(inputDataClone); + + // the recognizer has recognized a gesture + // so trigger an event + if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) { + this.tryEmit(inputDataClone); + } + }, + + /** + * return the state of the recognizer + * the actual recognizing happens in this method + * @virtual + * @param {Object} inputData + * @returns {Const} STATE + */ + process: function(inputData) { }, // jshint ignore:line + + /** + * return the preferred touch-action + * @virtual + * @returns {Array} + */ + getTouchAction: function() { }, + + /** + * called when the gesture isn't allowed to recognize + * like when another is being recognized or it is disabled + * @virtual + */ + reset: function() { } + }; + + /** + * get a usable string, used as event postfix + * @param {Const} state + * @returns {String} state + */ + function stateStr(state) { + if (state & STATE_CANCELLED) { + return 'cancel'; + } else if (state & STATE_ENDED) { + return 'end'; + } else if (state & STATE_CHANGED) { + return 'move'; + } else if (state & STATE_BEGAN) { + return 'start'; + } + return ''; + } + + /** + * direction cons to string + * @param {Const} direction + * @returns {String} + */ + function directionStr(direction) { + if (direction == DIRECTION_DOWN) { + return 'down'; + } else if (direction == DIRECTION_UP) { + return 'up'; + } else if (direction == DIRECTION_LEFT) { + return 'left'; + } else if (direction == DIRECTION_RIGHT) { + return 'right'; + } + return ''; + } + + /** + * get a recognizer by name if it is bound to a manager + * @param {Recognizer|String} otherRecognizer + * @param {Recognizer} recognizer + * @returns {Recognizer} + */ + function getRecognizerByNameIfManager(otherRecognizer, recognizer) { + var manager = recognizer.manager; + if (manager) { + return manager.get(otherRecognizer); + } + return otherRecognizer; + } + + /** + * This recognizer is just used as a base for the simple attribute recognizers. + * @constructor + * @extends Recognizer + */ + function AttrRecognizer() { + Recognizer.apply(this, arguments); + } + + inherit(AttrRecognizer, Recognizer, { + /** + * @namespace + * @memberof AttrRecognizer + */ + defaults: { + /** + * @type {Number} + * @default 1 + */ + pointers: 1 + }, + + /** + * Used to check if it the recognizer receives valid input, like input.distance > 10. + * @memberof AttrRecognizer + * @param {Object} input + * @returns {Boolean} recognized + */ + attrTest: function(input) { + var optionPointers = this.options.pointers; + return optionPointers === 0 || input.pointers.length === optionPointers; + }, + + /** + * Process the input and return the state for the recognizer + * @memberof AttrRecognizer + * @param {Object} input + * @returns {*} State + */ + process: function(input) { + var state = this.state; + var eventType = input.eventType; + + var isRecognized = state & (STATE_BEGAN | STATE_CHANGED); + var isValid = this.attrTest(input); + + // on cancel input and we've recognized before, return STATE_CANCELLED + if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) { + return state | STATE_CANCELLED; + } else if (isRecognized || isValid) { + if (eventType & INPUT_END) { + return state | STATE_ENDED; + } else if (!(state & STATE_BEGAN)) { + return STATE_BEGAN; + } + return state | STATE_CHANGED; + } + return STATE_FAILED; + } + }); + + /** + * Pan + * Recognized when the pointer is down and moved in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function PanRecognizer() { + AttrRecognizer.apply(this, arguments); + + this.pX = null; + this.pY = null; + } + + inherit(PanRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PanRecognizer + */ + defaults: { + event: 'pan', + threshold: 10, + pointers: 1, + direction: DIRECTION_ALL + }, + + getTouchAction: function() { + var direction = this.options.direction; + var actions = []; + if (direction & DIRECTION_HORIZONTAL) { + actions.push(TOUCH_ACTION_PAN_Y); + } + if (direction & DIRECTION_VERTICAL) { + actions.push(TOUCH_ACTION_PAN_X); + } + return actions; + }, + + directionTest: function(input) { + var options = this.options; + var hasMoved = true; + var distance = input.distance; + var direction = input.direction; + var x = input.deltaX; + var y = input.deltaY; + + // lock to axis? + if (!(direction & options.direction)) { + if (options.direction & DIRECTION_HORIZONTAL) { + direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + hasMoved = x != this.pX; + distance = Math.abs(input.deltaX); + } else { + direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN; + hasMoved = y != this.pY; + distance = Math.abs(input.deltaY); + } + } + input.direction = direction; + return hasMoved && distance > options.threshold && direction & options.direction; + }, + + attrTest: function(input) { + return AttrRecognizer.prototype.attrTest.call(this, input) && + (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input))); + }, + + emit: function(input) { + + this.pX = input.deltaX; + this.pY = input.deltaY; + + var direction = directionStr(input.direction); + + if (direction) { + input.additionalEvent = this.options.event + direction; + } + this._super.emit.call(this, input); + } + }); + + /** + * Pinch + * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out). + * @constructor + * @extends AttrRecognizer + */ + function PinchRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(PinchRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'pinch', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN); + }, + + emit: function(input) { + if (input.scale !== 1) { + var inOut = input.scale < 1 ? 'in' : 'out'; + input.additionalEvent = this.options.event + inOut; + } + this._super.emit.call(this, input); + } + }); + + /** + * Press + * Recognized when the pointer is down for x ms without any movement. + * @constructor + * @extends Recognizer + */ + function PressRecognizer() { + Recognizer.apply(this, arguments); + + this._timer = null; + this._input = null; + } + + inherit(PressRecognizer, Recognizer, { + /** + * @namespace + * @memberof PressRecognizer + */ + defaults: { + event: 'press', + pointers: 1, + time: 251, // minimal time of the pointer to be pressed + threshold: 9 // a minimal movement is ok, but keep it low + }, + + getTouchAction: function() { + return [TOUCH_ACTION_AUTO]; + }, + + process: function(input) { + var options = this.options; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTime = input.deltaTime > options.time; + + this._input = input; + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) { + this.reset(); + } else if (input.eventType & INPUT_START) { + this.reset(); + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.time, this); + } else if (input.eventType & INPUT_END) { + return STATE_RECOGNIZED; + } + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function(input) { + if (this.state !== STATE_RECOGNIZED) { + return; + } + + if (input && (input.eventType & INPUT_END)) { + this.manager.emit(this.options.event + 'up', input); + } else { + this._input.timeStamp = now(); + this.manager.emit(this.options.event, this._input); + } + } + }); + + /** + * Rotate + * Recognized when two or more pointer are moving in a circular motion. + * @constructor + * @extends AttrRecognizer + */ + function RotateRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(RotateRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof RotateRecognizer + */ + defaults: { + event: 'rotate', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN); + } + }); + + /** + * Swipe + * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ + function SwipeRecognizer() { + AttrRecognizer.apply(this, arguments); + } + + inherit(SwipeRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof SwipeRecognizer + */ + defaults: { + event: 'swipe', + threshold: 10, + velocity: 0.3, + direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL, + pointers: 1 + }, + + getTouchAction: function() { + return PanRecognizer.prototype.getTouchAction.call(this); + }, + + attrTest: function(input) { + var direction = this.options.direction; + var velocity; + + if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) { + velocity = input.overallVelocity; + } else if (direction & DIRECTION_HORIZONTAL) { + velocity = input.overallVelocityX; + } else if (direction & DIRECTION_VERTICAL) { + velocity = input.overallVelocityY; + } + + return this._super.attrTest.call(this, input) && + direction & input.offsetDirection && + input.distance > this.options.threshold && + input.maxPointers == this.options.pointers && + abs(velocity) > this.options.velocity && input.eventType & INPUT_END; + }, + + emit: function(input) { + var direction = directionStr(input.offsetDirection); + if (direction) { + this.manager.emit(this.options.event + direction, input); + } + + this.manager.emit(this.options.event, input); + } + }); + + /** + * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur + * between the given interval and position. The delay option can be used to recognize multi-taps without firing + * a single tap. + * + * The eventData from the emitted event contains the property `tapCount`, which contains the amount of + * multi-taps being recognized. + * @constructor + * @extends Recognizer + */ + function TapRecognizer() { + Recognizer.apply(this, arguments); + + // previous time and center, + // used for tap counting + this.pTime = false; + this.pCenter = false; + + this._timer = null; + this._input = null; + this.count = 0; + } + + inherit(TapRecognizer, Recognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'tap', + pointers: 1, + taps: 1, + interval: 300, // max time between the multi-tap taps + time: 250, // max time of the pointer to be down (like finger on the screen) + threshold: 9, // a minimal movement is ok, but keep it low + posThreshold: 10 // a multi-tap can be a bit off the initial position + }, + + getTouchAction: function() { + return [TOUCH_ACTION_MANIPULATION]; + }, + + process: function(input) { + var options = this.options; + + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTouchTime = input.deltaTime < options.time; + + this.reset(); + + if ((input.eventType & INPUT_START) && (this.count === 0)) { + return this.failTimeout(); + } + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (validMovement && validTouchTime && validPointers) { + if (input.eventType != INPUT_END) { + return this.failTimeout(); + } + + var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true; + var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold; + + this.pTime = input.timeStamp; + this.pCenter = input.center; + + if (!validMultiTap || !validInterval) { + this.count = 1; + } else { + this.count += 1; + } + + this._input = input; + + // if tap count matches we have recognized it, + // else it has began recognizing... + var tapCount = this.count % options.taps; + if (tapCount === 0) { + // no failing requirements, immediately trigger the tap event + // or wait as long as the multitap interval to trigger + if (!this.hasRequireFailures()) { + return STATE_RECOGNIZED; + } else { + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.interval, this); + return STATE_BEGAN; + } + } + } + return STATE_FAILED; + }, + + failTimeout: function() { + this._timer = setTimeoutContext(function() { + this.state = STATE_FAILED; + }, this.options.interval, this); + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function() { + if (this.state == STATE_RECOGNIZED) { + this._input.tapCount = this.count; + this.manager.emit(this.options.event, this._input); + } + } + }); + + /** + * Simple way to create a manager with a default set of recognizers. + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ + function Hammer(element, options) { + options = options || {}; + options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset); + return new Manager(element, options); + } + + /** + * @const {string} + */ + Hammer.VERSION = '2.0.7'; + + /** + * default settings + * @namespace + */ + Hammer.defaults = { + /** + * set if DOM events are being triggered. + * But this is slower and unused by simple implementations, so disabled by default. + * @type {Boolean} + * @default false + */ + domEvents: false, + + /** + * The value for the touchAction property/fallback. + * When set to `compute` it will magically set the correct value based on the added recognizers. + * @type {String} + * @default compute + */ + touchAction: TOUCH_ACTION_COMPUTE, + + /** + * @type {Boolean} + * @default true + */ + enable: true, + + /** + * EXPERIMENTAL FEATURE -- can be removed/changed + * Change the parent input target element. + * If Null, then it is being set the to main element. + * @type {Null|EventTarget} + * @default null + */ + inputTarget: null, + + /** + * force an input class + * @type {Null|Function} + * @default null + */ + inputClass: null, + + /** + * Default recognizer setup when calling `Hammer()` + * When creating a new Manager these will be skipped. + * @type {Array} + */ + preset: [ + // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...] + [RotateRecognizer, {enable: false}], + [PinchRecognizer, {enable: false}, ['rotate']], + [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}], + [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']], + [TapRecognizer], + [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']], + [PressRecognizer] + ], + + /** + * Some CSS properties can be used to improve the working of Hammer. + * Add them to this method and they will be set when creating a new Manager. + * @namespace + */ + cssProps: { + /** + * Disables text selection to improve the dragging gesture. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userSelect: 'none', + + /** + * Disable the Windows Phone grippers when pressing an element. + * @type {String} + * @default 'none' + */ + touchSelect: 'none', + + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @type {String} + * @default 'none' + */ + touchCallout: 'none', + + /** + * Specifies whether zooming is enabled. Used by IE10> + * @type {String} + * @default 'none' + */ + contentZooming: 'none', + + /** + * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userDrag: 'none', + + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in iOS. This property obeys the alpha value, if specified. + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } + }; + + var STOP = 1; + var FORCED_STOP = 2; + + /** + * Manager + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ + function Manager(element, options) { + this.options = assign({}, Hammer.defaults, options || {}); + + this.options.inputTarget = this.options.inputTarget || element; + + this.handlers = {}; + this.session = {}; + this.recognizers = []; + this.oldCssProps = {}; + + this.element = element; + this.input = createInputInstance(this); + this.touchAction = new TouchAction(this, this.options.touchAction); + + toggleCssProps(this, true); + + each(this.options.recognizers, function(item) { + var recognizer = this.add(new (item[0])(item[1])); + item[2] && recognizer.recognizeWith(item[2]); + item[3] && recognizer.requireFailure(item[3]); + }, this); + } + + Manager.prototype = { + /** + * set options + * @param {Object} options + * @returns {Manager} + */ + set: function(options) { + assign(this.options, options); + + // Options that need a little more setup + if (options.touchAction) { + this.touchAction.update(); + } + if (options.inputTarget) { + // Clean up existing event listeners and reinitialize + this.input.destroy(); + this.input.target = options.inputTarget; + this.input.init(); + } + return this; + }, + + /** + * stop recognizing for this session. + * This session will be discarded, when a new [input]start event is fired. + * When forced, the recognizer cycle is stopped immediately. + * @param {Boolean} [force] + */ + stop: function(force) { + this.session.stopped = force ? FORCED_STOP : STOP; + }, + + /** + * run the recognizers! + * called by the inputHandler function on every movement of the pointers (touches) + * it walks through all the recognizers and tries to detect the gesture that is being made + * @param {Object} inputData + */ + recognize: function(inputData) { + var session = this.session; + if (session.stopped) { + return; + } + + // run the touch-action polyfill + this.touchAction.preventDefaults(inputData); + + var recognizer; + var recognizers = this.recognizers; + + // this holds the recognizer that is being recognized. + // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED + // if no recognizer is detecting a thing, it is set to `null` + var curRecognizer = session.curRecognizer; + + // reset when the last recognizer is recognized + // or when we're in a new session + if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) { + curRecognizer = session.curRecognizer = null; + } + + var i = 0; + while (i < recognizers.length) { + recognizer = recognizers[i]; + + // find out if we are allowed try to recognize the input for this one. + // 1. allow if the session is NOT forced stopped (see the .stop() method) + // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one + // that is being recognized. + // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer. + // this can be setup with the `recognizeWith()` method on the recognizer. + if (session.stopped !== FORCED_STOP && ( // 1 + !curRecognizer || recognizer == curRecognizer || // 2 + recognizer.canRecognizeWith(curRecognizer))) { // 3 + recognizer.recognize(inputData); + } else { + recognizer.reset(); + } + + // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the + // current active recognizer. but only if we don't already have an active recognizer + if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) { + curRecognizer = session.curRecognizer = recognizer; + } + i++; + } + }, + + /** + * get a recognizer by its event name. + * @param {Recognizer|String} recognizer + * @returns {Recognizer|Null} + */ + get: function(recognizer) { + if (recognizer instanceof Recognizer) { + return recognizer; + } + + var recognizers = this.recognizers; + for (var i = 0; i < recognizers.length; i++) { + if (recognizers[i].options.event == recognizer) { + return recognizers[i]; + } + } + return null; + }, + + /** + * add a recognizer to the manager + * existing recognizers with the same event name will be removed + * @param {Recognizer} recognizer + * @returns {Recognizer|Manager} + */ + add: function(recognizer) { + if (invokeArrayArg(recognizer, 'add', this)) { + return this; + } + + // remove existing + var existing = this.get(recognizer.options.event); + if (existing) { + this.remove(existing); + } + + this.recognizers.push(recognizer); + recognizer.manager = this; + + this.touchAction.update(); + return recognizer; + }, + + /** + * remove a recognizer by name or instance + * @param {Recognizer|String} recognizer + * @returns {Manager} + */ + remove: function(recognizer) { + if (invokeArrayArg(recognizer, 'remove', this)) { + return this; + } + + recognizer = this.get(recognizer); + + // let's make sure this recognizer exists + if (recognizer) { + var recognizers = this.recognizers; + var index = inArray(recognizers, recognizer); + + if (index !== -1) { + recognizers.splice(index, 1); + this.touchAction.update(); + } + } + + return this; + }, + + /** + * bind event + * @param {String} events + * @param {Function} handler + * @returns {EventEmitter} this + */ + on: function(events, handler) { + if (events === undefined) { + return; + } + if (handler === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + }); + return this; + }, + + /** + * unbind event, leave emit blank to remove all handlers + * @param {String} events + * @param {Function} [handler] + * @returns {EventEmitter} this + */ + off: function(events, handler) { + if (events === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + if (!handler) { + delete handlers[event]; + } else { + handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1); + } + }); + return this; + }, + + /** + * emit event to the listeners + * @param {String} event + * @param {Object} data + */ + emit: function(event, data) { + // we also want to trigger dom events + if (this.options.domEvents) { + triggerDomEvent(event, data); + } + + // no handlers, so skip it all + var handlers = this.handlers[event] && this.handlers[event].slice(); + if (!handlers || !handlers.length) { + return; + } + + data.type = event; + data.preventDefault = function() { + data.srcEvent.preventDefault(); + }; + + var i = 0; + while (i < handlers.length) { + handlers[i](data); + i++; + } + }, + + /** + * destroy the manager and unbinds all events + * it doesn't unbind dom events, that is the user own responsibility + */ + destroy: function() { + this.element && toggleCssProps(this, false); + + this.handlers = {}; + this.session = {}; + this.input.destroy(); + this.element = null; + } + }; + + /** + * add/remove the css properties as defined in manager.options.cssProps + * @param {Manager} manager + * @param {Boolean} add + */ + function toggleCssProps(manager, add) { + var element = manager.element; + if (!element.style) { + return; + } + var prop; + each(manager.options.cssProps, function(value, name) { + prop = prefixed(element.style, name); + if (add) { + manager.oldCssProps[prop] = element.style[prop]; + element.style[prop] = value; + } else { + element.style[prop] = manager.oldCssProps[prop] || ''; + } + }); + if (!add) { + manager.oldCssProps = {}; + } + } + + /** + * trigger dom event + * @param {String} event + * @param {Object} data + */ + function triggerDomEvent(event, data) { + var gestureEvent = document.createEvent('Event'); + gestureEvent.initEvent(event, true, true); + gestureEvent.gesture = data; + data.target.dispatchEvent(gestureEvent); + } + + assign(Hammer, { + INPUT_START: INPUT_START, + INPUT_MOVE: INPUT_MOVE, + INPUT_END: INPUT_END, + INPUT_CANCEL: INPUT_CANCEL, + + STATE_POSSIBLE: STATE_POSSIBLE, + STATE_BEGAN: STATE_BEGAN, + STATE_CHANGED: STATE_CHANGED, + STATE_ENDED: STATE_ENDED, + STATE_RECOGNIZED: STATE_RECOGNIZED, + STATE_CANCELLED: STATE_CANCELLED, + STATE_FAILED: STATE_FAILED, + + DIRECTION_NONE: DIRECTION_NONE, + DIRECTION_LEFT: DIRECTION_LEFT, + DIRECTION_RIGHT: DIRECTION_RIGHT, + DIRECTION_UP: DIRECTION_UP, + DIRECTION_DOWN: DIRECTION_DOWN, + DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL: DIRECTION_VERTICAL, + DIRECTION_ALL: DIRECTION_ALL, + + Manager: Manager, + Input: Input, + TouchAction: TouchAction, + + TouchInput: TouchInput, + MouseInput: MouseInput, + PointerEventInput: PointerEventInput, + TouchMouseInput: TouchMouseInput, + SingleTouchInput: SingleTouchInput, + + Recognizer: Recognizer, + AttrRecognizer: AttrRecognizer, + Tap: TapRecognizer, + Pan: PanRecognizer, + Swipe: SwipeRecognizer, + Pinch: PinchRecognizer, + Rotate: RotateRecognizer, + Press: PressRecognizer, + + on: addEventListeners, + off: removeEventListeners, + each: each, + merge: merge, + extend: extend, + assign: assign, + inherit: inherit, + bindFn: bindFn, + prefixed: prefixed + }); + + // jquery.hammer.js + // This jQuery plugin is just a small wrapper around the Hammer() class. + // It also extends the Manager.emit method by triggering jQuery events. + // $(element).hammer(options).bind("pan", myPanHandler); + // The Hammer instance is stored at $element.data("hammer"). + // https://github.com/hammerjs/jquery.hammer.js + + (function($, Hammer) { + function hammerify(el, options) { + var $el = $(el); + if (!$el.data('hammer')) { + $el.data('hammer', new Hammer($el[0], options)); + } + } + + $.fn.hammer = function(options) { + return this.each(function() { + hammerify(this, options); + }); + }; + + // extend the emit method to also trigger jQuery events + Hammer.Manager.prototype.emit = (function(originalEmit) { + return function(type, data) { + originalEmit.call(this, type, data); + $(this.element).trigger({ + type: type, + gesture: data + }); + }; + })(Hammer.Manager.prototype.emit); + })($, Hammer); + + module.exports = UI.Hammer = Hammer; + + +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var UI = __webpack_require__(2); + + /** + * Add to Homescreen v3.2.2 + * (c) 2015 Matteo Spinelli + * @license: http://cubiq.org/license + */ + + // Check for addEventListener browser support (prevent errors in IE<9) + var _eventListener = 'addEventListener' in window; + + // Check if document is loaded, needed by autostart + var _DOMReady = false; + if (document.readyState === 'complete') { + _DOMReady = true; + } else if (_eventListener) { + window.addEventListener('load', loaded, false); + } + + function loaded() { + window.removeEventListener('load', loaded, false); + _DOMReady = true; + } + + // regex used to detect if app has been added to the homescreen + var _reSmartURL = /\/ath(\/)?$/; + var _reQueryString = /([\?&]ath=[^&]*$|&ath=[^&]*(&))/; + + // singleton + var _instance; + function ath(options) { + _instance = _instance || new ath.Class(options); + + return _instance; + } + + // message in all supported languages + ath.intl = { + en_us: { + ios: 'To add this web app to the home screen: tap %icon and then Add to Home Screen.', + android: 'To add this web app to the home screen open the browser option menu and tap on Add to homescreen. The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon icon.' + }, + + zh_cn: { + ios: '如要把应用程式加至主屏幕,请点击%icon, 然后加至主屏幕', + android: 'To add this web app to the home screen open the browser option menu and tap on Add to homescreen. The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon icon.' + }, + + zh_tw: { + ios: '如要把應用程式加至主屏幕, 請點擊%icon, 然後加至主屏幕.', + android: 'To add this web app to the home screen open the browser option menu and tap on Add to homescreen. The menu can be accessed by pressing the menu hardware button if your device has one, or by tapping the top right menu icon icon.' + } + }; + + // Add 2 characters language support (Android mostly) + for (var lang in ath.intl) { + ath.intl[lang.substr(0, 2)] = ath.intl[lang]; + } + + // default options + ath.defaults = { + appID: 'org.cubiq.addtohome', // local storage name (no need to change) + fontSize: 15, // base font size, used to properly resize the popup based on viewport scale factor + debug: false, // override browser checks + logging: false, // log reasons for showing or not showing to js console; defaults to true when debug is true + modal: false, // prevent further actions until the message is closed + mandatory: false, // you can't proceed if you don't add the app to the homescreen + autostart: true, // show the message automatically + skipFirstVisit: false, // show only to returning visitors (ie: skip the first time you visit) + startDelay: 1, // display the message after that many seconds from page load + lifespan: 15, // life of the message in seconds + displayPace: 1440, // minutes before the message is shown again (0: display every time, default 24 hours) + maxDisplayCount: 0, // absolute maximum number of times the message will be shown to the user (0: no limit) + icon: true, // add touch icon to the message + message: '', // the message can be customized + validLocation: [], // list of pages where the message will be shown (array of regexes) + onInit: null, // executed on instance creation + onShow: null, // executed when the message is shown + onRemove: null, // executed when the message is removed + onAdd: null, // when the application is launched the first time from the homescreen (guesstimate) + onPrivate: null, // executed if user is in private mode + privateModeOverride: false, // show the message even in private mode (very rude) + detectHomescreen: false // try to detect if the site has been added to the homescreen (false | true | 'hash' | 'queryString' | 'smartURL') + }; + + // browser info and capability + var _ua = window.navigator.userAgent; + + var _nav = window.navigator; + _extend(ath, { + hasToken: document.location.hash == '#ath' || _reSmartURL.test(document.location.href) || _reQueryString.test(document.location.search), + isRetina: window.devicePixelRatio && window.devicePixelRatio > 1, + isIDevice: (/iphone|ipod|ipad/i).test(_ua), + isMobileChrome: _ua.indexOf('Android') > -1 && (/Chrome\/[.0-9]*/).test(_ua) && _ua.indexOf("Version") == -1, + isMobileIE: _ua.indexOf('Windows Phone') > -1, + language: _nav.language && _nav.language.toLowerCase().replace('-', '_') || '' + }); + + // falls back to en_us if language is unsupported + ath.language = ath.language && ath.language in ath.intl ? ath.language : 'en_us'; + + ath.isMobileSafari = ath.isIDevice && _ua.indexOf('Safari') > -1 && _ua.indexOf('CriOS') < 0; + ath.OS = ath.isIDevice ? 'ios' : ath.isMobileChrome ? 'android' : ath.isMobileIE ? 'windows' : 'unsupported'; + + ath.OSVersion = _ua.match(/(OS|Android) (\d+[_\.]\d+)/); + ath.OSVersion = ath.OSVersion && ath.OSVersion[2] ? +ath.OSVersion[2].replace('_', '.') : 0; + + ath.isStandalone = 'standalone' in window.navigator && window.navigator.standalone; + ath.isTablet = (ath.isMobileSafari && _ua.indexOf('iPad') > -1) || (ath.isMobileChrome && _ua.indexOf('Mobile') < 0); + + ath.isCompatible = (ath.isMobileSafari && ath.OSVersion >= 6) || ath.isMobileChrome; // TODO: add winphone + + var _defaultSession = { + lastDisplayTime: 0, // last time we displayed the message + returningVisitor: false, // is this the first time you visit + displayCount: 0, // number of times the message has been shown + optedout: false, // has the user opted out + added: false // has been actually added to the homescreen + }; + + ath.removeSession = function(appID) { + try { + if (!localStorage) { + throw new Error('localStorage is not defined'); + } + + localStorage.removeItem(appID || ath.defaults.appID); + } catch (e) { + // we are most likely in private mode + } + }; + + ath.doLog = function(logStr) { + if (this.options.logging) { + console.log(logStr); + } + }; + + ath.Class = function(options) { + // class methods + this.doLog = ath.doLog; + + // merge default options with user config + this.options = _extend({}, ath.defaults); + _extend(this.options, options); + // override defaults that are dependent on each other + if (this.options.debug) { + this.options.logging = true; + } + + // IE<9 so exit (I hate you, really) + if (!_eventListener) { + return; + } + + // normalize some options + this.options.mandatory = this.options.mandatory && ( 'standalone' in window.navigator || this.options.debug ); + this.options.modal = this.options.modal || this.options.mandatory; + if (this.options.mandatory) { + this.options.startDelay = -0.5; // make the popup hasty + } + this.options.detectHomescreen = this.options.detectHomescreen === true ? 'hash' : this.options.detectHomescreen; + + // setup the debug environment + if (this.options.debug) { + ath.isCompatible = true; + ath.OS = typeof this.options.debug == 'string' ? this.options.debug : ath.OS == 'unsupported' ? 'android' : ath.OS; + ath.OSVersion = ath.OS == 'ios' ? '8' : '4'; + } + + // the element the message will be appended to + this.container = document.documentElement; + + // load session + this.session = this.getItem(this.options.appID); + this.session = this.session ? JSON.parse(this.session) : undefined; + + // user most likely came from a direct link containing our token, we don't need it and we remove it + if (ath.hasToken && ( !ath.isCompatible || !this.session )) { + ath.hasToken = false; + _removeToken(); + } + + // the device is not supported + if (!ath.isCompatible) { + this.doLog("Add to homescreen: not displaying callout because device not supported"); + return; + } + + this.session = this.session || _defaultSession; + + // check if we can use the local storage + try { + if (!localStorage) { + throw new Error('localStorage is not defined'); + } + + localStorage.setItem(this.options.appID, JSON.stringify(this.session)); + ath.hasLocalStorage = true; + } catch (e) { + // we are most likely in private mode + ath.hasLocalStorage = false; + + if (this.options.onPrivate) { + this.options.onPrivate.call(this); + } + } + + // check if this is a valid location + var isValidLocation = !this.options.validLocation.length; + for (var i = this.options.validLocation.length; i--;) { + if (this.options.validLocation[i].test(document.location.href)) { + isValidLocation = true; + break; + } + } + + // check compatibility with old versions of add to homescreen. Opt-out if an old session is found + if (this.getItem('addToHome')) { + this.optOut(); + } + + // critical errors: + if (this.session.optedout) { + this.doLog("Add to homescreen: not displaying callout because user opted out"); + return; + } + if (this.session.added) { + this.doLog("Add to homescreen: not displaying callout because already added to the homescreen"); + return; + } + if (!isValidLocation) { + this.doLog("Add to homescreen: not displaying callout because not a valid location"); + return; + } + + // check if the app is in stand alone mode + if (ath.isStandalone) { + // execute the onAdd event if we haven't already + if (!this.session.added) { + this.session.added = true; + this.updateSession(); + + if (this.options.onAdd && ath.hasLocalStorage) { // double check on localstorage to avoid multiple calls to the custom event + this.options.onAdd.call(this); + } + } + + this.doLog("Add to homescreen: not displaying callout because in standalone mode"); + return; + } + + // (try to) check if the page has been added to the homescreen + if (this.options.detectHomescreen) { + // the URL has the token, we are likely coming from the homescreen + if (ath.hasToken) { + _removeToken(); // we don't actually need the token anymore, we remove it to prevent redistribution + + // this is called the first time the user opens the app from the homescreen + if (!this.session.added) { + this.session.added = true; + this.updateSession(); + + if (this.options.onAdd && ath.hasLocalStorage) { // double check on localstorage to avoid multiple calls to the custom event + this.options.onAdd.call(this); + } + } + + this.doLog("Add to homescreen: not displaying callout because URL has token, so we are likely coming from homescreen"); + return; + } + + // URL doesn't have the token, so add it + if (this.options.detectHomescreen == 'hash') { + history.replaceState('', window.document.title, document.location.href + '#ath'); + } else if (this.options.detectHomescreen == 'smartURL') { + history.replaceState('', window.document.title, document.location.href.replace(/(\/)?$/, '/ath$1')); + } else { + history.replaceState('', window.document.title, document.location.href + (document.location.search ? '&' : '?' ) + 'ath='); + } + } + + // check if this is a returning visitor + if (!this.session.returningVisitor) { + this.session.returningVisitor = true; + this.updateSession(); + + // we do not show the message if this is your first visit + if (this.options.skipFirstVisit) { + this.doLog("Add to homescreen: not displaying callout because skipping first visit"); + return; + } + } + + // we do no show the message in private mode + if (!this.options.privateModeOverride && !ath.hasLocalStorage) { + this.doLog("Add to homescreen: not displaying callout because browser is in private mode"); + return; + } + + // all checks passed, ready to display + this.ready = true; + + if (this.options.onInit) { + this.options.onInit.call(this); + } + + if (this.options.autostart) { + this.doLog("Add to homescreen: autostart displaying callout"); + this.show(); + } + }; + + ath.Class.prototype = { + // event type to method conversion + events: { + load: '_delayedShow', + error: '_delayedShow', + orientationchange: 'resize', + resize: 'resize', + scroll: 'resize', + click: 'remove', + touchmove: '_preventDefault', + transitionend: '_removeElements', + webkitTransitionEnd: '_removeElements', + MSTransitionEnd: '_removeElements' + }, + + handleEvent: function(e) { + var type = this.events[e.type]; + if (type) { + this[type](e); + } + }, + + show: function(force) { + // in autostart mode wait for the document to be ready + if (this.options.autostart && !_DOMReady) { + setTimeout(this.show.bind(this), 50); + // we are not displaying callout because DOM not ready, but don't log that because + // it would log too frequently + return; + } + + // message already on screen + if (this.shown) { + this.doLog("Add to homescreen: not displaying callout because already shown on screen"); + return; + } + + var now = Date.now(); + var lastDisplayTime = this.session.lastDisplayTime; + + if (force !== true) { + // this is needed if autostart is disabled and you programmatically call the show() method + if (!this.ready) { + this.doLog("Add to homescreen: not displaying callout because not ready"); + return; + } + + // we obey the display pace (prevent the message to popup too often) + if (now - lastDisplayTime < this.options.displayPace * 60000) { + this.doLog("Add to homescreen: not displaying callout because displayed recently"); + return; + } + + // obey the maximum number of display count + if (this.options.maxDisplayCount && this.session.displayCount >= this.options.maxDisplayCount) { + this.doLog("Add to homescreen: not displaying callout because displayed too many times already"); + return; + } + } + + this.shown = true; + + // increment the display count + this.session.lastDisplayTime = now; + this.session.displayCount++; + this.updateSession(); + + // try to get the highest resolution application icon + if (!this.applicationIcon) { + if (ath.OS == 'ios') { + this.applicationIcon = document.querySelector('head link[rel^=apple-touch-icon][sizes="152x152"],head link[rel^=apple-touch-icon][sizes="144x144"],head link[rel^=apple-touch-icon][sizes="120x120"],head link[rel^=apple-touch-icon][sizes="114x114"],head link[rel^=apple-touch-icon]'); + } else { + this.applicationIcon = document.querySelector('head link[rel^="shortcut icon"][sizes="196x196"],head link[rel^=apple-touch-icon]'); + } + } + + var message = ''; + + if (typeof this.options.message == 'object' && ath.language in this.options.message) { // use custom language message + message = this.options.message[ath.language][ath.OS]; + } else if (typeof this.options.message == 'object' && ath.OS in this.options.message) { // use custom os message + message = this.options.message[ath.OS]; + } else if (this.options.message in ath.intl) { // you can force the locale + message = ath.intl[this.options.message][ath.OS]; + } else if (this.options.message !== '') { // use a custom message + message = this.options.message; + } else if (ath.OS in ath.intl[ath.language]) { // otherwise we use our message + message = ath.intl[ath.language][ath.OS]; + } + + // add the action icon + message = '

' + message.replace('%icon', 'icon') + '

'; + + // create the message container + this.viewport = document.createElement('div'); + this.viewport.className = 'ath-viewport'; + if (this.options.modal) { + this.viewport.className += ' ath-modal'; + } + if (this.options.mandatory) { + this.viewport.className += ' ath-mandatory'; + } + this.viewport.style.position = 'absolute'; + + // create the actual message element + this.element = document.createElement('div'); + this.element.className = 'ath-container ath-' + ath.OS + ' ath-' + ath.OS + (ath.OSVersion + '').substr(0, 1) + ' ath-' + (ath.isTablet ? 'tablet' : 'phone'); + this.element.style.cssText = '-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0s;-webkit-transition-timing-function:ease-out;transition-property:transform,opacity;transition-duration:0s;transition-timing-function:ease-out;'; + this.element.style.webkitTransform = 'translate3d(0,-' + window.innerHeight + 'px,0)'; + this.element.style.transform = 'translate3d(0,-' + window.innerHeight + 'px,0)'; + + // add the application icon + if (this.options.icon && this.applicationIcon) { + this.element.className += ' ath-icon'; + this.img = document.createElement('img'); + this.img.className = 'ath-application-icon'; + this.img.addEventListener('load', this, false); + this.img.addEventListener('error', this, false); + + this.img.src = this.applicationIcon.href; + this.element.appendChild(this.img); + } + + this.element.innerHTML += message; + + // we are not ready to show, place the message out of sight + this.viewport.style.left = '-99999em'; + + // attach all elements to the DOM + this.viewport.appendChild(this.element); + this.container.appendChild(this.viewport); + + // if we don't have to wait for an image to load, show the message right away + if (this.img) { + this.doLog("Add to homescreen: not displaying callout because waiting for img to load"); + } else { + this._delayedShow(); + } + }, + + _delayedShow: function(e) { + setTimeout(this._show.bind(this), this.options.startDelay * 1000 + 500); + }, + + _show: function() { + var that = this; + + // update the viewport size and orientation + this.updateViewport(); + + // reposition/resize the message on orientation change + window.addEventListener('resize', this, false); + window.addEventListener('scroll', this, false); + window.addEventListener('orientationchange', this, false); + + if (this.options.modal) { + // lock any other interaction + document.addEventListener('touchmove', this, true); + } + + // Enable closing after 1 second + if (!this.options.mandatory) { + setTimeout(function() { + that.element.addEventListener('click', that, true); + }, 1000); + } + + // kick the animation + setTimeout(function() { + that.element.style.webkitTransitionDuration = '1.2s'; + that.element.style.transitionDuration = '1.2s'; + that.element.style.webkitTransform = 'translate3d(0,0,0)'; + that.element.style.transform = 'translate3d(0,0,0)'; + }, 0); + + // set the destroy timer + if (this.options.lifespan) { + this.removeTimer = setTimeout(this.remove.bind(this), this.options.lifespan * 1000); + } + + // fire the custom onShow event + if (this.options.onShow) { + this.options.onShow.call(this); + } + }, + + remove: function() { + clearTimeout(this.removeTimer); + + // clear up the event listeners + if (this.img) { + this.img.removeEventListener('load', this, false); + this.img.removeEventListener('error', this, false); + } + + window.removeEventListener('resize', this, false); + window.removeEventListener('scroll', this, false); + window.removeEventListener('orientationchange', this, false); + document.removeEventListener('touchmove', this, true); + this.element.removeEventListener('click', this, true); + + // remove the message element on transition end + this.element.addEventListener('transitionend', this, false); + this.element.addEventListener('webkitTransitionEnd', this, false); + this.element.addEventListener('MSTransitionEnd', this, false); + + // start the fade out animation + this.element.style.webkitTransitionDuration = '0.3s'; + this.element.style.opacity = '0'; + }, + + _removeElements: function() { + this.element.removeEventListener('transitionend', this, false); + this.element.removeEventListener('webkitTransitionEnd', this, false); + this.element.removeEventListener('MSTransitionEnd', this, false); + + // remove the message from the DOM + this.container.removeChild(this.viewport); + + this.shown = false; + + // fire the custom onRemove event + if (this.options.onRemove) { + this.options.onRemove.call(this); + } + }, + + updateViewport: function() { + if (!this.shown) { + return; + } + + this.viewport.style.width = window.innerWidth + 'px'; + this.viewport.style.height = window.innerHeight + 'px'; + this.viewport.style.left = window.scrollX + 'px'; + this.viewport.style.top = window.scrollY + 'px'; + + var clientWidth = document.documentElement.clientWidth; + + this.orientation = clientWidth > document.documentElement.clientHeight ? 'landscape' : 'portrait'; + + var screenWidth = ath.OS == 'ios' ? this.orientation == 'portrait' ? screen.width : screen.height : screen.width; + this.scale = screen.width > clientWidth ? 1 : screenWidth / window.innerWidth; + + this.element.style.fontSize = this.options.fontSize / this.scale + 'px'; + }, + + resize: function() { + clearTimeout(this.resizeTimer); + this.resizeTimer = setTimeout(this.updateViewport.bind(this), 100); + }, + + updateSession: function() { + if (ath.hasLocalStorage === false) { + return; + } + + if (localStorage) { + localStorage.setItem(this.options.appID, JSON.stringify(this.session)); + } + }, + + clearSession: function() { + this.session = _defaultSession; + this.updateSession(); + }, + + getItem: function(item) { + try { + if (!localStorage) { + throw new Error('localStorage is not defined'); + } + + return localStorage.getItem(item); + } catch (e) { + // Preventing exception for some browsers when fetching localStorage key + ath.hasLocalStorage = false; + } + }, + + optOut: function() { + this.session.optedout = true; + this.updateSession(); + }, + + optIn: function() { + this.session.optedout = false; + this.updateSession(); + }, + + clearDisplayCount: function() { + this.session.displayCount = 0; + this.updateSession(); + }, + + _preventDefault: function(e) { + e.preventDefault(); + e.stopPropagation(); + } + }; + + // utility + function _extend(target, obj) { + for (var i in obj) { + target[i] = obj[i]; + } + + return target; + } + + function _removeToken() { + if (document.location.hash == '#ath') { + history.replaceState('', window.document.title, document.location.href.split('#')[0]); + } + + if (_reSmartURL.test(document.location.href)) { + history.replaceState('', window.document.title, document.location.href.replace(_reSmartURL, '$1')); + } + + if (_reQueryString.test(document.location.search)) { + history.replaceState('', window.document.title, document.location.href.replace(_reQueryString, '$2')); + } + } + + /* jshint +W101, +W106 */ + + ath.VERSION = '3.2.2'; + + module.exports = UI.addToHomescreen = ath; + + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + /** + * @via https://github.com/Minwe/bootstrap/blob/master/js/alert.js + * @copyright Copyright 2013 Twitter, Inc. + * @license Apache 2.0 + */ + + // Alert Class + // NOTE: removeElement option is unavailable now + var Alert = function(element, options) { + var _this = this; + this.options = $.extend({}, Alert.DEFAULTS, options); + this.$element = $(element); + + this.$element + .addClass('am-fade am-in') + .on('click.alert.amui', '.am-close', function() { + _this.close(); + }); + }; + + Alert.DEFAULTS = { + removeElement: true + }; + + Alert.prototype.close = function() { + var $element = this.$element; + + $element.trigger('close.alert.amui').removeClass('am-in'); + + function processAlert() { + $element.trigger('closed.alert.amui').remove(); + } + + UI.support.transition && $element.hasClass('am-fade') ? + $element + .one(UI.support.transition.end, processAlert) + .emulateTransitionEnd(200) : + processAlert(); + }; + + // plugin + UI.plugin('alert', Alert); + + // Init code + $(document).on('click.alert.amui.data-api', '[data-am-alert]', function(e) { + var $target = $(e.target); + $target.is('.am-close') && $(this).alert('close'); + }); + + module.exports = Alert; + + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + /** + * @via https://github.com/twbs/bootstrap/blob/master/js/button.js + * @copyright (c) 2011-2014 Twitter, Inc + * @license The MIT License + */ + + var Button = function(element, options) { + this.$element = $(element); + this.options = $.extend({}, Button.DEFAULTS, options); + this.isLoading = false; + this.hasSpinner = false; + }; + + Button.DEFAULTS = { + loadingText: 'loading...', + disabledClassName: 'am-disabled', + activeClassName: 'am-active', + spinner: undefined + }; + + Button.prototype.setState = function(state, stateText) { + var $element = this.$element; + var disabled = 'disabled'; + var data = $element.data(); + var options = this.options; + var val = $element.is('input') ? 'val' : 'html'; + var stateClassName = 'am-btn-' + state + ' ' + options.disabledClassName; + + state += 'Text'; + + if (!options.resetText) { + options.resetText = $element[val](); + } + + // add spinner for element with html() + if (UI.support.animation && options.spinner && + val === 'html' && !this.hasSpinner) { + options.loadingText = '' + options.loadingText; + + this.hasSpinner = true; + } + + stateText = stateText || + (data[state] === undefined ? options[state] : data[state]); + + $element[val](stateText); + + // push to event loop to allow forms to submit + setTimeout($.proxy(function() { + // TODO: add stateClass for other states + if (state === 'loadingText') { + $element.addClass(stateClassName).attr(disabled, disabled); + this.isLoading = true; + } else if (this.isLoading) { + $element.removeClass(stateClassName).removeAttr(disabled); + this.isLoading = false; + } + }, this), 0); + }; + + Button.prototype.toggle = function() { + var changed = true; + var $element = this.$element; + var $parent = this.$element.parent('[class*="am-btn-group"]'); + var activeClassName = Button.DEFAULTS.activeClassName; + + if ($parent.length) { + var $input = this.$element.find('input'); + + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && $element.hasClass(activeClassName)) { + changed = false; + } else { + $parent.find('.' + activeClassName).removeClass(activeClassName); + } + } + + if (changed) { + $input.prop('checked', + !$element.hasClass(activeClassName)).trigger('change'); + } + } + + if (changed) { + $element.toggleClass(activeClassName); + if (!$element.hasClass(activeClassName)) { + $element.blur(); + } + } + }; + + UI.plugin('button', Button, { + dataOptions: 'data-am-loading', + methodCall: function(args, instance) { + if (args[0] === 'toggle') { + instance.toggle(); + } else if (typeof args[0] === 'string') { + instance.setState.apply(instance, args); + } + } + }); + + // Init code + $(document).on('click.button.amui.data-api', '[data-am-button]', function(e) { + e.preventDefault(); + var $btn = $(e.target); + + if (!$btn.hasClass('am-btn')) { + $btn = $btn.closest('.am-btn'); + } + + $btn.button('toggle'); + }); + + UI.ready(function(context) { + $('[data-am-loading]', context).button(); + + // resolves #866 + $('[data-am-button]', context).find('input:checked').each(function() { + $(this).parent('label').addClass(Button.DEFAULTS.activeClassName); + }); + }); + + module.exports = UI.button = Button; + + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + /** + * @via https://github.com/twbs/bootstrap/blob/master/js/collapse.js + * @copyright (c) 2011-2014 Twitter, Inc + * @license The MIT License + */ + + var Collapse = function(element, options) { + this.$element = $(element); + this.options = $.extend({}, Collapse.DEFAULTS, options); + this.transitioning = null; + + if (this.options.parent) { + this.$parent = $(this.options.parent); + } + + if (this.options.toggle) { + this.toggle(); + } + }; + + Collapse.DEFAULTS = { + toggle: true + }; + + Collapse.prototype.open = function() { + if (this.transitioning || this.$element.hasClass('am-in')) { + return; + } + + var startEvent = $.Event('open.collapse.amui'); + this.$element.trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + var actives = this.$parent && this.$parent.find('> .am-panel > .am-in'); + + if (actives && actives.length) { + var hasData = actives.data('amui.collapse'); + + if (hasData && hasData.transitioning) { + return; + } + + Plugin.call(actives, 'close'); + + hasData || actives.data('amui.collapse', null); + } + + this.$element + .removeClass('am-collapse') + .addClass('am-collapsing').height(0); + + this.transitioning = 1; + + var complete = function() { + this.$element + .removeClass('am-collapsing') + .addClass('am-collapse am-in') + .height('') + .trigger('opened.collapse.amui'); + this.transitioning = 0; + }; + + if (!UI.support.transition) { + return complete.call(this); + } + + var scrollHeight = this.$element[0].scrollHeight; + + this.$element + .one(UI.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(300) + .css({height: scrollHeight}); // 当折叠的容器有 padding 时,如果用 height() 只能设置内容的宽度 + }; + + Collapse.prototype.close = function() { + if (this.transitioning || !this.$element.hasClass('am-in')) { + return; + } + + var startEvent = $.Event('close.collapse.amui'); + this.$element.trigger(startEvent); + + if (startEvent.isDefaultPrevented()) { + return; + } + + this.$element.height(this.$element.height()).redraw(); + + this.$element.addClass('am-collapsing'). + removeClass('am-collapse am-in'); + + this.transitioning = 1; + + var complete = function() { + this.transitioning = 0; + this.$element + .trigger('closed.collapse.amui') + .removeClass('am-collapsing') + .addClass('am-collapse'); + // css({height: '0'}); + }; + + if (!UI.support.transition) { + return complete.call(this); + } + + this.$element.height(0) + .one(UI.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(300); + }; + + Collapse.prototype.toggle = function() { + this[this.$element.hasClass('am-in') ? 'close' : 'open'](); + }; + + // Collapse Plugin + function Plugin(option) { + return this.each(function() { + var $this = $(this); + var data = $this.data('amui.collapse'); + var options = $.extend({}, Collapse.DEFAULTS, + UI.utils.options($this.attr('data-am-collapse')), + typeof option == 'object' && option); + + if (!data && options.toggle && option === 'open') { + option = !option; + } + + if (!data) { + $this.data('amui.collapse', (data = new Collapse(this, options))); + } + + if (typeof option == 'string') { + data[option](); + } + }); + } + + $.fn.collapse = Plugin; + + // Init code + $(document).on('click.collapse.amui.data-api', '[data-am-collapse]', + function(e) { + var href; + var $this = $(this); + var options = UI.utils.options($this.attr('data-am-collapse')); + var target = options.target || + e.preventDefault() || + (href = $this.attr('href')) && + href.replace(/.*(?=#[^\s]+$)/, ''); + var $target = $(target); + var data = $target.data('amui.collapse'); + var option = data ? 'toggle' : options; + var parent = options.parent; + var $parent = parent && $(parent); + + if (!data || !data.transitioning) { + if ($parent) { + // '[data-am-collapse*="{parent: \'' + parent + '"] + $parent.find('[data-am-collapse]').not($this).addClass('am-collapsed'); + } + + $this[$target.hasClass('am-in') ? + 'addClass' : 'removeClass']('am-collapsed'); + } + + Plugin.call($target, option); + }); + + module.exports = UI.collapse = Collapse; + + // TODO: 更好的 target 选择方式 + // 折叠的容器必须没有 border/padding 才能正常处理,否则动画会有一些小问题 + // 寻找更好的未知高度 transition 动画解决方案,max-height 之类的就算了 + + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var $doc = $(document); + + /** + * bootstrap-datepicker.js + * @via http://www.eyecon.ro/bootstrap-datepicker + * @license http://www.apache.org/licenses/LICENSE-2.0 + */ + var Datepicker = function(element, options) { + this.$element = $(element); + this.options = $.extend({}, Datepicker.DEFAULTS, options); + this.format = DPGlobal.parseFormat(this.options.format); + + this.$element.data('date', this.options.date); + this.language = this.getLocale(this.options.locale); + this.theme = this.options.theme; + this.$picker = $(DPGlobal.template).appendTo('body').on({ + click: $.proxy(this.click, this) + // mousedown: $.proxy(this.mousedown, this) + }); + + this.isInput = this.$element.is('input'); + this.component = this.$element.is('.am-datepicker-date') ? + this.$element.find('.am-datepicker-add-on') : false; + + if (this.isInput) { + this.$element.on({ + 'click.datepicker.amui': $.proxy(this.open, this), + // blur: $.proxy(this.close, this), + 'keyup.datepicker.amui': $.proxy(this.update, this) + }); + } else { + if (this.component) { + this.component.on('click.datepicker.amui', $.proxy(this.open, this)); + } else { + this.$element.on('click.datepicker.amui', $.proxy(this.open, this)); + } + } + + this.minViewMode = this.options.minViewMode; + + if (typeof this.minViewMode === 'string') { + switch (this.minViewMode) { + case 'months': + this.minViewMode = 1; + break; + case 'years': + this.minViewMode = 2; + break; + default: + this.minViewMode = 0; + break; + } + } + + this.viewMode = this.options.viewMode; + + if (typeof this.viewMode === 'string') { + switch (this.viewMode) { + case 'months': + this.viewMode = 1; + break; + case 'years': + this.viewMode = 2; + break; + default: + this.viewMode = 0; + break; + } + } + + this.startViewMode = this.viewMode; + this.weekStart = ((this.options.weekStart || + Datepicker.locales[this.language].weekStart || 0) % 7); + this.weekEnd = ((this.weekStart + 6) % 7); + this.onRender = this.options.onRender; + + this.setTheme(); + this.fillDow(); + this.fillMonths(); + this.update(); + this.showMode(); + }; + + Datepicker.DEFAULTS = { + locale: 'zh_CN', + format: 'yyyy-mm-dd', + weekStart: undefined, + viewMode: 0, + minViewMode: 0, + date: '', + theme: '', + autoClose: 1, + onRender: function(date) { + return ''; + } + }; + + Datepicker.prototype.open = function(e) { + this.$picker.show(); + this.height = this.component ? + this.component.outerHeight() : this.$element.outerHeight(); + + this.place(); + $(window).on('resize.datepicker.amui', $.proxy(this.place, this)); + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + var that = this; + $doc.on('mousedown.datapicker.amui touchstart.datepicker.amui', function(ev) { + if ($(ev.target).closest('.am-datepicker').length === 0) { + that.close(); + } + }); + this.$element.trigger({ + type: 'open.datepicker.amui', + date: this.date + }); + }; + + Datepicker.prototype.close = function() { + this.$picker.hide(); + $(window).off('resize.datepicker.amui', this.place); + this.viewMode = this.startViewMode; + this.showMode(); + if (!this.isInput) { + $(document).off('mousedown.datapicker.amui touchstart.datepicker.amui', + this.close); + } + // this.set(); + this.$element.trigger({ + type: 'close.datepicker.amui', + date: this.date + }); + }; + + Datepicker.prototype.set = function() { + var formatted = DPGlobal.formatDate(this.date, this.format); + var $input; + + if (!this.isInput) { + if (this.component) { + $input = this.$element.find('input').attr('value', formatted); + } + + this.$element.data('date', formatted); + } else { + $input = this.$element.attr('value', formatted); + } + + // fixes https://github.com/amazeui/amazeui/issues/711 + $input && $input.trigger('change'); + }; + + Datepicker.prototype.setValue = function(newDate) { + if (typeof newDate === 'string') { + this.date = DPGlobal.parseDate(newDate, this.format); + } else { + this.date = new Date(newDate); + } + this.set(); + + this.viewDate = new Date(this.date.getFullYear(), + this.date.getMonth(), 1, 0, 0, 0, 0); + + this.fill(); + }; + + Datepicker.prototype.place = function() { + var offset = this.component ? + this.component.offset() : this.$element.offset(); + var $width = this.component ? + this.component.width() : this.$element.width(); + var top = offset.top + this.height; + var left = offset.left; + var right = $doc.width() - offset.left - $width; + var isOutView = this.isOutView(); + + this.$picker.removeClass('am-datepicker-right'); + this.$picker.removeClass('am-datepicker-up'); + + if ($doc.width() > 640) { + if (isOutView.outRight) { + this.$picker.addClass('am-datepicker-right'); + this.$picker.css({ + top: top, + left: 'auto', + right: right + }); + return; + } + if (isOutView.outBottom) { + this.$picker.addClass('am-datepicker-up'); + top = offset.top - this.$picker.outerHeight(true); + } + } else { + left = 0; + } + + this.$picker.css({ + top: top, + left: left + }); + }; + + Datepicker.prototype.update = function(newDate) { + this.date = DPGlobal.parseDate( + typeof newDate === 'string' ? newDate : (this.isInput ? + this.$element.prop('value') : this.$element.data('date')), + this.format + ); + this.viewDate = new Date(this.date.getFullYear(), + this.date.getMonth(), 1, 0, 0, 0, 0); + this.fill(); + }; + + // Days of week + Datepicker.prototype.fillDow = function() { + var dowCount = this.weekStart; + var html = ''; + while (dowCount < this.weekStart + 7) { + // NOTE: do % then add 1 + html += '' + + Datepicker.locales[this.language].daysMin[(dowCount++) % 7] + + ''; + } + html += ''; + + this.$picker.find('.am-datepicker-days thead').append(html); + }; + + Datepicker.prototype.fillMonths = function() { + var html = ''; + var i = 0; + while (i < 12) { + html += '' + + Datepicker.locales[this.language].monthsShort[i++] + ''; + } + this.$picker.find('.am-datepicker-months td').append(html); + }; + + Datepicker.prototype.fill = function() { + var d = new Date(this.viewDate); + var year = d.getFullYear(); + var month = d.getMonth(); + var currentDate = this.date.valueOf(); + + var prevMonth = new Date(year, month - 1, 28, 0, 0, 0, 0); + var day = DPGlobal + .getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); + + var daysSelect = this.$picker + .find('.am-datepicker-days .am-datepicker-select'); + + if (this.language === 'zh_CN') { + daysSelect.text(year + Datepicker.locales[this.language].year[0] + + ' ' + Datepicker.locales[this.language].months[month]); + } else { + daysSelect.text(Datepicker.locales[this.language].months[month] + + ' ' + year); + } + + prevMonth.setDate(day); + prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7) % 7); + + var nextMonth = new Date(prevMonth); + nextMonth.setDate(nextMonth.getDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + + var className; + var prevY; + var prevM; + + while (prevMonth.valueOf() < nextMonth) { + if (prevMonth.getDay() === this.weekStart) { + html.push(''); + } + + className = this.onRender(prevMonth, 0); + prevY = prevMonth.getFullYear(); + prevM = prevMonth.getMonth(); + + if ((prevM < month && prevY === year) || prevY < year) { + className += ' am-datepicker-old'; + } else if ((prevM > month && prevY === year) || prevY > year) { + className += ' am-datepicker-new'; + } + + if (prevMonth.valueOf() === currentDate) { + className += ' am-active'; + } + html.push('' + prevMonth.getDate() + ''); + + if (prevMonth.getDay() === this.weekEnd) { + html.push(''); + } + + prevMonth.setDate(prevMonth.getDate() + 1); + } + + this.$picker.find('.am-datepicker-days tbody') + .empty().append(html.join('')); + + var currentYear = this.date.getFullYear(); + var months = this.$picker.find('.am-datepicker-months') + .find('.am-datepicker-select') + .text(year); + months = months.end() + .find('span').removeClass('am-active').removeClass('am-disabled'); + + var monthLen = 0; + + while (monthLen < 12) { + if (this.onRender(d.setFullYear(year, monthLen), 1)) { + months.eq(monthLen).addClass('am-disabled'); + } + monthLen++; + } + + if (currentYear === year) { + months.eq(this.date.getMonth()) + .removeClass('am-disabled') + .addClass('am-active'); + } + + html = ''; + year = parseInt(year / 10, 10) * 10; + var yearCont = this.$picker + .find('.am-datepicker-years') + .find('.am-datepicker-select') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + var yearClassName; + // fixes https://github.com/amazeui/amazeui/issues/770 + // maybe not need now + var viewDate = new Date(this.viewDate); + + year -= 1; + + for (var i = -1; i < 11; i++) { + yearClassName = this.onRender(viewDate.setFullYear(year), 2); + html += '' + year + ''; + year += 1; + } + yearCont.html(html); + }; + + Datepicker.prototype.click = function(event) { + event.stopPropagation(); + event.preventDefault(); + var month; + var year; + var $dayActive = this.$picker.find('.am-datepicker-days').find('.am-active'); + var $months = this.$picker.find('.am-datepicker-months'); + var $monthIndex = $months.find('.am-active').index(); + + var $target = $(event.target).closest('span, td, th'); + if ($target.length === 1) { + switch ($target[0].nodeName.toLowerCase()) { + case 'th': + switch ($target[0].className) { + case 'am-datepicker-switch': + this.showMode(1); + break; + case 'am-datepicker-prev': + case 'am-datepicker-next': + this.viewDate['set' + DPGlobal.modes[this.viewMode].navFnc].call( + this.viewDate, + this.viewDate + ['get' + DPGlobal.modes[this.viewMode].navFnc] + .call(this.viewDate) + + DPGlobal.modes[this.viewMode].navStep * + ($target[0].className === 'am-datepicker-prev' ? -1 : 1) + ); + this.fill(); + this.set(); + break; + } + break; + case 'span': + if ($target.is('.am-disabled')) { + return; + } + + if ($target.is('.am-datepicker-month')) { + month = $target.parent().find('span').index($target); + + if ($target.is('.am-active')) { + this.viewDate.setMonth(month, $dayActive.text()); + } else { + this.viewDate.setMonth(month); + } + + } else { + year = parseInt($target.text(), 10) || 0; + if ($target.is('.am-active')) { + this.viewDate.setFullYear(year, $monthIndex, $dayActive.text()); + } else { + this.viewDate.setFullYear(year); + } + + } + + if (this.viewMode !== 0) { + this.date = new Date(this.viewDate); + this.$element.trigger({ + type: 'changeDate.datepicker.amui', + date: this.date, + viewMode: DPGlobal.modes[this.viewMode].clsName + }); + } + + this.showMode(-1); + this.fill(); + this.set(); + break; + case 'td': + if ($target.is('.am-datepicker-day') && !$target.is('.am-disabled')) { + var day = parseInt($target.text(), 10) || 1; + month = this.viewDate.getMonth(); + if ($target.is('.am-datepicker-old')) { + month -= 1; + } else if ($target.is('.am-datepicker-new')) { + month += 1; + } + year = this.viewDate.getFullYear(); + this.date = new Date(year, month, day, 0, 0, 0, 0); + this.viewDate = new Date(year, month, Math.min(28, day), 0, 0, 0, 0); + this.fill(); + this.set(); + this.$element.trigger({ + type: 'changeDate.datepicker.amui', + date: this.date, + viewMode: DPGlobal.modes[this.viewMode].clsName + }); + + this.options.autoClose && this.close(); + } + break; + } + } + }; + + Datepicker.prototype.mousedown = function(event) { + event.stopPropagation(); + event.preventDefault(); + }; + + Datepicker.prototype.showMode = function(dir) { + if (dir) { + this.viewMode = Math.max(this.minViewMode, + Math.min(2, this.viewMode + dir)); + } + + this.$picker.find('>div').hide(). + filter('.am-datepicker-' + DPGlobal.modes[this.viewMode].clsName).show(); + }; + + Datepicker.prototype.isOutView = function() { + var offset = this.component ? + this.component.offset() : this.$element.offset(); + var isOutView = { + outRight: false, + outBottom: false + }; + var $picker = this.$picker; + var width = offset.left + $picker.outerWidth(true); + var height = offset.top + $picker.outerHeight(true) + + this.$element.innerHeight(); + + if (width > $doc.width()) { + isOutView.outRight = true; + } + if (height > $doc.height()) { + isOutView.outBottom = true; + } + return isOutView; + }; + + Datepicker.prototype.getLocale = function(locale) { + if (!locale) { + locale = navigator.language && navigator.language.split('-'); + locale[1] = locale[1].toUpperCase(); + locale = locale.join('_'); + } + + if (!Datepicker.locales[locale]) { + locale = 'en_US'; + } + return locale; + }; + + Datepicker.prototype.setTheme = function() { + if (this.theme) { + this.$picker.addClass('am-datepicker-' + this.theme); + } + }; + + // Datepicker locales + Datepicker.locales = { + en_US: { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', + 'Friday', 'Saturday'], + daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + months: ['January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + weekStart: 0 + }, + zh_CN: { + days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], + daysShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], + daysMin: ['日', '一', '二', '三', '四', '五', '六'], + months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', + '八月', '九月', '十月', '十一月', '十二月'], + monthsShort: ['一月', '二月', '三月', '四月', '五月', '六月', + '七月', '八月', '九月', '十月', '十一月', '十二月'], + weekStart: 1, + year: ['年'] + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + } + ], + + isLeapYear: function(year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); + }, + + getDaysInMonth: function(year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), + 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + + parseFormat: function(format) { + var separator = format.match(/[.\/\-\s].*?/); + var parts = format.split(/\W+/); + + if (!separator || !parts || parts.length === 0) { + throw new Error('Invalid date format.'); + } + + return { + separator: separator, + parts: parts + }; + }, + + parseDate: function(date, format) { + var parts = date.split(format.separator); + var val; + date = new Date(); + + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + + if (parts.length === format.parts.length) { + var year = date.getFullYear(); + var day = date.getDate(); + var month = date.getMonth(); + + for (var i = 0, cnt = format.parts.length; i < cnt; i++) { + val = parseInt(parts[i], 10) || 1; + switch (format.parts[i]) { + case 'dd': + case 'd': + day = val; + date.setDate(val); + break; + case 'mm': + case 'm': + month = val - 1; + date.setMonth(val - 1); + break; + case 'yy': + year = 2000 + val; + date.setFullYear(2000 + val); + break; + case 'yyyy': + year = val; + date.setFullYear(val); + break; + } + } + date = new Date(year, month, day, 0, 0, 0); + } + return date; + }, + + formatDate: function(date, format) { + var val = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: date.getFullYear().toString().substring(2), + yyyy: date.getFullYear() + }; + var dateArray = []; + + val.dd = (val.d < 10 ? '0' : '') + val.d; + val.mm = (val.m < 10 ? '0' : '') + val.m; + + for (var i = 0, cnt = format.parts.length; i < cnt; i++) { + dateArray.push(val[format.parts[i]]); + } + return dateArray.join(format.separator); + }, + + headTemplate: '' + + '' + + '' + + '' + + '' + + '
' + + '' + + '', + + contTemplate: '' + }; + + DPGlobal.template = '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + '' + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate + + '
' + + '
' + + '
'; + + // jQuery plugin + UI.plugin('datepicker', Datepicker); + + // Init code + UI.ready(function(context) { + $('[data-am-datepicker]').datepicker(); + }); + + module.exports = UI.datepicker = Datepicker; + + // TODO: 1. 载入动画 + // 2. less 优化 + + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var $doc = $(document); + var transition = UI.support.transition; + + var Dimmer = function() { + this.id = UI.utils.generateGUID('am-dimmer'); + this.$element = $(Dimmer.DEFAULTS.tpl, { + id: this.id + }); + + this.inited = false; + this.scrollbarWidth = 0; + this.$used = $([]); + }; + + Dimmer.DEFAULTS = { + tpl: '
' + }; + + Dimmer.prototype.init = function() { + if (!this.inited) { + $(document.body).append(this.$element); + this.inited = true; + $doc.trigger('init.dimmer.amui'); + this.$element.on('touchmove.dimmer.amui', function(e) { + e.preventDefault(); + }); + } + + return this; + }; + + Dimmer.prototype.open = function(relatedElement) { + if (!this.inited) { + this.init(); + } + + var $element = this.$element; + + // 用于多重调用 + if (relatedElement) { + this.$used = this.$used.add($(relatedElement)); + } + + this.checkScrollbar().setScrollbar(); + + $element.show().trigger('open.dimmer.amui'); + + transition && $element.off(transition.end); + + setTimeout(function() { + $element.addClass('am-active'); + }, 0); + + return this; + }; + + Dimmer.prototype.close = function(relatedElement, force) { + this.$used = this.$used.not($(relatedElement)); + + if (!force && this.$used.length) { + return this; + } + + var $element = this.$element; + + $element.removeClass('am-active').trigger('close.dimmer.amui'); + + function complete() { + $element.hide(); + this.resetScrollbar(); + } + + // transition ? $element.one(transition.end, $.proxy(complete, this)) : + complete.call(this); + + return this; + }; + + Dimmer.prototype.checkScrollbar = function() { + this.scrollbarWidth = UI.utils.measureScrollbar(); + + return this; + }; + + Dimmer.prototype.setScrollbar = function() { + var $body = $(document.body); + var bodyPaddingRight = parseInt(($body.css('padding-right') || 0), 10); + + if (this.scrollbarWidth) { + $body.css('padding-right', bodyPaddingRight + this.scrollbarWidth); + } + + $body.addClass('am-dimmer-active'); + + return this; + }; + + Dimmer.prototype.resetScrollbar = function() { + $(document.body).css('padding-right', '').removeClass('am-dimmer-active'); + + return this; + }; + + module.exports = UI.dimmer = new Dimmer(); + + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var animation = UI.support.animation; + + /** + * @via https://github.com/Minwe/bootstrap/blob/master/js/dropdown.js + * @copyright (c) 2011-2014 Twitter, Inc + * @license The MIT License + */ + + // var toggle = '[data-am-dropdown] > .am-dropdown-toggle'; + + var Dropdown = function(element, options) { + this.options = $.extend({}, Dropdown.DEFAULTS, options); + + options = this.options; + + this.$element = $(element); + this.$toggle = this.$element.find(options.selector.toggle); + this.$dropdown = this.$element.find(options.selector.dropdown); + this.$boundary = (options.boundary === window) ? $(window) : + this.$element.closest(options.boundary); + this.$justify = (options.justify && $(options.justify).length && + $(options.justify)) || undefined; + + !this.$boundary.length && (this.$boundary = $(window)); + + this.active = this.$element.hasClass('am-active') ? true : false; + this.animating = null; + + this.events(); + }; + + Dropdown.DEFAULTS = { + animation: 'am-animation-slide-top-fixed', + boundary: window, + justify: undefined, + selector: { + dropdown: '.am-dropdown-content', + toggle: '.am-dropdown-toggle' + }, + trigger: 'click' + }; + + Dropdown.prototype.toggle = function() { + this.clear(); + + if (this.animating) { + return; + } + + this[this.active ? 'close' : 'open'](); + }; + + Dropdown.prototype.open = function(e) { + var $toggle = this.$toggle; + var $element = this.$element; + var $dropdown = this.$dropdown; + + if ($toggle.is('.am-disabled, :disabled')) { + return; + } + + if (this.active) { + return; + } + + $element.trigger('open.dropdown.amui').addClass('am-active'); + + $toggle.trigger('focus'); + + this.checkDimensions(e); + + var complete = $.proxy(function() { + $element.trigger('opened.dropdown.amui'); + this.active = true; + this.animating = 0; + }, this); + + if (animation) { + this.animating = 1; + $dropdown.addClass(this.options.animation). + on(animation.end + '.open.dropdown.amui', $.proxy(function() { + complete(); + $dropdown.removeClass(this.options.animation); + }, this)); + } else { + complete(); + } + }; + + Dropdown.prototype.close = function() { + if (!this.active) { + return; + } + + // fix #165 + // var animationName = this.options.animation + ' am-animation-reverse'; + var animationName = 'am-dropdown-animation'; + var $element = this.$element; + var $dropdown = this.$dropdown; + + $element.trigger('close.dropdown.amui'); + + var complete = $.proxy(function complete() { + $element. + removeClass('am-active'). + trigger('closed.dropdown.amui'); + this.active = false; + this.animating = 0; + this.$toggle.blur(); + }, this); + + if (animation) { + $dropdown.removeClass(this.options.animation); + $dropdown.addClass(animationName); + this.animating = 1; + // animation + $dropdown.one(animation.end + '.close.dropdown.amui', function() { + $dropdown.removeClass(animationName); + complete(); + }); + } else { + complete(); + } + }; + + Dropdown.prototype.enable = function() { + this.$toggle.prop('disabled', false); + }, + + Dropdown.prototype.disable = function() { + this.$toggle.prop('disabled', true); + }, + + Dropdown.prototype.checkDimensions = function(e) { + if (!this.$dropdown.length) { + return; + } + + var $dropdown = this.$dropdown; + + // @see #873 + if (e && e.offset) { + $dropdown.offset(e.offset); + } + + var offset = $dropdown.offset(); + var width = $dropdown.outerWidth(); + var boundaryWidth = this.$boundary.width(); + var boundaryOffset = $.isWindow(this.boundary) && this.$boundary.offset() ? + this.$boundary.offset().left : 0; + + if (this.$justify) { + // jQuery.fn.width() is really... + $dropdown.css({'min-width': this.$justify.css('width')}); + } + + if ((width + (offset.left - boundaryOffset)) > boundaryWidth) { + this.$element.addClass('am-dropdown-flip'); + } + }; + + Dropdown.prototype.clear = function() { + $('[data-am-dropdown]').not(this.$element).each(function() { + var data = $(this).data('amui.dropdown'); + data && data.close(); + }); + }; + + Dropdown.prototype.events = function() { + var eventNS = 'dropdown.amui'; + // triggers = this.options.trigger.split(' '), + var $toggle = this.$toggle; + + $toggle.on('click.' + eventNS, $.proxy(function(e) { + e.preventDefault(); + this.toggle(); + }, this)); + + /*for (var i = triggers.length; i--;) { + var trigger = triggers[i]; + + if (trigger === 'click') { + $toggle.on('click.' + eventNS, $.proxy(this.toggle, this)) + } + + if (trigger === 'focus' || trigger === 'hover') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'; + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'; + + this.$element.on(eventIn + '.' + eventNS, $.proxy(this.open, this)) + .on(eventOut + '.' + eventNS, $.proxy(this.close, this)); + } + }*/ + + $(document).on('keydown.dropdown.amui', $.proxy(function(e) { + e.keyCode === 27 && this.active && this.close(); + }, this)).on('click.outer.dropdown.amui', $.proxy(function(e) { + // var $target = $(e.target); + + if (this.active && + (this.$element[0] === e.target || !this.$element.find(e.target).length)) { + this.close(); + } + }, this)); + }; + + // Dropdown Plugin + UI.plugin('dropdown', Dropdown); + + // Init code + UI.ready(function(context) { + $('[data-am-dropdown]', context).dropdown(); + }); + + $(document).on('click.dropdown.amui.data-api', '.am-dropdown form', + function(e) { + e.stopPropagation(); + }); + + module.exports = UI.dropdown = Dropdown; + + // TODO: 1. 处理链接 focus + // 2. 增加 mouseenter / mouseleave 选项 + // 3. 宽度适应 + + +/***/ }, +/* 11 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(setImmediate) {var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + // MODIFIED: + // - LINE 252: add `` + // - namespace + // - Init code + // TODO: start after x ms when pause on actions + + /* + * jQuery FlexSlider v2.6.1 + * Copyright 2012 WooThemes + * Contributing Author: Tyler Smith + */ + + var focused = true; + + // FlexSlider: Object Instance + $.flexslider = function(el, options) { + var slider = $(el); + + // making variables public + slider.vars = $.extend({}, $.flexslider.defaults, options); + + var namespace = slider.vars.namespace, + msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture, + touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch, + // depricating this idea, as devices are being released with both of these events + eventType = "click touchend MSPointerUp keyup", + watchedEvent = "", + watchedEventClearTimer, + vertical = slider.vars.direction === "vertical", + reverse = slider.vars.reverse, + carousel = (slider.vars.itemWidth > 0), + fade = slider.vars.animation === "fade", + asNav = slider.vars.asNavFor !== "", + methods = {}; + + // Store a reference to the slider object + $.data(el, 'flexslider', slider); + + // Private slider methods + methods = { + init: function() { + slider.animating = false; + // Get current slide and make sure it is a number + slider.currentSlide = parseInt((slider.vars.startAt ? slider.vars.startAt : 0), 10); + if (isNaN(slider.currentSlide)) { + slider.currentSlide = 0; + } + slider.animatingTo = slider.currentSlide; + slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last); + slider.containerSelector = slider.vars.selector.substr(0, slider.vars.selector.search(' ')); + slider.slides = $(slider.vars.selector, slider); + slider.container = $(slider.containerSelector, slider); + slider.count = slider.slides.length; + // SYNC: + slider.syncExists = $(slider.vars.sync).length > 0; + // SLIDE: + if (slider.vars.animation === "slide") { + slider.vars.animation = "swing"; + } + slider.prop = (vertical) ? "top" : "marginLeft"; + slider.args = {}; + // SLIDESHOW: + slider.manualPause = false; + slider.stopped = false; + //PAUSE WHEN INVISIBLE + slider.started = false; + slider.startTimeout = null; + // TOUCH/USECSS: + slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() { + var obj = document.createElement('div'), + props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; + for (var i in props) { + if (obj.style[props[i]] !== undefined) { + slider.pfx = props[i].replace('Perspective', '').toLowerCase(); + slider.prop = "-" + slider.pfx + "-transform"; + return true; + } + } + return false; + }()); + slider.ensureAnimationEnd = ''; + // CONTROLSCONTAINER: + if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer); + // MANUAL: + if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls); + + // CUSTOM DIRECTION NAV: + if (slider.vars.customDirectionNav !== "") slider.customDirectionNav = $(slider.vars.customDirectionNav).length === 2 && $(slider.vars.customDirectionNav); + + // RANDOMIZE: + if (slider.vars.randomize) { + slider.slides.sort(function() { + return (Math.round(Math.random()) - 0.5); + }); + slider.container.empty().append(slider.slides); + } + + slider.doMath(); + + // INIT + slider.setup("init"); + + // CONTROLNAV: + if (slider.vars.controlNav) { + methods.controlNav.setup(); + } + + // DIRECTIONNAV: + if (slider.vars.directionNav) { + methods.directionNav.setup(); + } + + // KEYBOARD: + if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) { + $(document).bind('keyup', function(event) { + var keycode = event.keyCode; + if (!slider.animating && (keycode === 39 || keycode === 37)) { + var target = (keycode === 39) ? slider.getTarget('next') : + (keycode === 37) ? slider.getTarget('prev') : false; + slider.flexAnimate(target, slider.vars.pauseOnAction); + } + }); + } + // MOUSEWHEEL: + if (slider.vars.mousewheel) { + slider.bind('mousewheel', function(event, delta, deltaX, deltaY) { + event.preventDefault(); + var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev'); + slider.flexAnimate(target, slider.vars.pauseOnAction); + }); + } + + // PAUSEPLAY + if (slider.vars.pausePlay) { + methods.pausePlay.setup(); + } + + //PAUSE WHEN INVISIBLE + if (slider.vars.slideshow && slider.vars.pauseInvisible) { + methods.pauseInvisible.init(); + } + + // SLIDSESHOW + if (slider.vars.slideshow) { + if (slider.vars.pauseOnHover) { + slider.hover(function() { + if (!slider.manualPlay && !slider.manualPause) {slider.pause();} + }, function() { + if (!slider.manualPause && !slider.manualPlay && !slider.stopped) {slider.play();} + }); + } + // initialize animation + // If we're visible, or we don't use PageVisibility API + if (!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) { + (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play(); + } + } + + // ASNAV: + if (asNav) {methods.asNav.setup();} + + // TOUCH + if (touch && slider.vars.touch) {methods.touch();} + + // FADE&&SMOOTHHEIGHT || SLIDE: + if (!fade || (fade && slider.vars.smoothHeight)) {$(window).bind("resize orientationchange focus", methods.resize);} + + slider.find("assets/img").attr("draggable", "false"); + + // API: start() Callback + setTimeout(function() { + slider.vars.start(slider); + }, 200); + }, + asNav: { + setup: function() { + slider.asNav = true; + slider.animatingTo = Math.floor(slider.currentSlide / slider.move); + slider.currentItem = slider.currentSlide; + slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide"); + if (!msGesture) { + slider.slides.on(eventType, function(e) { + e.preventDefault(); + var $slide = $(this), + target = $slide.index(); + var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container + if (posFromLeft <= 0 && $slide.hasClass(namespace + 'active-slide')) { + slider.flexAnimate(slider.getTarget("prev"), true); + } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) { + slider.direction = (slider.currentItem < target) ? "next" : "prev"; + slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); + } + }); + } else { + el._slider = slider; + slider.slides.each(function() { + var that = this; + that._gesture = new MSGesture(); + that._gesture.target = that; + that.addEventListener("MSPointerDown", function(e) { + e.preventDefault(); + if (e.currentTarget._gesture) { + e.currentTarget._gesture.addPointer(e.pointerId); + } + }, false); + that.addEventListener("MSGestureTap", function(e) { + e.preventDefault(); + var $slide = $(this), + target = $slide.index(); + if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) { + slider.direction = (slider.currentItem < target) ? "next" : "prev"; + slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true); + } + }); + }); + } + } + }, + controlNav: { + setup: function() { + if (!slider.manualControls) { + methods.controlNav.setupPaging(); + } else { // MANUALCONTROLS: + methods.controlNav.setupManual(); + } + }, + setupPaging: function() { + var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging', + j = 1, + item, + slide; + + slider.controlNavScaffold = $('
    '); + + if (slider.pagingCount > 1) { + for (var i = 0; i < slider.pagingCount; i++) { + slide = slider.slides.eq(i); + if (undefined === slide.attr('data-thumb-alt')) { + slide.attr('data-thumb-alt', ''); + } + var altText = ('' !== slide.attr('data-thumb-alt')) ? altText = ' alt="' + slide.attr('data-thumb-alt') + '"' : ''; + item = (slider.vars.controlNav === "thumbnails") ? '' : '' + j + ''; + if ('thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions) { + var captn = slide.attr('data-thumbcaption'); + if ('' !== captn && undefined !== captn) {item += '' + captn + '';} + } + // slider.controlNavScaffold.append('
  1. ' + item + '
  2. '); + slider.controlNavScaffold.append('
  3. ' + item + '
  4. '); + j++; + } + } + + // CONTROLSCONTAINER: + (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold); + methods.controlNav.set(); + + methods.controlNav.active(); + + slider.controlNavScaffold.delegate('a, img', eventType, function(event) { + event.preventDefault(); + + if (watchedEvent === "" || watchedEvent === event.type) { + var $this = $(this), + target = slider.controlNav.index($this); + + if (!$this.hasClass(namespace + 'active')) { + slider.direction = (target > slider.currentSlide) ? "next" : "prev"; + slider.flexAnimate(target, slider.vars.pauseOnAction); + } + } + + // setup flags to prevent event duplication + if (watchedEvent === "") { + watchedEvent = event.type; + } + methods.setToClearWatchedEvent(); + + }); + }, + setupManual: function() { + slider.controlNav = slider.manualControls; + methods.controlNav.active(); + + slider.controlNav.bind(eventType, function(event) { + event.preventDefault(); + + if (watchedEvent === "" || watchedEvent === event.type) { + var $this = $(this), + target = slider.controlNav.index($this); + + if (!$this.hasClass(namespace + 'active')) { + (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev"; + slider.flexAnimate(target, slider.vars.pauseOnAction); + } + } + + // setup flags to prevent event duplication + if (watchedEvent === "") { + watchedEvent = event.type; + } + methods.setToClearWatchedEvent(); + }); + }, + set: function() { + var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a'; + slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider); + }, + active: function() { + slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active"); + }, + update: function(action, pos) { + if (slider.pagingCount > 1 && action === "add") { + slider.controlNavScaffold.append($('
  5. ' + slider.count + '
  6. ')); + } else if (slider.pagingCount === 1) { + slider.controlNavScaffold.find('li').remove(); + } else { + slider.controlNav.eq(pos).closest('li').remove(); + } + methods.controlNav.set(); + (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active(); + } + }, + directionNav: { + setup: function() { + var directionNavScaffold = $(''); + + // CUSTOM DIRECTION NAV: + if (slider.customDirectionNav) { + slider.directionNav = slider.customDirectionNav; + } else if (slider.controlsContainer) { // CONTROLSCONTAINER: + $(slider.controlsContainer).append(directionNavScaffold); + slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer); + } else { + slider.append(directionNavScaffold); + slider.directionNav = $('.' + namespace + 'direction-nav li a', slider); + } + + methods.directionNav.update(); + + slider.directionNav.bind(eventType, function(event) { + event.preventDefault(); + var target; + + if (watchedEvent === "" || watchedEvent === event.type) { + target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev'); + slider.flexAnimate(target, slider.vars.pauseOnAction); + } + + // setup flags to prevent event duplication + if (watchedEvent === "") { + watchedEvent = event.type; + } + methods.setToClearWatchedEvent(); + }); + }, + update: function() { + var disabledClass = namespace + 'disabled'; + if (slider.pagingCount === 1) { + slider.directionNav.addClass(disabledClass).attr('tabindex', '-1'); + } else if (!slider.vars.animationLoop) { + if (slider.animatingTo === 0) { + slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1'); + } else if (slider.animatingTo === slider.last) { + slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1'); + } else { + slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); + } + } else { + slider.directionNav.removeClass(disabledClass).removeAttr('tabindex'); + } + } + }, + pausePlay: { + setup: function() { + var pausePlayScaffold = $('
    '); + + // CONTROLSCONTAINER: + if (slider.controlsContainer) { + slider.controlsContainer.append(pausePlayScaffold); + slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer); + } else { + slider.append(pausePlayScaffold); + slider.pausePlay = $('.' + namespace + 'pauseplay a', slider); + } + + methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play'); + + slider.pausePlay.bind(eventType, function(event) { + event.preventDefault(); + + if (watchedEvent === "" || watchedEvent === event.type) { + if ($(this).hasClass(namespace + 'pause')) { + slider.manualPause = true; + slider.manualPlay = false; + slider.pause(); + } else { + slider.manualPause = false; + slider.manualPlay = true; + slider.play(); + } + } + + // setup flags to prevent event duplication + if (watchedEvent === "") { + watchedEvent = event.type; + } + methods.setToClearWatchedEvent(); + }); + }, + update: function(state) { + (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText); + } + }, + touch: function() { + var startX, + startY, + offset, + cwidth, + dx, + startT, + onTouchStart, + onTouchMove, + onTouchEnd, + scrolling = false, + localX = 0, + localY = 0, + accDx = 0; + + if (!msGesture) { + onTouchStart = function(e) { + if (slider.animating) { + e.preventDefault(); + } else if (( window.navigator.msPointerEnabled ) || e.touches.length === 1) { + slider.pause(); + // CAROUSEL: + cwidth = (vertical) ? slider.h : slider.w; + startT = Number(new Date()); + // CAROUSEL: + + // Local vars for X and Y points. + localX = e.touches[0].pageX; + localY = e.touches[0].pageY; + + offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : + (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : + (carousel && slider.currentSlide === slider.last) ? slider.limit : + (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : + (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; + startX = (vertical) ? localY : localX; + startY = (vertical) ? localX : localY; + + el.addEventListener('touchmove', onTouchMove, false); + el.addEventListener('touchend', onTouchEnd, false); + } + }; + + onTouchMove = function(e) { + // Local vars for X and Y points. + + localX = e.touches[0].pageX; + localY = e.touches[0].pageY; + + dx = (vertical) ? startX - localY : startX - localX; + scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY)); + + var fxms = 500; + + if (!scrolling || Number(new Date()) - startT > fxms) { + e.preventDefault(); + if (!fade && slider.transitions) { + if (!slider.vars.animationLoop) { + dx = dx / ((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx) / cwidth + 2) : 1); + } + slider.setProps(offset + dx, "setTouch"); + } + } + }; + + onTouchEnd = function(e) { + // finish the touch by undoing the touch session + el.removeEventListener('touchmove', onTouchMove, false); + + if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { + var updateDx = (reverse) ? -dx : dx, + target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); + + if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth / 2)) { + slider.flexAnimate(target, slider.vars.pauseOnAction); + } else { + if (!fade) {slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true);} + } + } + el.removeEventListener('touchend', onTouchEnd, false); + + startX = null; + startY = null; + dx = null; + offset = null; + }; + + el.addEventListener('touchstart', onTouchStart, false); + } else { + el.style.msTouchAction = "none"; + el._gesture = new MSGesture(); + el._gesture.target = el; + el.addEventListener("MSPointerDown", onMSPointerDown, false); + el._slider = slider; + el.addEventListener("MSGestureChange", onMSGestureChange, false); + el.addEventListener("MSGestureEnd", onMSGestureEnd, false); + + function onMSPointerDown(e) { + e.stopPropagation(); + if (slider.animating) { + e.preventDefault(); + } else { + slider.pause(); + el._gesture.addPointer(e.pointerId); + accDx = 0; + cwidth = (vertical) ? slider.h : slider.w; + startT = Number(new Date()); + // CAROUSEL: + + offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 : + (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : + (carousel && slider.currentSlide === slider.last) ? slider.limit : + (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide : + (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth; + } + } + + function onMSGestureChange(e) { + e.stopPropagation(); + var slider = e.target._slider; + if (!slider) { + return; + } + var transX = -e.translationX, + transY = -e.translationY; + + //Accumulate translations. + accDx = accDx + ((vertical) ? transY : transX); + dx = accDx; + scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY)); + + if (e.detail === e.MSGESTURE_FLAG_INERTIA) { + setImmediate(function() { + el._gesture.stop(); + }); + + return; + } + + if (!scrolling || Number(new Date()) - startT > 500) { + e.preventDefault(); + if (!fade && slider.transitions) { + if (!slider.vars.animationLoop) { + dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1); + } + slider.setProps(offset + dx, "setTouch"); + } + } + } + + function onMSGestureEnd(e) { + e.stopPropagation(); + var slider = e.target._slider; + if (!slider) { + return; + } + if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) { + var updateDx = (reverse) ? -dx : dx, + target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); + + if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth / 2)) { + slider.flexAnimate(target, slider.vars.pauseOnAction); + } else { + if (!fade) {slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true);} + } + } + + startX = null; + startY = null; + dx = null; + offset = null; + accDx = 0; + } + } + }, + resize: function() { + if (!slider.animating && slider.is(':visible')) { + if (!carousel) {slider.doMath()}; + + if (fade) { + // SMOOTH HEIGHT: + methods.smoothHeight(); + } else if (carousel) { //CAROUSEL: + slider.slides.width(slider.computedW); + slider.update(slider.pagingCount); + slider.setProps(); + } + else if (vertical) { //VERTICAL: + slider.viewport.height(slider.h); + slider.setProps(slider.h, "setTotal"); + } else { + // SMOOTH HEIGHT: + if (slider.vars.smoothHeight) {methods.smoothHeight();} + slider.newSlides.width(slider.computedW); + slider.setProps(slider.computedW, "setTotal"); + } + } + }, + smoothHeight: function(dur) { + if (!vertical || fade) { + var $obj = (fade) ? slider : slider.viewport; + (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).innerHeight()}, dur) : $obj.innerHeight(slider.slides.eq(slider.animatingTo).innerHeight()); + } + }, + sync: function(action) { + var $obj = $(slider.vars.sync).data("flexslider"), + target = slider.animatingTo; + + switch (action) { + case "animate": + $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); + break; + case "play": + if (!$obj.playing && !$obj.asNav) { + $obj.play(); + } + break; + case "pause": + $obj.pause(); + break; + } + }, + uniqueID: function($clone) { + // Append _clone to current level and children elements with id attributes + $clone.filter('[id]').add($clone.find('[id]')).each(function() { + var $this = $(this); + $this.attr('id', $this.attr('id') + '_clone'); + }); + return $clone; + }, + pauseInvisible: { + visProp: null, + init: function() { + var visProp = methods.pauseInvisible.getHiddenProp(); + if (visProp) { + var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange'; + document.addEventListener(evtname, function() { + if (methods.pauseInvisible.isHidden()) { + if(slider.startTimeout) { + clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible + } else { + slider.pause(); //Or just pause + } + } + else { + if(slider.started) { + slider.play(); //Initiated before, just play + } else { + if (slider.vars.initDelay > 0) { + setTimeout(slider.play, slider.vars.initDelay); + } else { + slider.play(); //Didn't init before: simply init or wait for it + } + } + } + }); + } + }, + isHidden: function() { + var prop = methods.pauseInvisible.getHiddenProp(); + if (!prop) { + return false; + } + return document[prop]; + }, + getHiddenProp: function() { + var prefixes = ['webkit','moz','ms','o']; + // if 'hidden' is natively supported just return it + if ('hidden' in document) { + return 'hidden'; + } + // otherwise loop over all the known prefixes until we find one + for (var i = 0; i < prefixes.length; i++ ) { + if ((prefixes[i] + 'Hidden') in document) { + return prefixes[i] + 'Hidden'; + } + } + // otherwise it's not supported + return null; + } + }, + setToClearWatchedEvent: function() { + clearTimeout(watchedEventClearTimer); + watchedEventClearTimer = setTimeout(function() { + watchedEvent = ""; + }, 3000); + } + }; + + // public methods + slider.flexAnimate = function(target, pause, override, withSync, fromNav) { + if (!slider.vars.animationLoop && target !== slider.currentSlide) { + slider.direction = (target > slider.currentSlide) ? "next" : "prev"; + } + + if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev"; + + if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) { + if (asNav && withSync) { + var master = $(slider.vars.asNavFor).data('flexslider'); + slider.atEnd = target === 0 || target === slider.count - 1; + master.flexAnimate(target, true, false, true, fromNav); + slider.direction = (slider.currentItem < target) ? "next" : "prev"; + master.direction = slider.direction; + + if (Math.ceil((target + 1) / slider.visible) - 1 !== slider.currentSlide && target !== 0) { + slider.currentItem = target; + slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); + target = Math.floor(target / slider.visible); + } else { + slider.currentItem = target; + slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide"); + return false; + } + } + + slider.animating = true; + slider.animatingTo = target; + + // SLIDESHOW: + if (pause) {slider.pause();} + + // API: before() animation Callback + slider.vars.before(slider); + + // SYNC: + if (slider.syncExists && !fromNav) {methods.sync("animate");} + + // CONTROLNAV + if (slider.vars.controlNav) {methods.controlNav.active();} + + // !CAROUSEL: + // CANDIDATE: slide active class (for add/remove slide) + if (!carousel) {slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide');} + + // INFINITE LOOP: + // CANDIDATE: atEnd + slider.atEnd = target === 0 || target === slider.last; + + // DIRECTIONNAV: + if (slider.vars.directionNav) {methods.directionNav.update();} + + if (target === slider.last) { + // API: end() of cycle Callback + slider.vars.end(slider); + // SLIDESHOW && !INFINITE LOOP: + if (!slider.vars.animationLoop) {slider.pause();} + } + + // SLIDE: + if (!fade) { + var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW, + margin, slideString, calcNext; + + // INFINITE LOOP / REVERSE: + if (carousel) { + //margin = (slider.vars.itemWidth > slider.w) ? slider.vars.itemMargin * 2 : slider.vars.itemMargin; + margin = slider.vars.itemMargin; + calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo; + slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext; + } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") { + slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0; + } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") { + slideString = (reverse) ? 0 : (slider.count + 1) * dimension; + } else { + slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension; + } + slider.setProps(slideString, "", slider.vars.animationSpeed); + if (slider.transitions) { + if (!slider.vars.animationLoop || !slider.atEnd) { + slider.animating = false; + slider.currentSlide = slider.animatingTo; + } + + // Unbind previous transitionEnd events and re-bind new transitionEnd event + slider.container.unbind("webkitTransitionEnd transitionend"); + slider.container.bind("webkitTransitionEnd transitionend", function() { + clearTimeout(slider.ensureAnimationEnd); + slider.wrapup(dimension); + }); + + // Insurance for the ever-so-fickle transitionEnd event + clearTimeout(slider.ensureAnimationEnd); + slider.ensureAnimationEnd = setTimeout(function() { + slider.wrapup(dimension); + }, slider.vars.animationSpeed + 100); + + } else { + slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){ + slider.wrapup(dimension); + }); + } + } else { // FADE: + if (!touch) { + //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing); + //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); + + slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing); + slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup); + + } else { + slider.slides.eq(slider.currentSlide).css({ + "opacity": 0, + "zIndex": 1 + }); + slider.slides.eq(target).css({"opacity": 1, "zIndex": 2}); + slider.wrapup(dimension); + } + } + // SMOOTH HEIGHT: + if (slider.vars.smoothHeight) {methods.smoothHeight(slider.vars.animationSpeed)}; + } + }; + slider.wrapup = function(dimension) { + // SLIDE: + if (!fade && !carousel) { + if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) { + slider.setProps(dimension, "jumpEnd"); + } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) { + slider.setProps(dimension, "jumpStart"); + } + } + slider.animating = false; + slider.currentSlide = slider.animatingTo; + // API: after() animation Callback + slider.vars.after(slider); + }; + + // SLIDESHOW: + slider.animateSlides = function() { + if (!slider.animating && focused) {slider.flexAnimate(slider.getTarget("next"));} + }; + // SLIDESHOW: + slider.pause = function() { + clearInterval(slider.animatedSlides); + slider.animatedSlides = null; + slider.playing = false; + // PAUSEPLAY: + if (slider.vars.pausePlay) {methods.pausePlay.update("play");} + // SYNC: + if (slider.syncExists) {methods.sync("pause");} + }; + // SLIDESHOW: + slider.play = function() { + if (slider.playing) {clearInterval(slider.animatedSlides);} + slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed); + slider.started = slider.playing = true; + // PAUSEPLAY: + if (slider.vars.pausePlay) {methods.pausePlay.update("pause");} + // SYNC: + if (slider.syncExists) {methods.sync("play");} + }; + // STOP: + slider.stop = function() { + slider.pause(); + slider.stopped = true; + }; + slider.canAdvance = function(target, fromNav) { + // ASNAV: + var last = (asNav) ? slider.pagingCount - 1 : slider.last; + return (fromNav) ? true : + (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true : + (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false : + (target === slider.currentSlide && !asNav) ? false : + (slider.vars.animationLoop) ? true : + (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false : + (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false : + true; + }; + slider.getTarget = function(dir) { + slider.direction = dir; + if (dir === "next") { + return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1; + } else { + return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1; + } + }; + + // SLIDE: + slider.setProps = function(pos, special, dur) { + var target = (function() { + var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo, + posCalc = (function() { + if (carousel) { + return (special === "setTouch") ? pos : + (reverse && slider.animatingTo === slider.last) ? 0 : + (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) : + (slider.animatingTo === slider.last) ? slider.limit : posCheck; + } else { + switch (special) { + case "setTotal": + return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos; + case "setTouch": + return (reverse) ? pos : pos; + case "jumpEnd": + return (reverse) ? pos : slider.count * pos; + case "jumpStart": + return (reverse) ? slider.count * pos : pos; + default: + return pos; + } + } + }()); + + return (posCalc * -1) + "px"; + }()); + + if (slider.transitions) { + target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)"; + dur = (dur !== undefined) ? (dur / 1000) + "s" : "0s"; + slider.container.css("-" + slider.pfx + "-transition-duration", dur); + slider.container.css("transition-duration", dur); + } + + slider.args[slider.prop] = target; + if (slider.transitions || dur === undefined) {slider.container.css(slider.args);} + + slider.container.css('transform', target); + }; + + slider.setup = function(type) { + // SLIDE: + if (!fade) { + var sliderOffset, arr; + + if (type === "init") { + slider.viewport = $('
    ').css({ + "overflow": "hidden", + "position": "relative" + }).appendTo(slider).append(slider.container); + // INFINITE LOOP: + slider.cloneCount = 0; + slider.cloneOffset = 0; + // REVERSE: + if (reverse) { + arr = $.makeArray(slider.slides).reverse(); + slider.slides = $(arr); + slider.container.empty().append(slider.slides); + } + } + // INFINITE LOOP && !CAROUSEL: + if (slider.vars.animationLoop && !carousel) { + slider.cloneCount = 2; + slider.cloneOffset = 1; + // clear out old clones + if (type !== "init") { slider.container.find('.clone').remove(); } + slider.container.append(methods.uniqueID(slider.slides.first().clone().addClass('clone')).attr('aria-hidden', 'true')) + .prepend(methods.uniqueID(slider.slides.last().clone().addClass('clone')).attr('aria-hidden', 'true')); + } + slider.newSlides = $(slider.vars.selector, slider); + + sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset; + // VERTICAL: + if (vertical && !carousel) { + slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%"); + setTimeout(function() { + slider.newSlides.css({"display": "block"}); + slider.doMath(); + slider.viewport.height(slider.h); + slider.setProps(sliderOffset * slider.h, "init"); + }, (type === "init") ? 100 : 0); + } else { + slider.container.width((slider.count + slider.cloneCount) * 200 + "%"); + slider.setProps(sliderOffset * slider.computedW, "init"); + setTimeout(function() { + slider.doMath(); + slider.newSlides.css({"width": slider.computedW, "marginRight" : slider.computedM, "float": "left", "display": "block"}); + + // SMOOTH HEIGHT: + if (slider.vars.smoothHeight) {methods.smoothHeight();} + }, (type === "init") ? 100 : 0); + } + } else { // FADE: + slider.slides.css({ + "width": "100%", + "float": "left", + "marginRight": "-100%", + "position": "relative" + }); + if (type === "init") { + if (!touch) { + //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing); + if (slider.vars.fadeFirstSlide == false) { + slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1}); + } else { + slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing); + } + } else { + slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2}); + } + } + // SMOOTH HEIGHT: + if (slider.vars.smoothHeight) {methods.smoothHeight();} + } + // !CAROUSEL: + // CANDIDATE: active slide + if (!carousel) {slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide");} + + //FlexSlider: init() Callback + slider.vars.init(slider); + }; + + slider.doMath = function() { + var slide = slider.slides.first(), + slideMargin = slider.vars.itemMargin, + minItems = slider.vars.minItems, + maxItems = slider.vars.maxItems; + + slider.w = (slider.viewport === undefined) ? slider.width() : slider.viewport.width(); + slider.h = slide.height(); + slider.boxPadding = slide.outerWidth() - slide.width(); + + // CAROUSEL: + if (carousel) { + slider.itemT = slider.vars.itemWidth + slideMargin; + slider.itemM = slideMargin; + slider.minW = (minItems) ? minItems * slider.itemT : slider.w; + slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w; + slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1))) / minItems : + (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1))) / maxItems : + (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth; + + slider.visible = Math.floor(slider.w / (slider.itemW)); + slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible; + slider.pagingCount = Math.ceil(((slider.count - slider.visible) / slider.move) + 1); + slider.last = slider.pagingCount - 1; + slider.limit = (slider.pagingCount === 1) ? 0 : + (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin; + } else { + slider.itemW = slider.w; + slider.itemM = slideMargin; + slider.pagingCount = slider.count; + slider.last = slider.count - 1; + } + slider.computedW = slider.itemW - slider.boxPadding; + slider.computedM = slider.itemM; + }; + + slider.update = function(pos, action) { + slider.doMath(); + + // update currentSlide and slider.animatingTo if necessary + if (!carousel) { + if (pos < slider.currentSlide) { + slider.currentSlide += 1; + } else if (pos <= slider.currentSlide && pos !== 0) { + slider.currentSlide -= 1; + } + slider.animatingTo = slider.currentSlide; + } + + // update controlNav + if (slider.vars.controlNav && !slider.manualControls) { + if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) { + methods.controlNav.update("add"); + } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) { + if (carousel && slider.currentSlide > slider.last) { + slider.currentSlide -= 1; + slider.animatingTo -= 1; + } + methods.controlNav.update("remove", slider.last); + } + } + // update directionNav + if (slider.vars.directionNav) {methods.directionNav.update();} + + }; + + slider.addSlide = function(obj, pos) { + var $obj = $(obj); + + slider.count += 1; + slider.last = slider.count - 1; + + // append new slide + if (vertical && reverse) { + (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj); + } else { + (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj); + } + + // update currentSlide, animatingTo, controlNav, and directionNav + slider.update(pos, "add"); + + // update slider.slides + slider.slides = $(slider.vars.selector + ':not(.clone)', slider); + // re-setup the slider to accomdate new slide + slider.setup(); + + //FlexSlider: added() Callback + slider.vars.added(slider); + }; + slider.removeSlide = function(obj) { + var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj; + + // update count + slider.count -= 1; + slider.last = slider.count - 1; + + // remove slide + if (isNaN(obj)) { + $(obj, slider.slides).remove(); + } else { + (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove(); + } + + // update currentSlide, animatingTo, controlNav, and directionNav + slider.doMath(); + slider.update(pos, "remove"); + + // update slider.slides + slider.slides = $(slider.vars.selector + ':not(.clone)', slider); + // re-setup the slider to accomdate new slide + slider.setup(); + + // FlexSlider: removed() Callback + slider.vars.removed(slider); + }; + + //FlexSlider: Initialize + methods.init(); + }; + + // Ensure the slider isn't focussed if the window loses focus. + $(window).blur(function(e) { + focused = false; + }).focus(function(e) { + focused = true; + }); + + // FlexSlider: Default Settings + $.flexslider.defaults = { + namespace: 'am-', // {NEW} String: Prefix string attached to the class of every element generated by the plugin + selector: '.am-slides > li', // {NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril + animation: 'slide', // String: Select your animation type, 'fade' or 'slide' + easing: 'swing', // {NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported! + direction: 'horizontal', // String: Select the sliding direction, "horizontal" or "vertical" + reverse: false, // {NEW} Boolean: Reverse the animation direction + animationLoop: true, // Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end + smoothHeight: false, // {NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode + startAt: 0, // Integer: The slide that the slider should start on. Array notation (0 = first slide) + slideshow: true, // Boolean: Animate slider automatically + slideshowSpeed: 5000, // Integer: Set the speed of the slideshow cycling, in milliseconds + animationSpeed: 600, // Integer: Set the speed of animations, in milliseconds + initDelay: 0, // {NEW} Integer: Set an initialization delay, in milliseconds + randomize: false, // Boolean: Randomize slide order + fadeFirstSlide: true, // Boolean: Fade in the first slide when animation type is "fade" + thumbCaptions: false, // Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav. + + // Usability features + pauseOnAction: true, // Boolean: Pause the slideshow when interacting with control elements, highly recommended. + pauseOnHover: false, // Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering + pauseInvisible: true, // {NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage. + useCSS: true, // {NEW} Boolean: Slider will use CSS3 transitions if available + touch: true, // {NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices + video: false, // {NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches + + // Primary Controls + controlNav: true, // Boolean: Create navigation for paging control of each slide? Note: Leave true for manualControls usage + directionNav: true, // Boolean: Create navigation for previous/next navigation? (true/false) + prevText: ' ', // String: Set the text for the "previous" directionNav item + nextText: ' ', // String: Set the text for the "next" directionNav item + + // Secondary Navigation + keyboard: true, // Boolean: Allow slider navigating via keyboard left/right keys + multipleKeyboard: false, // {NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present. + mousewheel: false, // {UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel + pausePlay: false, // Boolean: Create pause/play dynamic element + pauseText: 'Pause', // String: Set the text for the 'pause' pausePlay item + playText: 'Play', // String: Set the text for the 'play' pausePlay item + + // Special properties + controlsContainer: '', // {UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $('.flexslider-container'). Property is ignored if given element is not found. + manualControls: '', // {UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs. + customDirectionNav: '', // {NEW} jQuery Object/Selector: Custom prev / next button. Must be two jQuery elements. In order to make the events work they have to have the classes "prev" and "next" (plus namespace) + sync: '', // {NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care. + asNavFor: '', // {NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider + + // Carousel Options + itemWidth: 0, // {NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding. + itemMargin: 0, // {NEW} Integer: Margin between carousel items. + minItems: 1, // {NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this. + maxItems: 0, // {NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit. + move: 0, // {NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items. + allowOneSlide: true, // {NEW} Boolean: Whether or not to allow a slider comprised of a single slide + + // Callback API + start: function() { + }, // Callback: function(slider) - Fires when the slider loads the first slide + before: function() { + }, // Callback: function(slider) - Fires asynchronously with each slider animation + after: function() { + }, // Callback: function(slider) - Fires after each slider animation completes + end: function() { + }, // Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous) + added: function() { + }, // {NEW} Callback: function(slider) - Fires after a slide is added + removed: function() { + }, // {NEW} Callback: function(slider) - Fires after a slide is removed + init: function() { + } // {NEW} Callback: function(slider) - Fires after the slider is initially setup + }; + + // FlexSlider: Plugin Function + $.fn.flexslider = function(options) { + var args = Array.prototype.slice.call(arguments, 1); + if (options === undefined) {options = {};} + + if (typeof options === 'object') { + return this.each(function() { + var $this = $(this); + var selector = (options.selector) ? options.selector : '.am-slides > li'; + var $slides = $this.find(selector); + + if (( $slides.length === 1 && options.allowOneSlide === false) || $slides.length === 0) { + $slides.fadeIn(400); + if (options.start) {options.start($this);} + } else if ($this.data('flexslider') === undefined) { + new $.flexslider(this, options); + } + }); + } else { + // Helper strings to quickly pecdrform functions on the slider + var $slider = $(this).data('flexslider'); + var methodReturn; + switch (options) { + case 'next': + $slider.flexAnimate($slider.getTarget('next'), true); + break; + case 'prev': + case 'previous': + $slider.flexAnimate($slider.getTarget('prev'), true); + break; + default: + if (typeof options === 'number') { + $slider.flexAnimate(options, true); + } else if (typeof options === 'string') { + methodReturn = (typeof $slider[options] === 'function') ? + $slider[options].apply($slider, args) : $slider[options]; + } + } + + return methodReturn === undefined ? this : methodReturn; + } + }; + + // Init code + UI.ready(function(context) { + $('[data-am-flexslider]', context).each(function(i, item) { + var $slider = $(item); + var options = UI.utils.parseOptions($slider.data('amFlexslider')); + + options.before = function(slider) { + if (slider._pausedTimer) { + window.clearTimeout(slider._pausedTimer); + slider._pausedTimer = null; + } + }; + + options.after = function(slider) { + var pauseTime = slider.vars.playAfterPaused; + if (pauseTime && !isNaN(pauseTime) && !slider.playing) { + if (!slider.manualPause && !slider.manualPlay && !slider.stopped) { + slider._pausedTimer = window.setTimeout(function() { + slider.play(); + }, pauseTime); + } + } + }; + + $slider.flexslider(options); + }); + }); + + module.exports = $.flexslider; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12).setImmediate)) + +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {var nextTick = __webpack_require__(13).nextTick; + var apply = Function.prototype.apply; + var slice = Array.prototype.slice; + var immediateIds = {}; + var nextImmediateId = 0; + + // DOM APIs, for completeness + + exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); + }; + exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); + }; + exports.clearTimeout = + exports.clearInterval = function(timeout) { timeout.close(); }; + + function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; + } + Timeout.prototype.unref = Timeout.prototype.ref = function() {}; + Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); + }; + + // Does not start the time, just sets up the members needed. + exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; + }; + + exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; + }; + + exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); + + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); + } + }; + + // That's not how node.js implements it but the exposed api is the same. + exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { + var id = nextImmediateId++; + var args = arguments.length < 2 ? false : slice.call(arguments, 1); + + immediateIds[id] = true; + + nextTick(function onNextTick() { + if (immediateIds[id]) { + // fn.call() is faster so we optimize for the common use-case + // @see http://jsperf.com/call-apply-segu + if (args) { + fn.apply(null, args); + } else { + fn.call(null); + } + // Prevent ids from leaking + exports.clearImmediate(id); + } + }); + + return id; + }; + + exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { + delete immediateIds[id]; + }; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12).setImmediate, __webpack_require__(12).clearImmediate)) + +/***/ }, +/* 13 */ +/***/ function(module, exports) { + + // shim for using process in browser + var process = module.exports = {}; + + // cached from whatever global is present so that test runners that stub it + // don't break things. But we need to wrap it in a try catch in case it is + // wrapped in strict mode code which doesn't define any globals. It's inside a + // function because try/catches deoptimize in certain engines. + + var cachedSetTimeout; + var cachedClearTimeout; + + (function () { + try { + cachedSetTimeout = setTimeout; + } catch (e) { + cachedSetTimeout = function () { + throw new Error('setTimeout is not defined'); + } + } + try { + cachedClearTimeout = clearTimeout; + } catch (e) { + cachedClearTimeout = function () { + throw new Error('clearTimeout is not defined'); + } + } + } ()) + function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + + } + function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + + } + var queue = []; + var draining = false; + var currentQueue; + var queueIndex = -1; + + function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } + } + + function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); + } + + process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } + }; + + // v8 likes predictible objects + function Item(fun, array) { + this.fun = fun; + this.array = array; + } + Item.prototype.run = function () { + this.fun.apply(null, this.array); + }; + process.title = 'browser'; + process.browser = true; + process.env = {}; + process.argv = []; + process.version = ''; // empty string to avoid regexp issues + process.versions = {}; + + function noop() {} + + process.on = noop; + process.addListener = noop; + process.once = noop; + process.off = noop; + process.removeListener = noop; + process.removeAllListeners = noop; + process.emit = noop; + + process.binding = function (name) { + throw new Error('process.binding is not supported'); + }; + + process.cwd = function () { return '/' }; + process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); + }; + process.umask = function() { return 0; }; + + +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var UI = __webpack_require__(2); + + /*! iScroll v5.2.0 + * (c) 2008-2016 Matteo Spinelli + * http://cubiq.org/license + */ + + var rAF = UI.utils.rAF; + + var utils = (function() { + var me = {}; + + var _elementStyle = document.createElement('div').style; + var _vendor = (function() { + var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], + transform, + i = 0, + l = vendors.length; + + for (; i < l; i++) { + transform = vendors[i] + 'ransform'; + if (transform in _elementStyle) return vendors[i].substr(0, vendors[i].length - 1); + } + + return false; + })(); + + function _prefixStyle(style) { + if (_vendor === false) return false; + if (_vendor === '') return style; + return _vendor + style.charAt(0).toUpperCase() + style.substr(1); + } + + me.getTime = Date.now || function getTime() { + return new Date().getTime(); + }; + + me.extend = function(target, obj) { + for (var i in obj) { + target[i] = obj[i]; + } + }; + + me.addEvent = function(el, type, fn, capture) { + el.addEventListener(type, fn, !!capture); + }; + + me.removeEvent = function(el, type, fn, capture) { + el.removeEventListener(type, fn, !!capture); + }; + + me.prefixPointerEvent = function(pointerEvent) { + return window.MSPointerEvent ? + 'MSPointer' + pointerEvent.charAt(7) + .toUpperCase() + pointerEvent.substr(8) : + pointerEvent; + }; + + me.momentum = function(current, start, time, lowerMargin, wrapperSize, deceleration) { + var distance = current - start, + speed = Math.abs(distance) / time, + destination, + duration; + + deceleration = deceleration === undefined ? 0.0006 : deceleration; + + destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); + duration = speed / deceleration; + + if (destination < lowerMargin) { + destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; + distance = Math.abs(destination - current); + duration = distance / speed; + } else if (destination > 0) { + destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; + distance = Math.abs(current) + destination; + duration = distance / speed; + } + + return { + destination: Math.round(destination), + duration: duration + }; + }; + + var _transform = _prefixStyle('transform'); + + me.extend(me, { + hasTransform: _transform !== false, + hasPerspective: _prefixStyle('perspective') in _elementStyle, + hasTouch: 'ontouchstart' in window, + hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed + hasTransition: _prefixStyle('transition') in _elementStyle + }); + + /* + This should find all Android browsers lower than build 535.19 (both stock browser and webview) + - galaxy S2 is ok + - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` + - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` + - galaxy S3 is badAndroid (stock brower, webview) + `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` + - galaxy S4 is badAndroid (stock brower, webview) + `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` + - galaxy S5 is OK + `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` + - galaxy S6 is OK + `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` + */ + me.isBadAndroid = (function() { + var appVersion = window.navigator.appVersion; + // Android browser is not a chrome browser. + if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { + var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); + if (safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { + return parseFloat(safariVersion[1]) < 535.19; + } else { + return true; + } + } else { + return false; + } + })(); + + me.extend(me.style = {}, { + transform: _transform, + transitionTimingFunction: _prefixStyle('transitionTimingFunction'), + transitionDuration: _prefixStyle('transitionDuration'), + transitionDelay: _prefixStyle('transitionDelay'), + transformOrigin: _prefixStyle('transformOrigin') + }); + + me.hasClass = function(e, c) { + var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); + return re.test(e.className); + }; + + me.addClass = function(e, c) { + if (me.hasClass(e, c)) { + return; + } + + var newclass = e.className.split(' '); + newclass.push(c); + e.className = newclass.join(' '); + }; + + me.removeClass = function(e, c) { + if (!me.hasClass(e, c)) { + return; + } + + var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); + e.className = e.className.replace(re, ' '); + }; + + me.offset = function(el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + // jshint -W084 + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + // jshint +W084 + + return { + left: left, + top: top + }; + }; + + me.preventDefaultException = function(el, exceptions) { + for (var i in exceptions) { + if (exceptions[i].test(el[i])) { + return true; + } + } + + return false; + }; + + me.extend(me.eventType = {}, { + touchstart: 1, + touchmove: 1, + touchend: 1, + + mousedown: 2, + mousemove: 2, + mouseup: 2, + + pointerdown: 3, + pointermove: 3, + pointerup: 3, + + MSPointerDown: 3, + MSPointerMove: 3, + MSPointerUp: 3 + }); + + me.extend(me.ease = {}, { + quadratic: { + style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', + fn: function(k) { + return k * ( 2 - k ); + } + }, + circular: { + style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) + fn: function(k) { + return Math.sqrt(1 - ( --k * k )); + } + }, + back: { + style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', + fn: function(k) { + var b = 4; + return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; + } + }, + bounce: { + style: '', + fn: function(k) { + if (( k /= 1 ) < ( 1 / 2.75 )) { + return 7.5625 * k * k; + } else if (k < ( 2 / 2.75 )) { + return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; + } else if (k < ( 2.5 / 2.75 )) { + return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; + } else { + return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; + } + } + }, + elastic: { + style: '', + fn: function(k) { + var f = 0.22, + e = 0.4; + + if (k === 0) { + return 0; + } + if (k == 1) { + return 1; + } + + return ( e * Math.pow(2, -10 * k) * Math.sin(( k - f / 4 ) * ( 2 * Math.PI ) / f) + 1 ); + } + } + }); + + me.tap = function(e, eventName) { + var ev = document.createEvent('Event'); + ev.initEvent(eventName, true, true); + ev.pageX = e.pageX; + ev.pageY = e.pageY; + e.target.dispatchEvent(ev); + }; + + me.click = function(e) { + var target = e.target, + ev; + + if (!(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName)) { + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent + // initMouseEvent is deprecated. + ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); + ev.initEvent('click', true, true); + ev.view = e.view || window; + ev.detail = 1; + ev.screenX = target.screenX || 0; + ev.screenY = target.screenY || 0; + ev.clientX = target.clientX || 0; + ev.clientY = target.clientY || 0; + ev.ctrlKey = !!e.ctrlKey; + ev.altKey = !!e.altKey; + ev.shiftKey = !!e.shiftKey; + ev.metaKey = !!e.metaKey; + ev.button = 0; + ev.relatedTarget = null; + ev._constructed = true; + target.dispatchEvent(ev); + } + }; + + return me; + })(); + function IScroll(el, options) { + this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; + this.scroller = this.wrapper.children[0]; + this.scrollerStyle = this.scroller.style; // cache style for better performance + + this.options = { + + // INSERT POINT: OPTIONS + disablePointer: !utils.hasPointer, + disableTouch: utils.hasPointer || !utils.hasTouch, + disableMouse: utils.hasPointer || utils.hasTouch, + startX: 0, + startY: 0, + scrollY: true, + directionLockThreshold: 5, + momentum: true, + + bounce: true, + bounceTime: 600, + bounceEasing: '', + + preventDefault: true, + preventDefaultException: {tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/}, + + HWCompositing: true, + useTransition: true, + useTransform: true, + bindToWrapper: typeof window.onmousedown === "undefined" + }; + + for (var i in options) { + this.options[i] = options[i]; + } + + // Normalize options + this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; + + this.options.useTransition = utils.hasTransition && this.options.useTransition; + this.options.useTransform = utils.hasTransform && this.options.useTransform; + + this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; + this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; + + // If you want eventPassthrough I have to lock one of the axes + this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; + this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; + + // With eventPassthrough we also need lockDirection mechanism + this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; + this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; + + this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; + + this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; + + if (this.options.tap === true) { + this.options.tap = 'tap'; + } + + // https://github.com/cubiq/iscroll/issues/1029 + if (!this.options.useTransition && !this.options.useTransform) { + if (!(/relative|absolute/i).test(this.scrollerStyle.position)) { + this.scrollerStyle.position = "relative"; + } + } + + // INSERT POINT: NORMALIZATION + + // Some defaults + this.x = 0; + this.y = 0; + this.directionX = 0; + this.directionY = 0; + this._events = {}; + + // INSERT POINT: DEFAULTS + + this._init(); + this.refresh(); + + this.scrollTo(this.options.startX, this.options.startY); + this.enable(); + } + + IScroll.prototype = { + version: '5.2.0', + + _init: function() { + this._initEvents(); + + // INSERT POINT: _init + + }, + + destroy: function() { + this._initEvents(true); + clearTimeout(this.resizeTimeout); + this.resizeTimeout = null; + this._execEvent('destroy'); + }, + + _transitionEnd: function(e) { + if (e.target != this.scroller || !this.isInTransition) { + return; + } + + this._transitionTime(); + if (!this.resetPosition(this.options.bounceTime)) { + this.isInTransition = false; + this._execEvent('scrollEnd'); + } + }, + + _start: function(e) { + // React to left mouse button only + if (utils.eventType[e.type] != 1) { + // for button property + // http://unixpapa.com/js/mouse.html + var button; + if (!e.which) { + /* IE case */ + button = (e.button < 2) ? 0 : + ((e.button == 4) ? 1 : 2); + } else { + /* All others */ + button = e.button; + } + if (button !== 0) { + return; + } + } + + if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) { + return; + } + + if (this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) { + e.preventDefault(); + } + + var point = e.touches ? e.touches[0] : e, + pos; + + this.initiated = utils.eventType[e.type]; + this.moved = false; + this.distX = 0; + this.distY = 0; + this.directionX = 0; + this.directionY = 0; + this.directionLocked = 0; + + this.startTime = utils.getTime(); + + if (this.options.useTransition && this.isInTransition) { + this._transitionTime(); + this.isInTransition = false; + pos = this.getComputedPosition(); + this._translate(Math.round(pos.x), Math.round(pos.y)); + this._execEvent('scrollEnd'); + } else if (!this.options.useTransition && this.isAnimating) { + this.isAnimating = false; + this._execEvent('scrollEnd'); + } + + this.startX = this.x; + this.startY = this.y; + this.absStartX = this.x; + this.absStartY = this.y; + this.pointX = point.pageX; + this.pointY = point.pageY; + + this._execEvent('beforeScrollStart'); + }, + + _move: function(e) { + if (!this.enabled || utils.eventType[e.type] !== this.initiated) { + return; + } + + if (this.options.preventDefault) { // increases performance on Android? TODO: check! + e.preventDefault(); + } + + var point = e.touches ? e.touches[0] : e, + deltaX = point.pageX - this.pointX, + deltaY = point.pageY - this.pointY, + timestamp = utils.getTime(), + newX, newY, + absDistX, absDistY; + + this.pointX = point.pageX; + this.pointY = point.pageY; + + this.distX += deltaX; + this.distY += deltaY; + absDistX = Math.abs(this.distX); + absDistY = Math.abs(this.distY); + + // We need to move at least 10 pixels for the scrolling to initiate + if (timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10)) { + return; + } + + // If you are scrolling in one direction lock the other + if (!this.directionLocked && !this.options.freeScroll) { + if (absDistX > absDistY + this.options.directionLockThreshold) { + this.directionLocked = 'h'; // lock horizontally + } else if (absDistY >= absDistX + this.options.directionLockThreshold) { + this.directionLocked = 'v'; // lock vertically + } else { + this.directionLocked = 'n'; // no lock + } + } + + if (this.directionLocked == 'h') { + if (this.options.eventPassthrough == 'vertical') { + e.preventDefault(); + } else if (this.options.eventPassthrough == 'horizontal') { + this.initiated = false; + return; + } + + deltaY = 0; + } else if (this.directionLocked == 'v') { + if (this.options.eventPassthrough == 'horizontal') { + e.preventDefault(); + } else if (this.options.eventPassthrough == 'vertical') { + this.initiated = false; + return; + } + + deltaX = 0; + } + + deltaX = this.hasHorizontalScroll ? deltaX : 0; + deltaY = this.hasVerticalScroll ? deltaY : 0; + + newX = this.x + deltaX; + newY = this.y + deltaY; + + // Slow down if outside of the boundaries + if (newX > 0 || newX < this.maxScrollX) { + newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; + } + if (newY > 0 || newY < this.maxScrollY) { + newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; + } + + this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if (!this.moved) { + this._execEvent('scrollStart'); + } + + this.moved = true; + + this._translate(newX, newY); + + /* REPLACE START: _move */ + + if (timestamp - this.startTime > 300) { + this.startTime = timestamp; + this.startX = this.x; + this.startY = this.y; + } + + /* REPLACE END: _move */ + + }, + + _end: function(e) { + if (!this.enabled || utils.eventType[e.type] !== this.initiated) { + return; + } + + if (this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) { + e.preventDefault(); + } + + var point = e.changedTouches ? e.changedTouches[0] : e, + momentumX, + momentumY, + duration = utils.getTime() - this.startTime, + newX = Math.round(this.x), + newY = Math.round(this.y), + distanceX = Math.abs(newX - this.startX), + distanceY = Math.abs(newY - this.startY), + time = 0, + easing = ''; + + this.isInTransition = 0; + this.initiated = 0; + this.endTime = utils.getTime(); + + // reset if we are outside of the boundaries + if (this.resetPosition(this.options.bounceTime)) { + return; + } + + this.scrollTo(newX, newY); // ensures that the last position is rounded + + // we scrolled less than 10 pixels + if (!this.moved) { + if (this.options.tap) { + utils.tap(e, this.options.tap); + } + + if (this.options.click) { + utils.click(e); + } + + this._execEvent('scrollCancel'); + return; + } + + if (this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100) { + this._execEvent('flick'); + return; + } + + // start momentum animation if needed + if (this.options.momentum && duration < 300) { + momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { + destination: newX, + duration: 0 + }; + momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { + destination: newY, + duration: 0 + }; + newX = momentumX.destination; + newY = momentumY.destination; + time = Math.max(momentumX.duration, momentumY.duration); + this.isInTransition = 1; + } + + // INSERT POINT: _end + + if (newX != this.x || newY != this.y) { + // change easing function when scroller goes out of the boundaries + if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY) { + easing = utils.ease.quadratic; + } + + this.scrollTo(newX, newY, time, easing); + return; + } + + this._execEvent('scrollEnd'); + }, + + _resize: function() { + var that = this; + + clearTimeout(this.resizeTimeout); + + this.resizeTimeout = setTimeout(function() { + that.refresh(); + }, this.options.resizePolling); + }, + + resetPosition: function(time) { + var x = this.x, + y = this.y; + + time = time || 0; + + if (!this.hasHorizontalScroll || this.x > 0) { + x = 0; + } else if (this.x < this.maxScrollX) { + x = this.maxScrollX; + } + + if (!this.hasVerticalScroll || this.y > 0) { + y = 0; + } else if (this.y < this.maxScrollY) { + y = this.maxScrollY; + } + + if (x == this.x && y == this.y) { + return false; + } + + this.scrollTo(x, y, time, this.options.bounceEasing); + + return true; + }, + + disable: function() { + this.enabled = false; + }, + + enable: function() { + this.enabled = true; + }, + + refresh: function() { + var rf = this.wrapper.offsetHeight; // Force reflow + + this.wrapperWidth = this.wrapper.clientWidth; + this.wrapperHeight = this.wrapper.clientHeight; + + /* REPLACE START: refresh */ + + this.scrollerWidth = this.scroller.offsetWidth; + this.scrollerHeight = this.scroller.offsetHeight; + + this.maxScrollX = this.wrapperWidth - this.scrollerWidth; + this.maxScrollY = this.wrapperHeight - this.scrollerHeight; + + /* REPLACE END: refresh */ + + this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; + this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; + + if (!this.hasHorizontalScroll) { + this.maxScrollX = 0; + this.scrollerWidth = this.wrapperWidth; + } + + if (!this.hasVerticalScroll) { + this.maxScrollY = 0; + this.scrollerHeight = this.wrapperHeight; + } + + this.endTime = 0; + this.directionX = 0; + this.directionY = 0; + + this.wrapperOffset = utils.offset(this.wrapper); + + this._execEvent('refresh'); + + this.resetPosition(); + + // INSERT POINT: _refresh + + }, + + on: function(type, fn) { + if (!this._events[type]) { + this._events[type] = []; + } + + this._events[type].push(fn); + }, + + off: function(type, fn) { + if (!this._events[type]) { + return; + } + + var index = this._events[type].indexOf(fn); + + if (index > -1) { + this._events[type].splice(index, 1); + } + }, + + _execEvent: function(type) { + if (!this._events[type]) { + return; + } + + var i = 0, + l = this._events[type].length; + + if (!l) { + return; + } + + for (; i < l; i++) { + this._events[type][i].apply(this, [].slice.call(arguments, 1)); + } + }, + + scrollBy: function(x, y, time, easing) { + x = this.x + x; + y = this.y + y; + time = time || 0; + + this.scrollTo(x, y, time, easing); + }, + + scrollTo: function(x, y, time, easing) { + easing = easing || utils.ease.circular; + + this.isInTransition = this.options.useTransition && time > 0; + var transitionType = this.options.useTransition && easing.style; + if (!time || transitionType) { + if (transitionType) { + this._transitionTimingFunction(easing.style); + this._transitionTime(time); + } + this._translate(x, y); + } else { + this._animate(x, y, time, easing.fn); + } + }, + + scrollToElement: function(el, time, offsetX, offsetY, easing) { + el = el.nodeType ? el : this.scroller.querySelector(el); + + if (!el) { + return; + } + + var pos = utils.offset(el); + + pos.left -= this.wrapperOffset.left; + pos.top -= this.wrapperOffset.top; + + // if offsetX/Y are true we center the element to the screen + if (offsetX === true) { + offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); + } + if (offsetY === true) { + offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); + } + + pos.left -= offsetX || 0; + pos.top -= offsetY || 0; + + pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; + pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; + + time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x - pos.left), Math.abs(this.y - pos.top)) : time; + + this.scrollTo(pos.left, pos.top, time, easing); + }, + + _transitionTime: function(time) { + if (!this.options.useTransition) { + return; + } + time = time || 0; + var durationProp = utils.style.transitionDuration; + if (!durationProp) { + return; + } + + this.scrollerStyle[durationProp] = time + 'ms'; + + if (!time && utils.isBadAndroid) { + this.scrollerStyle[durationProp] = '0.0001ms'; + // remove 0.0001ms + var self = this; + rAF(function() { + if (self.scrollerStyle[durationProp] === '0.0001ms') { + self.scrollerStyle[durationProp] = '0s'; + } + }); + } + + // INSERT POINT: _transitionTime + + }, + + _transitionTimingFunction: function(easing) { + this.scrollerStyle[utils.style.transitionTimingFunction] = easing; + + // INSERT POINT: _transitionTimingFunction + + }, + + _translate: function(x, y) { + if (this.options.useTransform) { + + /* REPLACE START: _translate */ + + this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; + + /* REPLACE END: _translate */ + + } else { + x = Math.round(x); + y = Math.round(y); + this.scrollerStyle.left = x + 'px'; + this.scrollerStyle.top = y + 'px'; + } + + this.x = x; + this.y = y; + + // INSERT POINT: _translate + + }, + + _initEvents: function(remove) { + var eventType = remove ? utils.removeEvent : utils.addEvent, + target = this.options.bindToWrapper ? this.wrapper : window; + + eventType(window, 'orientationchange', this); + eventType(window, 'resize', this); + + if (this.options.click) { + eventType(this.wrapper, 'click', this, true); + } + + if (!this.options.disableMouse) { + eventType(this.wrapper, 'mousedown', this); + eventType(target, 'mousemove', this); + eventType(target, 'mousecancel', this); + eventType(target, 'mouseup', this); + } + + if (utils.hasPointer && !this.options.disablePointer) { + eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); + eventType(target, utils.prefixPointerEvent('pointermove'), this); + eventType(target, utils.prefixPointerEvent('pointercancel'), this); + eventType(target, utils.prefixPointerEvent('pointerup'), this); + } + + if (utils.hasTouch && !this.options.disableTouch) { + eventType(this.wrapper, 'touchstart', this); + eventType(target, 'touchmove', this); + eventType(target, 'touchcancel', this); + eventType(target, 'touchend', this); + } + + eventType(this.scroller, 'transitionend', this); + eventType(this.scroller, 'webkitTransitionEnd', this); + eventType(this.scroller, 'oTransitionEnd', this); + eventType(this.scroller, 'MSTransitionEnd', this); + }, + + getComputedPosition: function() { + var matrix = window.getComputedStyle(this.scroller, null), + x, y; + + if (this.options.useTransform) { + matrix = matrix[utils.style.transform].split(')')[0].split(', '); + x = +(matrix[12] || matrix[4]); + y = +(matrix[13] || matrix[5]); + } else { + x = +matrix.left.replace(/[^-\d.]/g, ''); + y = +matrix.top.replace(/[^-\d.]/g, ''); + } + + return {x: x, y: y}; + }, + _animate: function(destX, destY, duration, easingFn) { + var that = this, + startX = this.x, + startY = this.y, + startTime = utils.getTime(), + destTime = startTime + duration; + + function step() { + var now = utils.getTime(), + newX, newY, + easing; + + if (now >= destTime) { + that.isAnimating = false; + that._translate(destX, destY); + + if (!that.resetPosition(that.options.bounceTime)) { + that._execEvent('scrollEnd'); + } + + return; + } + + now = ( now - startTime ) / duration; + easing = easingFn(now); + newX = ( destX - startX ) * easing + startX; + newY = ( destY - startY ) * easing + startY; + that._translate(newX, newY); + + if (that.isAnimating) { + rAF(step); + } + } + + this.isAnimating = true; + step(); + }, + handleEvent: function(e) { + switch (e.type) { + case 'touchstart': + case 'pointerdown': + case 'MSPointerDown': + case 'mousedown': + this._start(e); + break; + case 'touchmove': + case 'pointermove': + case 'MSPointerMove': + case 'mousemove': + this._move(e); + break; + case 'touchend': + case 'pointerup': + case 'MSPointerUp': + case 'mouseup': + case 'touchcancel': + case 'pointercancel': + case 'MSPointerCancel': + case 'mousecancel': + this._end(e); + break; + case 'orientationchange': + case 'resize': + this._resize(); + break; + case 'transitionend': + case 'webkitTransitionEnd': + case 'oTransitionEnd': + case 'MSTransitionEnd': + this._transitionEnd(e); + break; + case 'wheel': + case 'DOMMouseScroll': + case 'mousewheel': + this._wheel(e); + break; + case 'keydown': + this._key(e); + break; + case 'click': + if (this.enabled && !e._constructed) { + e.preventDefault(); + e.stopPropagation(); + } + break; + } + } + }; + + IScroll.utils = utils; + + module.exports = UI.iScroll = IScroll; + + /* jshint unused: true */ + /* jshint +W101, +W116, +W109 */ + + +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var dimmer = __webpack_require__(9); + var $doc = $(document); + var supportTransition = UI.support.transition; + + /** + * @reference https://github.com/nolimits4web/Framework7/blob/master/src/js/modals.js + * @license https://github.com/nolimits4web/Framework7/blob/master/LICENSE + */ + + var Modal = function(element, options) { + this.options = $.extend({}, Modal.DEFAULTS, options || {}); + this.$element = $(element); + this.$dialog = this.$element.find('.am-modal-dialog'); + + if (!this.$element.attr('id')) { + this.$element.attr('id', UI.utils.generateGUID('am-modal')); + } + + this.isPopup = this.$element.hasClass('am-popup'); + this.isActions = this.$element.hasClass('am-modal-actions'); + this.isPrompt = this.$element.hasClass('am-modal-prompt'); + this.isLoading = this.$element.hasClass('am-modal-loading'); + this.active = this.transitioning = this.relatedTarget = null; + this.dimmer = this.options.dimmer ? dimmer : { + open: function() { + }, + close: function() { + } + }; + + this.events(); + }; + + Modal.DEFAULTS = { + className: { + active: 'am-modal-active', + out: 'am-modal-out' + }, + selector: { + modal: '.am-modal', + active: '.am-modal-active' + }, + closeViaDimmer: true, + cancelable: true, + onConfirm: function() { + }, + onCancel: function() { + }, + closeOnCancel: true, + closeOnConfirm: true, + dimmer: true, + height: undefined, + width: undefined, + duration: 300, // must equal the CSS transition duration + transitionEnd: supportTransition && supportTransition.end + '.modal.amui' + }; + + Modal.prototype.toggle = function(relatedTarget) { + return this.active ? this.close() : this.open(relatedTarget); + }; + + Modal.prototype.open = function(relatedTarget) { + var $element = this.$element; + var options = this.options; + var isPopup = this.isPopup; + var width = options.width; + var height = options.height; + var style = {}; + + if (this.active) { + return; + } + + if (!this.$element.length) { + return; + } + + // callback hook + relatedTarget && (this.relatedTarget = relatedTarget); + + // 判断如果还在动画,就先触发之前的closed事件 + if (this.transitioning) { + clearTimeout($element.transitionEndTimmer); + $element.transitionEndTimmer = null; + $element.trigger(options.transitionEnd) + .off(options.transitionEnd); + } + + isPopup && this.$element.show(); + + this.active = true; + + $element.trigger($.Event('open.modal.amui', {relatedTarget: relatedTarget})); + + this.dimmer.open($element); + + $element.show().redraw(); + + // apply Modal width/height if set + if (!isPopup && !this.isActions) { + if (width) { + style.width = parseInt(width, 10) + 'px'; + } + + if (height) { + style.height = parseInt(height, 10) + 'px'; + } + + this.$dialog.css(style); + } + + $element + .removeClass(options.className.out) + .addClass(options.className.active); + + this.transitioning = 1; + + var complete = function() { + $element.trigger($.Event('opened.modal.amui', { + relatedTarget: relatedTarget + })); + this.transitioning = 0; + + // Prompt auto focus + if (this.isPrompt) { + this.$dialog.find('input').eq(0).focus(); + } + }; + + if (!supportTransition) { + return complete.call(this); + } + + $element + .one(options.transitionEnd, $.proxy(complete, this)) + .emulateTransitionEnd(options.duration); + }; + + Modal.prototype.close = function(relatedTarget) { + if (!this.active) { + return; + } + + var $element = this.$element; + var options = this.options; + var isPopup = this.isPopup; + + // 判断如果还在动画,就先触发之前的opened事件 + if (this.transitioning) { + clearTimeout($element.transitionEndTimmer); + $element.transitionEndTimmer = null; + $element.trigger(options.transitionEnd).off(options.transitionEnd); + this.dimmer.close($element, true); + } + + this.$element.trigger($.Event('close.modal.amui', { + relatedTarget: relatedTarget + })); + + this.transitioning = 1; + + var complete = function() { + $element.trigger('closed.modal.amui'); + isPopup && $element.removeClass(options.className.out); + $element.hide(); + this.transitioning = 0; + // 不强制关闭 Dimmer,以便多个 Modal 可以共享 Dimmer + this.dimmer.close($element, false); + this.active = false; + }; + + $element.removeClass(options.className.active) + .addClass(options.className.out); + + if (!supportTransition) { + return complete.call(this); + } + + $element.one(options.transitionEnd, $.proxy(complete, this)) + .emulateTransitionEnd(options.duration); + }; + + Modal.prototype.events = function() { + var _this = this; + var options = this.options; + var $element = this.$element; + var $dimmer = this.dimmer.$element; + var $ipt = $element.find('.am-modal-prompt-input'); + var $confirm = $element.find('[data-am-modal-confirm]'); + var $cancel = $element.find('[data-am-modal-cancel]'); + var getData = function() { + var data = []; + $ipt.each(function() { + data.push($(this).val()); + }); + + return (data.length === 0) ? undefined : + ((data.length === 1) ? data[0] : data); + }; + + // close via Esc key + if (this.options.cancelable) { + $element.on('keyup.modal.amui', function(e) { + if (_this.active && e.which === 27) { + $element.trigger('cancel.modal.amui'); + _this.close(); + } + }); + } + + // Close Modal when dimmer clicked + if (this.options.dimmer && this.options.closeViaDimmer && !this.isLoading) { + $dimmer.on('click.dimmer.modal.amui', function() { + _this.close(); + }); + } + + // Close Modal when button clicked + $element.on( + 'click.close.modal.amui', + '[data-am-modal-close], .am-modal-btn', + function(e) { + e.preventDefault(); + var $this = $(this); + + if ($this.is($confirm)) { + options.closeOnConfirm && _this.close(); + } else if ($this.is($cancel)) { + options.closeOnCancel && _this.close(); + } else { + _this.close(); + } + } + ) + // trigger dimmer click event if non-dialog area clicked + // fixes #882 caused by https://github.com/amazeui/amazeui/commit/b6be7719681193f1c4cb04af89cb9fd9f4422163 + .on('click', function(e) { + // fixes #900 + // e.stopPropagation(); + $(e.target).is($element) && $dimmer.trigger('click.dimmer.modal.amui'); + }); + + $confirm.on('click.confirm.modal.amui', + function() { + $element.trigger($.Event('confirm.modal.amui', { + trigger: this + })); + }); + + $cancel.on('click.cancel.modal.amui', function() { + $element.trigger($.Event('cancel.modal.amui', { + trigger: this + })); + }); + + $element.on('confirm.modal.amui', function(e) { + e.data = getData(); + _this.options.onConfirm.call(_this, e); + }).on('cancel.modal.amui', function(e) { + e.data = getData(); + _this.options.onCancel.call(_this, e); + }); + }; + + function Plugin(option, relatedTarget) { + return this.each(function() { + var $this = $(this); + var data = $this.data('amui.modal'); + var options = typeof option == 'object' && option; + + if (!data) { + $this.data('amui.modal', (data = new Modal(this, options))); + } + + if (typeof option == 'string') { + data[option] && data[option](relatedTarget); + } else { + data.toggle(option && option.relatedTarget || undefined); + } + }); + } + + $.fn.modal = Plugin; + + // Init + $doc.on('click.modal.amui.data-api', '[data-am-modal]', function() { + var $this = $(this); + var options = UI.utils.parseOptions($this.attr('data-am-modal')); + var $target = $(options.target || + (this.href && this.href.replace(/.*(?=#[^\s]+$)/, ''))); + var option = $target.data('amui.modal') ? 'toggle' : options; + + Plugin.call($target, option, this); + }); + + module.exports = UI.modal = Modal; + + +/***/ }, +/* 16 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + __webpack_require__(3); + + var $win = $(window); + var $doc = $(document); + var scrollPos; + + /** + * @via https://github.com/uikit/uikit/blob/master/src/js/offcanvas.js + * @license https://github.com/uikit/uikit/blob/master/LICENSE.md + */ + + var OffCanvas = function(element, options) { + this.$element = $(element); + this.options = $.extend({}, OffCanvas.DEFAULTS, options); + this.active = null; + this.bindEvents(); + }; + + OffCanvas.DEFAULTS = { + duration: 300, + effect: 'overlay' // {push|overlay}, push is too expensive + }; + + OffCanvas.prototype.open = function(relatedElement) { + var _this = this; + var $element = this.$element; + + if (!$element.length || $element.hasClass('am-active')) { + return; + } + + var effect = this.options.effect; + var $html = $('html'); + var $body = $('body'); + var $bar = $element.find('.am-offcanvas-bar').first(); + var dir = $bar.hasClass('am-offcanvas-bar-flip') ? -1 : 1; + + $bar.addClass('am-offcanvas-bar-' + effect); + + scrollPos = {x: window.scrollX, y: window.scrollY}; + + $element.addClass('am-active'); + + $body.css({ + width: window.innerWidth, + height: $win.height() + }).addClass('am-offcanvas-page'); + + if (effect !== 'overlay') { + $body.css({ + 'margin-left': $bar.outerWidth() * dir + }).width(); // force redraw + } + + $html.css('margin-top', scrollPos.y * -1); + + setTimeout(function() { + $bar.addClass('am-offcanvas-bar-active').width(); + }, 0); + + $element.trigger('open.offcanvas.amui'); + + this.active = 1; + + // Close OffCanvas when none content area clicked + $element.on('click.offcanvas.amui', function(e) { + var $target = $(e.target); + + if ($target.hasClass('am-offcanvas-bar')) { + return; + } + + if ($target.parents('.am-offcanvas-bar').first().length) { + return; + } + + // https://developer.mozilla.org/zh-CN/docs/DOM/event.stopImmediatePropagation + e.stopImmediatePropagation(); + + _this.close(); + }); + + $html.on('keydown.offcanvas.amui', function(e) { + (e.keyCode === 27) && _this.close(); + }); + }; + + OffCanvas.prototype.close = function(relatedElement) { + var _this = this; + var $html = $('html'); + var $body = $('body'); + var $element = this.$element; + var $bar = $element.find('.am-offcanvas-bar').first(); + + if (!$element.length || !this.active || !$element.hasClass('am-active')) { + return; + } + + $element.trigger('close.offcanvas.amui'); + + function complete() { + $body + .removeClass('am-offcanvas-page') + .css({ + width: '', + height: '', + 'margin-left': '', + 'margin-right': '' + }); + $element.removeClass('am-active'); + $bar.removeClass('am-offcanvas-bar-active'); + $html.css('margin-top', ''); + window.scrollTo(scrollPos.x, scrollPos.y); + $element.trigger('closed.offcanvas.amui'); + _this.active = 0; + } + + if (UI.support.transition) { + setTimeout(function() { + $bar.removeClass('am-offcanvas-bar-active'); + }, 0); + + $body.css('margin-left', '').one(UI.support.transition.end, function() { + complete(); + }).emulateTransitionEnd(this.options.duration); + } else { + complete(); + } + + $element.off('click.offcanvas.amui'); + $html.off('.offcanvas.amui'); + }; + + OffCanvas.prototype.bindEvents = function() { + var _this = this; + $doc.on('click.offcanvas.amui', '[data-am-dismiss="offcanvas"]', function(e) { + e.preventDefault(); + _this.close(); + }); + + $win.on('resize.offcanvas.amui orientationchange.offcanvas.amui', + function() { + _this.active && _this.close(); + }); + + this.$element.hammer().on('swipeleft swipeleft', function(e) { + e.preventDefault(); + _this.close(); + }); + + return this; + }; + + function Plugin(option, relatedElement) { + var args = Array.prototype.slice.call(arguments, 1); + + return this.each(function() { + var $this = $(this); + var data = $this.data('amui.offcanvas'); + var options = $.extend({}, typeof option == 'object' && option); + + if (!data) { + $this.data('amui.offcanvas', (data = new OffCanvas(this, options))); + (!option || typeof option == 'object') && data.open(relatedElement); + } + + if (typeof option == 'string') { + data[option] && data[option].apply(data, args); + } + }); + } + + $.fn.offCanvas = Plugin; + + // Init code + $doc.on('click.offcanvas.amui', '[data-am-offcanvas]', function(e) { + e.preventDefault(); + var $this = $(this); + var options = UI.utils.parseOptions($this.data('amOffcanvas')); + var $target = $(options.target || + (this.href && this.href.replace(/.*(?=#[^\s]+$)/, ''))); + var option = $target.data('amui.offcanvas') ? 'open' : options; + + Plugin.call($target, option, this); + }); + + module.exports = UI.offcanvas = OffCanvas; + + // TODO: 优化动画效果 + // http://dbushell.github.io/Responsive-Off-Canvas-Menu/step4.html + + +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var requestAnimationFrame = UI.utils.rAF; + + /** + * @via https://github.com/manuelstofer/pinchzoom/blob/master/src/pinchzoom.js + * @license the MIT License. + */ + + var definePinchZoom = function($) { + + /** + * Pinch zoom using jQuery + * @version 0.0.2 + * @author Manuel Stofer + * @param el + * @param options + * @constructor + */ + var PinchZoom = function(el, options) { + this.el = $(el); + this.zoomFactor = 1; + this.lastScale = 1; + this.offset = { + x: 0, + y: 0 + }; + this.options = $.extend({}, this.defaults, options); + this.setupMarkup(); + this.bindEvents(); + this.update(); + // default enable. + this.enable(); + + }, + sum = function(a, b) { + return a + b; + }, + isCloseTo = function(value, expected) { + return value > expected - 0.01 && value < expected + 0.01; + }; + + PinchZoom.prototype = { + + defaults: { + tapZoomFactor: 2, + zoomOutFactor: 1.3, + animationDuration: 300, + maxZoom: 4, + minZoom: 0.5, + lockDragAxis: false, + use2d: true, + zoomStartEventName: 'pz_zoomstart', + zoomEndEventName: 'pz_zoomend', + dragStartEventName: 'pz_dragstart', + dragEndEventName: 'pz_dragend', + doubleTapEventName: 'pz_doubletap' + }, + + /** + * Event handler for 'dragstart' + * @param event + */ + handleDragStart: function(event) { + this.el.trigger(this.options.dragStartEventName); + this.stopAnimation(); + this.lastDragPosition = false; + this.hasInteraction = true; + this.handleDrag(event); + }, + + /** + * Event handler for 'drag' + * @param event + */ + handleDrag: function(event) { + + if (this.zoomFactor > 1.0) { + var touch = this.getTouches(event)[0]; + this.drag(touch, this.lastDragPosition); + this.offset = this.sanitizeOffset(this.offset); + this.lastDragPosition = touch; + } + }, + + handleDragEnd: function() { + this.el.trigger(this.options.dragEndEventName); + this.end(); + }, + + /** + * Event handler for 'zoomstart' + * @param event + */ + handleZoomStart: function(event) { + this.el.trigger(this.options.zoomStartEventName); + this.stopAnimation(); + this.lastScale = 1; + this.nthZoom = 0; + this.lastZoomCenter = false; + this.hasInteraction = true; + }, + + /** + * Event handler for 'zoom' + * @param event + */ + handleZoom: function(event, newScale) { + + // a relative scale factor is used + var touchCenter = this.getTouchCenter(this.getTouches(event)), + scale = newScale / this.lastScale; + this.lastScale = newScale; + + // the first touch events are thrown away since they are not precise + this.nthZoom += 1; + if (this.nthZoom > 3) { + + this.scale(scale, touchCenter); + this.drag(touchCenter, this.lastZoomCenter); + } + this.lastZoomCenter = touchCenter; + }, + + handleZoomEnd: function() { + this.el.trigger(this.options.zoomEndEventName); + this.end(); + }, + + /** + * Event handler for 'doubletap' + * @param event + */ + handleDoubleTap: function(event) { + var center = this.getTouches(event)[0], + zoomFactor = this.zoomFactor > 1 ? 1 : this.options.tapZoomFactor, + startZoomFactor = this.zoomFactor, + updateProgress = (function(progress) { + this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor), center); + }).bind(this); + + if (this.hasInteraction) { + return; + } + if (startZoomFactor > zoomFactor) { + center = this.getCurrentZoomCenter(); + } + + this.animate(this.options.animationDuration, updateProgress, this.swing); + this.el.trigger(this.options.doubleTapEventName); + }, + + /** + * Max / min values for the offset + * @param offset + * @return {Object} the sanitized offset + */ + sanitizeOffset: function(offset) { + var maxX = (this.zoomFactor - 1) * this.getContainerX(), + maxY = (this.zoomFactor - 1) * this.getContainerY(), + maxOffsetX = Math.max(maxX, 0), + maxOffsetY = Math.max(maxY, 0), + minOffsetX = Math.min(maxX, 0), + minOffsetY = Math.min(maxY, 0); + + return { + x: Math.min(Math.max(offset.x, minOffsetX), maxOffsetX), + y: Math.min(Math.max(offset.y, minOffsetY), maxOffsetY) + }; + }, + + /** + * Scale to a specific zoom factor (not relative) + * @param zoomFactor + * @param center + */ + scaleTo: function(zoomFactor, center) { + this.scale(zoomFactor / this.zoomFactor, center); + }, + + /** + * Scales the element from specified center + * @param scale + * @param center + */ + scale: function(scale, center) { + scale = this.scaleZoomFactor(scale); + this.addOffset({ + x: (scale - 1) * (center.x + this.offset.x), + y: (scale - 1) * (center.y + this.offset.y) + }); + }, + + /** + * Scales the zoom factor relative to current state + * @param scale + * @return the actual scale (can differ because of max min zoom factor) + */ + scaleZoomFactor: function(scale) { + var originalZoomFactor = this.zoomFactor; + this.zoomFactor *= scale; + this.zoomFactor = Math.min(this.options.maxZoom, Math.max(this.zoomFactor, this.options.minZoom)); + return this.zoomFactor / originalZoomFactor; + }, + + /** + * Drags the element + * @param center + * @param lastCenter + */ + drag: function(center, lastCenter) { + if (lastCenter) { + if (this.options.lockDragAxis) { + // lock scroll to position that was changed the most + if (Math.abs(center.x - lastCenter.x) > Math.abs(center.y - lastCenter.y)) { + this.addOffset({ + x: -(center.x - lastCenter.x), + y: 0 + }); + } + else { + this.addOffset({ + y: -(center.y - lastCenter.y), + x: 0 + }); + } + } + else { + this.addOffset({ + y: -(center.y - lastCenter.y), + x: -(center.x - lastCenter.x) + }); + } + } + }, + + /** + * Calculates the touch center of multiple touches + * @param touches + * @return {Object} + */ + getTouchCenter: function(touches) { + return this.getVectorAvg(touches); + }, + + /** + * Calculates the average of multiple vectors (x, y values) + */ + getVectorAvg: function(vectors) { + return { + x: vectors.map(function(v) { + return v.x; + }).reduce(sum) / vectors.length, + y: vectors.map(function(v) { + return v.y; + }).reduce(sum) / vectors.length + }; + }, + + /** + * Adds an offset + * @param offset the offset to add + * @return return true when the offset change was accepted + */ + addOffset: function(offset) { + this.offset = { + x: this.offset.x + offset.x, + y: this.offset.y + offset.y + }; + }, + + sanitize: function() { + if (this.zoomFactor < this.options.zoomOutFactor) { + this.zoomOutAnimation(); + } else if (this.isInsaneOffset(this.offset)) { + this.sanitizeOffsetAnimation(); + } + }, + + /** + * Checks if the offset is ok with the current zoom factor + * @param offset + * @return {Boolean} + */ + isInsaneOffset: function(offset) { + var sanitizedOffset = this.sanitizeOffset(offset); + return sanitizedOffset.x !== offset.x || + sanitizedOffset.y !== offset.y; + }, + + /** + * Creates an animation moving to a sane offset + */ + sanitizeOffsetAnimation: function() { + var targetOffset = this.sanitizeOffset(this.offset), + startOffset = { + x: this.offset.x, + y: this.offset.y + }, + updateProgress = (function(progress) { + this.offset.x = startOffset.x + progress * (targetOffset.x - startOffset.x); + this.offset.y = startOffset.y + progress * (targetOffset.y - startOffset.y); + this.update(); + }).bind(this); + + this.animate( + this.options.animationDuration, + updateProgress, + this.swing + ); + }, + + /** + * Zooms back to the original position, + * (no offset and zoom factor 1) + */ + zoomOutAnimation: function() { + var startZoomFactor = this.zoomFactor, + zoomFactor = 1, + center = this.getCurrentZoomCenter(), + updateProgress = (function(progress) { + this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor), center); + }).bind(this); + + this.animate( + this.options.animationDuration, + updateProgress, + this.swing + ); + }, + + /** + * Updates the aspect ratio + */ + updateAspectRatio: function() { + this.setContainerY(this.getContainerX() / this.getAspectRatio()); + }, + + /** + * Calculates the initial zoom factor (for the element to fit into the container) + * @return the initial zoom factor + */ + getInitialZoomFactor: function() { + // use .offsetWidth instead of width() + // because jQuery-width() return the original width but Zepto-width() will calculate width with transform. + // the same as .height() + return this.container[0].offsetWidth / this.el[0].offsetWidth; + }, + + /** + * Calculates the aspect ratio of the element + * @return the aspect ratio + */ + getAspectRatio: function() { + return this.el[0].offsetWidth / this.el[0].offsetHeight; + }, + + /** + * Calculates the virtual zoom center for the current offset and zoom factor + * (used for reverse zoom) + * @return {Object} the current zoom center + */ + getCurrentZoomCenter: function() { + + // uses following formula to calculate the zoom center x value + // offset_left / offset_right = zoomcenter_x / (container_x - zoomcenter_x) + var length = this.container[0].offsetWidth * this.zoomFactor, + offsetLeft = this.offset.x, + offsetRight = length - offsetLeft - this.container[0].offsetWidth, + widthOffsetRatio = offsetLeft / offsetRight, + centerX = widthOffsetRatio * this.container[0].offsetWidth / (widthOffsetRatio + 1), + + // the same for the zoomcenter y + height = this.container[0].offsetHeight * this.zoomFactor, + offsetTop = this.offset.y, + offsetBottom = height - offsetTop - this.container[0].offsetHeight, + heightOffsetRatio = offsetTop / offsetBottom, + centerY = heightOffsetRatio * this.container[0].offsetHeight / (heightOffsetRatio + 1); + + // prevents division by zero + if (offsetRight === 0) { + centerX = this.container[0].offsetWidth; + } + if (offsetBottom === 0) { + centerY = this.container[0].offsetHeight; + } + + return { + x: centerX, + y: centerY + }; + }, + + canDrag: function() { + return !isCloseTo(this.zoomFactor, 1); + }, + + /** + * Returns the touches of an event relative to the container offset + * @param event + * @return array touches + */ + getTouches: function(event) { + var position = this.container.offset(); + return Array.prototype.slice.call(event.touches).map(function(touch) { + return { + x: touch.pageX - position.left, + y: touch.pageY - position.top + }; + }); + }, + + /** + * Animation loop + * does not support simultaneous animations + * @param duration + * @param framefn + * @param timefn + * @param callback + */ + animate: function(duration, framefn, timefn, callback) { + var startTime = new Date().getTime(), + renderFrame = (function() { + if (!this.inAnimation) { + return; + } + var frameTime = new Date().getTime() - startTime, + progress = frameTime / duration; + if (frameTime >= duration) { + framefn(1); + if (callback) { + callback(); + } + this.update(); + this.stopAnimation(); + this.update(); + } else { + if (timefn) { + progress = timefn(progress); + } + framefn(progress); + this.update(); + requestAnimationFrame(renderFrame); + } + }).bind(this); + this.inAnimation = true; + requestAnimationFrame(renderFrame); + }, + + /** + * Stops the animation + */ + stopAnimation: function() { + this.inAnimation = false; + }, + + /** + * Swing timing function for animations + * @param p + * @return {Number} + */ + swing: function(p) { + return -Math.cos(p * Math.PI) / 2 + 0.5; + }, + + getContainerX: function() { + return this.container[0].offsetWidth; + }, + + getContainerY: function() { + return this.container[0].offsetHeight; + }, + + setContainerY: function(y) { + return this.container.height(y); + }, + + /** + * Creates the expected html structure + */ + setupMarkup: function() { + this.container = $('
    '); + this.el.before(this.container); + this.container.append(this.el); + + this.container.css({ + 'overflow': 'hidden', + 'position': 'relative' + }); + + // Zepto doesn't recognize `webkitTransform..` style + this.el.css({ + '-webkit-transform-origin': '0% 0%', + '-moz-transform-origin': '0% 0%', + '-ms-transform-origin': '0% 0%', + '-o-transform-origin': '0% 0%', + 'transform-origin': '0% 0%', + 'position': 'absolute' + }); + }, + + end: function() { + this.hasInteraction = false; + this.sanitize(); + this.update(); + }, + + /** + * Binds all required event listeners + */ + bindEvents: function() { + detectGestures(this.container.get(0), this); + // Zepto and jQuery both know about `on` + $(window).on('resize', this.update.bind(this)); + $(this.el).find('img').on('load', this.update.bind(this)); + }, + + /** + * Updates the css values according to the current zoom factor and offset + */ + update: function() { + + if (this.updatePlaned) { + return; + } + this.updatePlaned = true; + + setTimeout((function() { + this.updatePlaned = false; + this.updateAspectRatio(); + + var zoomFactor = this.getInitialZoomFactor() * this.zoomFactor, + offsetX = -this.offset.x / zoomFactor, + offsetY = -this.offset.y / zoomFactor, + transform3d = 'scale3d(' + zoomFactor + ', ' + zoomFactor + ',1) ' + + 'translate3d(' + offsetX + 'px,' + offsetY + 'px,0px)', + transform2d = 'scale(' + zoomFactor + ', ' + zoomFactor + ') ' + + 'translate(' + offsetX + 'px,' + offsetY + 'px)', + removeClone = (function() { + if (this.clone) { + this.clone.remove(); + delete this.clone; + } + }).bind(this); + + // Scale 3d and translate3d are faster (at least on ios) + // but they also reduce the quality. + // PinchZoom uses the 3d transformations during interactions + // after interactions it falls back to 2d transformations + if (!this.options.use2d || this.hasInteraction || this.inAnimation) { + this.is3d = true; + removeClone(); + this.el.css({ + '-webkit-transform': transform3d, + '-o-transform': transform2d, + '-ms-transform': transform2d, + '-moz-transform': transform2d, + 'transform': transform3d + }); + } else { + + // When changing from 3d to 2d transform webkit has some glitches. + // To avoid this, a copy of the 3d transformed element is displayed in the + // foreground while the element is converted from 3d to 2d transform + if (this.is3d) { + this.clone = this.el.clone(); + this.clone.css('pointer-events', 'none'); + this.clone.appendTo(this.container); + setTimeout(removeClone, 200); + } + this.el.css({ + '-webkit-transform': transform2d, + '-o-transform': transform2d, + '-ms-transform': transform2d, + '-moz-transform': transform2d, + 'transform': transform2d + }); + this.is3d = false; + } + }).bind(this), 0); + }, + + /** + * Enables event handling for gestures + */ + enable: function() { + this.enabled = true; + }, + + /** + * Disables event handling for gestures + */ + disable: function() { + this.enabled = false; + } + }; + + var detectGestures = function(el, target) { + var interaction = null, + fingers = 0, + lastTouchStart = null, + startTouches = null, + + setInteraction = function(newInteraction, event) { + if (interaction !== newInteraction) { + + if (interaction && !newInteraction) { + switch (interaction) { + case "zoom": + target.handleZoomEnd(event); + break; + case 'drag': + target.handleDragEnd(event); + break; + } + } + + switch (newInteraction) { + case 'zoom': + target.handleZoomStart(event); + break; + case 'drag': + target.handleDragStart(event); + break; + } + } + interaction = newInteraction; + }, + + updateInteraction = function(event) { + if (fingers === 2) { + setInteraction('zoom'); + } else if (fingers === 1 && target.canDrag()) { + setInteraction('drag', event); + } else { + setInteraction(null, event); + } + }, + + targetTouches = function(touches) { + return Array.prototype.slice.call(touches).map(function(touch) { + return { + x: touch.pageX, + y: touch.pageY + }; + }); + }, + + getDistance = function(a, b) { + var x, y; + x = a.x - b.x; + y = a.y - b.y; + return Math.sqrt(x * x + y * y); + }, + + calculateScale = function(startTouches, endTouches) { + var startDistance = getDistance(startTouches[0], startTouches[1]), + endDistance = getDistance(endTouches[0], endTouches[1]); + return endDistance / startDistance; + }, + + cancelEvent = function(event) { + event.stopPropagation(); + event.preventDefault(); + }, + + detectDoubleTap = function(event) { + var time = (new Date()).getTime(); + + if (fingers > 1) { + lastTouchStart = null; + } + + if (time - lastTouchStart < 300) { + cancelEvent(event); + + target.handleDoubleTap(event); + switch (interaction) { + case 'zoom': + target.handleZoomEnd(event); + break; + case 'drag': + target.handleDragEnd(event); + break; + } + } + + if (fingers === 1) { + lastTouchStart = time; + } + }, + firstMove = true; + + el.addEventListener('touchstart', function(event) { + if (target.enabled) { + firstMove = true; + fingers = event.touches.length; + detectDoubleTap(event); + } + }); + + el.addEventListener('touchmove', function(event) { + if (target.enabled) { + if (firstMove) { + updateInteraction(event); + if (interaction) { + cancelEvent(event); + } + startTouches = targetTouches(event.touches); + } else { + switch (interaction) { + case 'zoom': + target.handleZoom(event, calculateScale(startTouches, targetTouches(event.touches))); + break; + case 'drag': + target.handleDrag(event); + break; + } + if (interaction) { + cancelEvent(event); + target.update(); + } + } + + firstMove = false; + } + }); + + el.addEventListener('touchend', function(event) { + if (target.enabled) { + fingers = event.touches.length; + updateInteraction(event); + } + }); + }; + + return PinchZoom; + }; + + module.exports = UI.pichzoom = definePinchZoom($); + + +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var $w = $(window); + + /** + * @reference https://github.com/nolimits4web/Framework7/blob/master/src/js/modals.js + * @license https://github.com/nolimits4web/Framework7/blob/master/LICENSE + */ + + var Popover = function(element, options) { + this.options = $.extend({}, Popover.DEFAULTS, options); + this.$element = $(element); + this.active = null; + this.$popover = (this.options.target && $(this.options.target)) || null; + + this.init(); + this._bindEvents(); + }; + + Popover.DEFAULTS = { + theme: null, + trigger: 'click', + content: '', + open: false, + target: null, + tpl: '
    ' + + '
    ' + + '
    ' + }; + + Popover.prototype.init = function() { + var _this = this; + var $element = this.$element; + var $popover; + + if (!this.options.target) { + this.$popover = this.getPopover(); + this.setContent(); + } + + $popover = this.$popover; + + $popover.appendTo($('body')); + + this.sizePopover(); + + function sizePopover() { + _this.sizePopover(); + } + + // TODO: 监听页面内容变化,重新调整位置 + + $element.on('open.popover.amui', function() { + $(window).on('resize.popover.amui', UI.utils.debounce(sizePopover, 50)); + }); + + $element.on('close.popover.amui', function() { + $(window).off('resize.popover.amui', sizePopover); + }); + + this.options.open && this.open(); + }; + + Popover.prototype.sizePopover = function sizePopover() { + var $element = this.$element; + var $popover = this.$popover; + + if (!$popover || !$popover.length) { + return; + } + + var popWidth = $popover.outerWidth(); + var popHeight = $popover.outerHeight(); + var $popCaret = $popover.find('.am-popover-caret'); + var popCaretSize = ($popCaret.outerWidth() / 2) || 8; + // 取不到 $popCaret.outerHeight() 的值,所以直接加 8 + var popTotalHeight = popHeight + 8; // $popCaret.outerHeight(); + + var triggerWidth = $element.outerWidth(); + var triggerHeight = $element.outerHeight(); + var triggerOffset = $element.offset(); + var triggerRect = $element[0].getBoundingClientRect(); + + var winHeight = $w.height(); + var winWidth = $w.width(); + var popTop = 0; + var popLeft = 0; + var diff = 0; + var spacing = 2; + var popPosition = 'top'; + + $popover.css({left: '', top: ''}).removeClass('am-popover-left ' + + 'am-popover-right am-popover-top am-popover-bottom'); + + // $popCaret.css({left: '', top: ''}); + + if (popTotalHeight - spacing < triggerRect.top + spacing) { + // Popover on the top of trigger + popTop = triggerOffset.top - popTotalHeight - spacing; + } else if (popTotalHeight < + winHeight - triggerRect.top - triggerRect.height) { + // On bottom + popPosition = 'bottom'; + popTop = triggerOffset.top + triggerHeight + popCaretSize + spacing; + } else { // On middle + popPosition = 'middle'; + popTop = triggerHeight / 2 + triggerOffset.top - popHeight / 2; + } + + // Horizontal Position + if (popPosition === 'top' || popPosition === 'bottom') { + popLeft = triggerWidth / 2 + triggerOffset.left - popWidth / 2; + + diff = popLeft; + + if (popLeft < 5) { + popLeft = 5; + } + + if (popLeft + popWidth > winWidth) { + popLeft = (winWidth - popWidth - 20); + // console.log('left %d, win %d, popw %d', popLeft, winWidth, popWidth); + } + + if (popPosition === 'top') { + // This is the Popover position, NOT caret position + // Popover on the Top of trigger, caret on the bottom of Popover + $popover.addClass('am-popover-top'); + } + + if (popPosition === 'bottom') { + $popover.addClass('am-popover-bottom'); + } + + diff = diff - popLeft; + // $popCaret.css({left: (popWidth / 2 - popCaretSize + diff) + 'px'}); + + } else if (popPosition === 'middle') { + popLeft = triggerOffset.left - popWidth - popCaretSize; + $popover.addClass('am-popover-left'); + if (popLeft < 5) { + popLeft = triggerOffset.left + triggerWidth + popCaretSize; + $popover.removeClass('am-popover-left').addClass('am-popover-right'); + } + + if (popLeft + popWidth > winWidth) { + popLeft = winWidth - popWidth - 5; + $popover.removeClass('am-popover-left').addClass('am-popover-right'); + } + // $popCaret.css({top: (popHeight / 2 - popCaretSize / 2) + 'px'}); + } + + // Apply position style + $popover.css({top: popTop + 'px', left: popLeft + 'px'}); + }; + + Popover.prototype.toggle = function() { + return this[this.active ? 'close' : 'open'](); + }; + + Popover.prototype.open = function() { + var $popover = this.$popover; + + this.$element.trigger('open.popover.amui'); + this.sizePopover(); + $popover.show().addClass('am-active'); + this.active = true; + }; + + Popover.prototype.close = function() { + var $popover = this.$popover; + + this.$element.trigger('close.popover.amui'); + + $popover + .removeClass('am-active') + .trigger('closed.popover.amui') + .hide(); + + this.active = false; + }; + + Popover.prototype.getPopover = function() { + var uid = UI.utils.generateGUID('am-popover'); + var theme = []; + + if (this.options.theme) { + $.each(this.options.theme.split(' '), function(i, item) { + theme.push('am-popover-' + $.trim(item)); + }); + } + + return $(this.options.tpl).attr('id', uid).addClass(theme.join(' ')); + }; + + Popover.prototype.setContent = function(content) { + content = content || this.options.content; + this.$popover && this.$popover.find('.am-popover-inner') + .empty().html(content); + }; + + Popover.prototype._bindEvents = function() { + var eventNS = 'popover.amui'; + var triggers = this.options.trigger.split(' '); + + for (var i = triggers.length; i--;) { + var trigger = triggers[i]; + + if (trigger === 'click') { + this.$element.on('click.' + eventNS, $.proxy(this.toggle, this)); + } else { // hover or focus + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'; + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'; + + this.$element.on(eventIn + '.' + eventNS, $.proxy(this.open, this)); + this.$element.on(eventOut + '.' + eventNS, $.proxy(this.close, this)); + } + } + }; + + Popover.prototype.destroy = function() { + this.$element.off('.popover.amui').removeData('amui.popover'); + this.$popover.remove(); + }; + + UI.plugin('popover', Popover); + + // Init code + UI.ready(function(context) { + $('[data-am-popover]', context).popover(); + }); + + module.exports = Popover; + + // TODO: 允许用户定义位置 + + +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var UI = __webpack_require__(2); + + var Progress = (function() { + /** + * NProgress (c) 2013, Rico Sta. Cruz + * @via http://ricostacruz.com/nprogress + */ + + var NProgress = {}; + + NProgress.version = '0.2.0'; + + var Settings = NProgress.settings = { + minimum: 0.08, + easing: 'ease', + positionUsing: '', + speed: 200, + trickle: true, + trickleRate: 0.02, + trickleSpeed: 800, + showSpinner: true, + parent: 'body', + barSelector: '[role="nprogress-bar"]', + spinnerSelector: '[role="nprogress-spinner"]', + template: '
    ' + + '
    ' + + '
    ' + + '
    ' + }; + + /** + * Updates configuration. + * + * NProgress.configure({ + * minimum: 0.1 + * }); + */ + NProgress.configure = function(options) { + var key, value; + for (key in options) { + value = options[key]; + if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; + } + + return this; + }; + + /** + * Last number. + */ + + NProgress.status = null; + + /** + * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. + * + * NProgress.set(0.4); + * NProgress.set(1.0); + */ + + NProgress.set = function(n) { + var started = NProgress.isStarted(); + + n = clamp(n, Settings.minimum, 1); + NProgress.status = (n === 1 ? null : n); + + var progress = NProgress.render(!started), + bar = progress.querySelector(Settings.barSelector), + speed = Settings.speed, + ease = Settings.easing; + + progress.offsetWidth; /* Repaint */ + + queue(function(next) { + // Set positionUsing if it hasn't already been set + if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); + + // Add transition + css(bar, barPositionCSS(n, speed, ease)); + + if (n === 1) { + // Fade out + css(progress, { + transition: 'none', + opacity: 1 + }); + progress.offsetWidth; /* Repaint */ + + setTimeout(function() { + css(progress, { + transition: 'all ' + speed + 'ms linear', + opacity: 0 + }); + setTimeout(function() { + NProgress.remove(); + next(); + }, speed); + }, speed); + } else { + setTimeout(next, speed); + } + }); + + return this; + }; + + NProgress.isStarted = function() { + return typeof NProgress.status === 'number'; + }; + + /** + * Shows the progress bar. + * This is the same as setting the status to 0%, except that it doesn't go backwards. + * + * NProgress.start(); + * + */ + NProgress.start = function() { + if (!NProgress.status) NProgress.set(0); + + var work = function() { + setTimeout(function() { + if (!NProgress.status) return; + NProgress.trickle(); + work(); + }, Settings.trickleSpeed); + }; + + if (Settings.trickle) work(); + + return this; + }; + + /** + * Hides the progress bar. + * This is the *sort of* the same as setting the status to 100%, with the + * difference being `done()` makes some placebo effect of some realistic motion. + * + * NProgress.done(); + * + * If `true` is passed, it will show the progress bar even if its hidden. + * + * NProgress.done(true); + */ + + NProgress.done = function(force) { + if (!force && !NProgress.status) return this; + + return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); + }; + + /** + * Increments by a random amount. + */ + + NProgress.inc = function(amount) { + var n = NProgress.status; + + if (!n) { + return NProgress.start(); + } else { + if (typeof amount !== 'number') { + amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); + } + + n = clamp(n + amount, 0, 0.994); + return NProgress.set(n); + } + }; + + NProgress.trickle = function() { + return NProgress.inc(Math.random() * Settings.trickleRate); + }; + + /** + * Waits for all supplied jQuery promises and + * increases the progress as the promises resolve. + * + * @param $promise jQUery Promise + */ + (function() { + var initial = 0, current = 0; + + NProgress.promise = function($promise) { + if (!$promise || $promise.state() === "resolved") { + return this; + } + + if (current === 0) { + NProgress.start(); + } + + initial++; + current++; + + $promise.always(function() { + current--; + if (current === 0) { + initial = 0; + NProgress.done(); + } else { + NProgress.set((initial - current) / initial); + } + }); + + return this; + }; + + })(); + + /** + * (Internal) renders the progress bar markup based on the `template` + * setting. + */ + + NProgress.render = function(fromStart) { + if (NProgress.isRendered()) return document.getElementById('nprogress'); + + addClass(document.documentElement, 'nprogress-busy'); + + var progress = document.createElement('div'); + progress.id = 'nprogress'; + progress.innerHTML = Settings.template; + + var bar = progress.querySelector(Settings.barSelector), + perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), + parent = document.querySelector(Settings.parent), + spinner; + + css(bar, { + transition: 'all 0 linear', + transform: 'translate3d(' + perc + '%,0,0)' + }); + + if (!Settings.showSpinner) { + spinner = progress.querySelector(Settings.spinnerSelector); + spinner && removeElement(spinner); + } + + if (parent != document.body) { + addClass(parent, 'nprogress-custom-parent'); + } + + parent.appendChild(progress); + return progress; + }; + + /** + * Removes the element. Opposite of render(). + */ + + NProgress.remove = function() { + removeClass(document.documentElement, 'nprogress-busy'); + removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent'); + var progress = document.getElementById('nprogress'); + progress && removeElement(progress); + }; + + /** + * Checks if the progress bar is rendered. + */ + + NProgress.isRendered = function() { + return !!document.getElementById('nprogress'); + }; + + /** + * Determine which positioning CSS rule to use. + */ + + NProgress.getPositioningCSS = function() { + // Sniff on document.body.style + var bodyStyle = document.body.style; + + // Sniff prefixes + var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : + ('MozTransform' in bodyStyle) ? 'Moz' : + ('msTransform' in bodyStyle) ? 'ms' : + ('OTransform' in bodyStyle) ? 'O' : ''; + + if (vendorPrefix + 'Perspective' in bodyStyle) { + // Modern browsers with 3D support, e.g. Webkit, IE10 + return 'translate3d'; + } else if (vendorPrefix + 'Transform' in bodyStyle) { + // Browsers without 3D support, e.g. IE9 + return 'translate'; + } else { + // Browsers without translate() support, e.g. IE7-8 + return 'margin'; + } + }; + + /** + * Helpers + */ + + function clamp(n, min, max) { + if (n < min) return min; + if (n > max) return max; + return n; + } + + /** + * (Internal) converts a percentage (`0..1`) to a bar translateX + * percentage (`-100%..0%`). + */ + + function toBarPerc(n) { + return (-1 + n) * 100; + } + + + /** + * (Internal) returns the correct CSS for changing the bar's + * position given an n percentage, and speed and ease from Settings + */ + + function barPositionCSS(n, speed, ease) { + var barCSS; + + if (Settings.positionUsing === 'translate3d') { + barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; + } else if (Settings.positionUsing === 'translate') { + barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; + } else { + barCSS = { 'margin-left': toBarPerc(n)+'%' }; + } + + barCSS.transition = 'all '+speed+'ms '+ease; + + return barCSS; + } + + /** + * (Internal) Queues a function to be executed. + */ + + var queue = (function() { + var pending = []; + + function next() { + var fn = pending.shift(); + if (fn) { + fn(next); + } + } + + return function(fn) { + pending.push(fn); + if (pending.length == 1) next(); + }; + })(); + + /** + * (Internal) Applies css properties to an element, similar to the jQuery + * css method. + * + * While this helper does assist with vendor prefixed property names, it + * does not perform any manipulation of values prior to setting styles. + */ + + var css = (function() { + var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], + cssProps = {}; + + function camelCase(string) { + return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { + return letter.toUpperCase(); + }); + } + + function getVendorProp(name) { + var style = document.body.style; + if (name in style) return name; + + var i = cssPrefixes.length, + capName = name.charAt(0).toUpperCase() + name.slice(1), + vendorName; + while (i--) { + vendorName = cssPrefixes[i] + capName; + if (vendorName in style) return vendorName; + } + + return name; + } + + function getStyleProp(name) { + name = camelCase(name); + return cssProps[name] || (cssProps[name] = getVendorProp(name)); + } + + function applyCss(element, prop, value) { + prop = getStyleProp(prop); + element.style[prop] = value; + } + + return function(element, properties) { + var args = arguments, + prop, + value; + + if (args.length == 2) { + for (prop in properties) { + value = properties[prop]; + if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); + } + } else { + applyCss(element, args[1], args[2]); + } + } + })(); + + /** + * (Internal) Determines if an element or space separated list of class names contains a class name. + */ + + function hasClass(element, name) { + var list = typeof element == 'string' ? element : classList(element); + return list.indexOf(' ' + name + ' ') >= 0; + } + + /** + * (Internal) Adds a class to an element. + */ + + function addClass(element, name) { + var oldList = classList(element), + newList = oldList + name; + + if (hasClass(oldList, name)) return; + + // Trim the opening space. + element.className = newList.substring(1); + } + + /** + * (Internal) Removes a class from an element. + */ + + function removeClass(element, name) { + var oldList = classList(element), + newList; + + if (!hasClass(element, name)) return; + + // Replace the class name. + newList = oldList.replace(' ' + name + ' ', ' '); + + // Trim the opening and closing spaces. + element.className = newList.substring(1, newList.length - 1); + } + + /** + * (Internal) Gets a space separated list of the class names on the element. + * The list is wrapped with a single space on each end to facilitate finding + * matches within the list. + */ + + function classList(element) { + return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' '); + } + + /** + * (Internal) Removes an element from the DOM. + */ + + function removeElement(element) { + element && element.parentNode && element.parentNode.removeChild(element); + } + + return NProgress; + })(); + + module.exports = UI.progress = Progress; + + +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var PinchZoom = __webpack_require__(17); + var Hammer = __webpack_require__(3); + var animation = UI.support.animation; + var transition = UI.support.transition; + + /** + * PureView + * @desc Image browser for Mobile + * @param element + * @param options + * @constructor + */ + + var PureView = function(element, options) { + this.$element = $(element); + this.$body = $(document.body); + this.options = $.extend({}, PureView.DEFAULTS, options); + this.$pureview = $(this.options.tpl).attr('id', + UI.utils.generateGUID('am-pureview')); + + this.$slides = null; + this.transitioning = null; + this.scrollbarWidth = 0; + + this.init(); + }; + + PureView.DEFAULTS = { + tpl: '
    ' + + '
      ' + + '
        ' + + '
      • ' + + '
      ' + + '
        ' + + '
        ' + + '' + + '
        / ' + + '
        ' + + '
        ' + + '
        ' + + '
        ', + + className: { + prevSlide: 'am-pureview-slide-prev', + nextSlide: 'am-pureview-slide-next', + onlyOne: 'am-pureview-only', + active: 'am-active', + barActive: 'am-pureview-bar-active', + activeBody: 'am-pureview-active' + }, + + selector: { + slider: '.am-pureview-slider', + close: '[data-am-close="pureview"]', + total: '.am-pureview-total', + current: '.am-pureview-current', + title: '.am-pureview-title', + actions: '.am-pureview-actions', + bar: '.am-pureview-bar', + pinchZoom: '.am-pinch-zoom', + nav: '.am-pureview-nav' + }, + + shareBtn: false, + + // press to toggle Toolbar + toggleToolbar: true, + + // 从何处获取图片,img 可以使用 data-rel 指定大图 + target: 'img', + + // 微信 Webview 中调用微信的图片浏览器 + // 实现图片保存、分享好友、收藏图片等功能 + weChatImagePreview: true + }; + + PureView.prototype.init = function() { + var _this = this; + var options = this.options; + var $element = this.$element; + var $pureview = this.$pureview; + + this.refreshSlides(); + + $('body').append($pureview); + + this.$title = $pureview.find(options.selector.title); + this.$current = $pureview.find(options.selector.current); + this.$bar = $pureview.find(options.selector.bar); + this.$actions = $pureview.find(options.selector.actions); + + if (options.shareBtn) { + this.$actions.append(''); + } + + this.$element.on('click.pureview.amui', options.target, function(e) { + e.preventDefault(); + var clicked = _this.$images.index(this); + + // Invoke WeChat ImagePreview in WeChat + // TODO: detect WeChat before init + if (options.weChatImagePreview && window.WeixinJSBridge) { + window.WeixinJSBridge.invoke('imagePreview', { + current: _this.imgUrls[clicked], + urls: _this.imgUrls + }); + } else { + _this.open(clicked); + } + }); + + $pureview.find('.am-pureview-direction'). + on('click.direction.pureview.amui', 'li', function(e) { + e.preventDefault(); + + if ($(this).is('.am-pureview-prev')) { + _this.prevSlide(); + } else { + _this.nextSlide(); + } + }); + + // Nav Contorl + $pureview.find(options.selector.nav).on('click.nav.pureview.amui', 'li', + function() { + var index = _this.$navItems.index($(this)); + _this.activate(_this.$slides.eq(index)); + }); + + // Close Icon + $pureview.find(options.selector.close). + on('click.close.pureview.amui', function(e) { + e.preventDefault(); + _this.close(); + }); + + this.$slider.hammer().on('swipeleft.pureview.amui', function(e) { + e.preventDefault(); + _this.nextSlide(); + }).on('swiperight.pureview.amui', function(e) { + e.preventDefault(); + _this.prevSlide(); + }).on('press.pureview.amui', function(e) { + e.preventDefault(); + options.toggleToolbar && _this.toggleToolBar(); + }); + + this.$slider.data('hammer').get('swipe').set({ + direction: Hammer.DIRECTION_HORIZONTAL, + velocity: 0.35 + }); + + // Observe DOM + $element.DOMObserve({ + childList: true, + subtree: true + }, function(mutations, observer) { + // _this.refreshSlides(); + // console.log('mutations[0].type); + }); + + // NOTE: + // trigger this event manually if MutationObserver not supported + // when new images appended, or call refreshSlides() + // if (!UI.support.mutationobserver) $element.trigger('changed.dom.amui') + $element.on('changed.dom.amui', function(e) { + e.stopPropagation(); + _this.refreshSlides(); + }); + + $(document).on('keydown.pureview.amui', $.proxy(function(e) { + var keyCode = e.keyCode; + if (keyCode == 37) { + this.prevSlide(); + } else if (keyCode == 39) { + this.nextSlide(); + } else if (keyCode == 27) { + this.close(); + } + }, this)); + }; + + PureView.prototype.refreshSlides = function() { + // update images collections + this.$images = this.$element.find(this.options.target); + var _this = this; + var options = this.options; + var $pureview = this.$pureview; + var $slides = $([]); + var $navItems = $([]); + var $images = this.$images; + var total = $images.length; + this.$slider = $pureview.find(options.selector.slider); + this.$nav = $pureview.find(options.selector.nav); + var viewedFlag = 'data-am-pureviewed'; + // for WeChat Image Preview + this.imgUrls = this.imgUrls || []; + + if (!total) { + return; + } + + if (total === 1) { + $pureview.addClass(options.className.onlyOne); + } + + $images.not('[' + viewedFlag + ']').each(function(i, item) { + var src; + var title; + + // get image URI from link's href attribute + if (item.nodeName === 'A') { + src = item.href; // to absolute path + title = item.title || ''; + } else { + // NOTE: `data-rel` should be a full URL, otherwise, + // WeChat images preview will not work + src = $(item).data('rel') || item.src; // + src = UI.utils.getAbsoluteUrl(src); + title = $(item).attr('alt') || ''; + } + + // add pureviewed flag + item.setAttribute(viewedFlag, '1'); + + // hide bar: wechat_webview_type=1 + // http://tmt.io/wechat/ not working? + _this.imgUrls.push(src); + + $slides = $slides.add($('
      1. ')); + $navItems = $navItems.add($('
      2. ' + (i + 1) + '
      3. ')); + }); + + $pureview.find(options.selector.total).text(total); + + this.$slider.append($slides); + this.$nav.append($navItems); + this.$navItems = this.$nav.find('li'); + this.$slides = this.$slider.find('li'); + }; + + PureView.prototype.loadImage = function($slide, callback) { + var appendedFlag = 'image-appended'; + + if (!$slide.data(appendedFlag)) { + var $img = $('', { + src: $slide.data('src'), + alt: $slide.data('title') + }); + + $slide.html($img).wrapInner('
        ').redraw(); + + var $pinchWrapper = $slide.find(this.options.selector.pinchZoom); + $pinchWrapper.data('amui.pinchzoom', new PinchZoom($pinchWrapper[0], {})); + $slide.data('image-appended', true); + } + + callback && callback.call(this); + }; + + PureView.prototype.activate = function($slide) { + var options = this.options; + var $slides = this.$slides; + var activeIndex = $slides.index($slide); + var title = $slide.data('title') || ''; + var active = options.className.active; + + if ($slides.find('.' + active).is($slide)) { + return; + } + + if (this.transitioning) { + return; + } + + this.loadImage($slide, function() { + UI.utils.imageLoader($slide.find('img'), function(image) { + $slide.find('.am-pinch-zoom').addClass('am-pureview-loaded'); + $(image).addClass('am-img-loaded'); + }); + }); + + this.transitioning = 1; + + this.$title.text(title); + this.$current.text(activeIndex + 1); + $slides.removeClass(); + $slide.addClass(active); + $slides.eq(activeIndex - 1).addClass(options.className.prevSlide); + $slides.eq(activeIndex + 1).addClass(options.className.nextSlide); + + this.$navItems.removeClass(). + eq(activeIndex).addClass(options.className.active); + + if (transition) { + $slide.one(transition.end, $.proxy(function() { + this.transitioning = 0; + }, this)).emulateTransitionEnd(300); + } else { + this.transitioning = 0; + } + + // TODO: pre-load next image + }; + + PureView.prototype.nextSlide = function() { + if (this.$slides.length === 1) { + return; + } + + var $slides = this.$slides; + var $active = $slides.filter('.am-active'); + var activeIndex = $slides.index($active); + var rightSpring = 'am-animation-right-spring'; + + if (activeIndex + 1 >= $slides.length) { // last one + animation && $active.addClass(rightSpring).on(animation.end, function() { + $active.removeClass(rightSpring); + }); + } else { + this.activate($slides.eq(activeIndex + 1)); + } + }; + + PureView.prototype.prevSlide = function() { + if (this.$slides.length === 1) { + return; + } + + var $slides = this.$slides; + var $active = $slides.filter('.am-active'); + var activeIndex = this.$slides.index(($active)); + var leftSpring = 'am-animation-left-spring'; + + if (activeIndex === 0) { // first one + animation && $active.addClass(leftSpring).on(animation.end, function() { + $active.removeClass(leftSpring); + }); + } else { + this.activate($slides.eq(activeIndex - 1)); + } + }; + + PureView.prototype.toggleToolBar = function() { + this.$pureview.toggleClass(this.options.className.barActive); + }; + + PureView.prototype.open = function(index) { + var active = index || 0; + this.checkScrollbar(); + this.setScrollbar(); + this.activate(this.$slides.eq(active)); + this.$pureview.show().redraw().addClass(this.options.className.active); + this.$body.addClass(this.options.className.activeBody); + }; + + PureView.prototype.close = function() { + var options = this.options; + + this.$pureview.removeClass(options.className.active); + this.$slides.removeClass(); + + function resetBody() { + this.$pureview.hide(); + this.$body.removeClass(options.className.activeBody); + this.resetScrollbar(); + } + + if (transition) { + this.$pureview.one(transition.end, $.proxy(resetBody, this)). + emulateTransitionEnd(300); + } else { + resetBody.call(this); + } + }; + + PureView.prototype.checkScrollbar = function() { + this.scrollbarWidth = UI.utils.measureScrollbar(); + }; + + PureView.prototype.setScrollbar = function() { + var bodyPaddingRight = parseInt((this.$body.css('padding-right') || 0), 10); + if (this.scrollbarWidth) { + this.$body.css('padding-right', bodyPaddingRight + this.scrollbarWidth); + } + }; + + PureView.prototype.resetScrollbar = function() { + this.$body.css('padding-right', ''); + }; + + UI.plugin('pureview', PureView); + + // Init code + UI.ready(function(context) { + $('[data-am-pureview]', context).pureview(); + }); + + module.exports = PureView; + + // TODO: 1. 动画改进 + // 2. 改变图片的时候恢复 Zoom + // 3. 选项 + // 4. 图片高度问题:由于 PinchZoom 的原因,过高的图片如果设置看了滚动,则放大以后显示不全 + + +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + + /** + * @via https://github.com/uikit/uikit/blob/master/src/js/scrollspy.js + * @license https://github.com/uikit/uikit/blob/master/LICENSE.md + */ + + var ScrollSpy = function(element, options) { + if (!UI.support.animation) { + return; + } + + this.options = $.extend({}, ScrollSpy.DEFAULTS, options); + this.$element = $(element); + + var checkViewRAF = function() { + UI.utils.rAF.call(window, $.proxy(this.checkView, this)); + }.bind(this); + + this.$window = $(window).on('scroll.scrollspy.amui', checkViewRAF) + .on('resize.scrollspy.amui orientationchange.scrollspy.amui', + UI.utils.debounce(checkViewRAF, 50)); + + this.timer = this.inViewState = this.initInView = null; + + checkViewRAF(); + }; + + ScrollSpy.DEFAULTS = { + animation: 'fade', + className: { + inView: 'am-scrollspy-inview', + init: 'am-scrollspy-init' + }, + repeat: true, + delay: 0, + topOffset: 0, + leftOffset: 0 + }; + + ScrollSpy.prototype.checkView = function() { + var $element = this.$element; + var options = this.options; + var inView = UI.utils.isInView($element, options); + var animation = options.animation ? + ' am-animation-' + options.animation : ''; + + if (inView && !this.inViewState) { + if (this.timer) { + clearTimeout(this.timer); + } + + if (!this.initInView) { + $element.addClass(options.className.init); + this.offset = $element.offset(); + this.initInView = true; + + $element.trigger('init.scrollspy.amui'); + } + + this.timer = setTimeout(function() { + if (inView) { + $element.addClass(options.className.inView + animation).width(); + } + }, options.delay); + + this.inViewState = true; + $element.trigger('inview.scrollspy.amui'); + } + + if (!inView && this.inViewState && options.repeat) { + $element.removeClass(options.className.inView + animation); + + this.inViewState = false; + + $element.trigger('outview.scrollspy.amui'); + } + }; + + ScrollSpy.prototype.check = function() { + UI.utils.rAF.call(window, $.proxy(this.checkView, this)); + }; + + // Sticky Plugin + UI.plugin('scrollspy', ScrollSpy); + + // Init code + UI.ready(function(context) { + $('[data-am-scrollspy]', context).scrollspy(); + }); + + module.exports = ScrollSpy; + + +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + __webpack_require__(23); + + /** + * @via https://github.com/uikit/uikit/ + * @license https://github.com/uikit/uikit/blob/master/LICENSE.md + */ + + // ScrollSpyNav Class + var ScrollSpyNav = function(element, options) { + this.options = $.extend({}, ScrollSpyNav.DEFAULTS, options); + this.$element = $(element); + this.anchors = []; + + this.$links = this.$element.find('a[href^="#"]').each(function(i, link) { + this.anchors.push($(link).attr('href')); + }.bind(this)); + + this.$targets = $(this.anchors.join(', ')); + + var processRAF = function() { + UI.utils.rAF.call(window, $.proxy(this.process, this)); + }.bind(this); + + this.$window = $(window).on('scroll.scrollspynav.amui', processRAF) + .on('resize.scrollspynav.amui orientationchange.scrollspynav.amui', + UI.utils.debounce(processRAF, 50)); + + processRAF(); + this.scrollProcess(); + }; + + ScrollSpyNav.DEFAULTS = { + className: { + active: 'am-active' + }, + closest: false, + smooth: true, + offsetTop: 0 + }; + + ScrollSpyNav.prototype.process = function() { + var scrollTop = this.$window.scrollTop(); + var options = this.options; + var inViews = []; + var $links = this.$links; + + var $targets = this.$targets; + + $targets.each(function(i, target) { + if (UI.utils.isInView(target, options)) { + inViews.push(target); + } + }); + + // console.log(inViews.length); + + if (inViews.length) { + var $target; + + $.each(inViews, function(i, item) { + if ($(item).offset().top >= scrollTop) { + $target = $(item); + return false; // break + } + }); + + if (!$target) { + return; + } + + if (options.closest) { + $links.closest(options.closest).removeClass(options.className.active); + $links.filter('a[href="#' + $target.attr('id') + '"]'). + closest(options.closest).addClass(options.className.active); + } else { + $links.removeClass(options.className.active). + filter('a[href="#' + $target.attr('id') + '"]'). + addClass(options.className.active); + } + } + }; + + ScrollSpyNav.prototype.scrollProcess = function() { + var $links = this.$links; + var options = this.options; + + // smoothScroll + if (options.smooth && $.fn.smoothScroll) { + $links.on('click', function(e) { + e.preventDefault(); + + var $this = $(this); + var $target = $($this.attr('href')); + + if (!$target) { + return; + } + + var offsetTop = options.offsetTop && + !isNaN(parseInt(options.offsetTop)) && parseInt(options.offsetTop) || 0; + + $(window).smoothScroll({position: $target.offset().top - offsetTop}); + }); + } + }; + + // ScrollSpyNav Plugin + UI.plugin('scrollspynav', ScrollSpyNav); + + // Init code + UI.ready(function(context) { + $('[data-am-scrollspynav]', context).scrollspynav(); + }); + + module.exports = ScrollSpyNav; + + // TODO: 1. 算法改进 + // 2. 多级菜单支持 + // 3. smooth scroll pushState + + +/***/ }, +/* 23 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + var rAF = UI.utils.rAF; + var cAF = UI.utils.cancelAF; + + /** + * Smooth Scroll + * @param position + * @via http://mir.aculo.us/2014/01/19/scrolling-dom-elements-to-the-top-a-zepto-plugin/ + */ + + // Usage: $(window).smoothScroll([options]) + + // only allow one scroll to top operation to be in progress at a time, + // which is probably what you want + var smoothScrollInProgress = false; + + var SmoothScroll = function(element, options) { + options = options || {}; + + var $this = $(element); + var targetY = parseInt(options.position) || SmoothScroll.DEFAULTS.position; + var initialY = $this.scrollTop(); + var lastY = initialY; + var delta = targetY - initialY; + // duration in ms, make it a bit shorter for short distances + // this is not scientific and you might want to adjust this for + // your preferences + var speed = options.speed || + Math.min(750, Math.min(1500, Math.abs(initialY - targetY))); + // temp variables (t will be a position between 0 and 1, y is the calculated scrollTop) + var start; + var t; + var y; + var cancelScroll = function() { + abort(); + }; + + // abort if already in progress or nothing to scroll + if (smoothScrollInProgress) { + return; + } + + if (delta === 0) { + return; + } + + // quint ease-in-out smoothing, from + // https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/penner.js#L127-L136 + function smooth(pos) { + if ((pos /= 0.5) < 1) { + return 0.5 * Math.pow(pos, 5); + } + + return 0.5 * (Math.pow((pos - 2), 5) + 2); + } + + function abort() { + $this.off('touchstart.smoothscroll.amui', cancelScroll); + smoothScrollInProgress = false; + } + + // when there's a touch detected while scrolling is in progress, abort + // the scrolling (emulates native scrolling behavior) + $this.on('touchstart.smoothscroll.amui', cancelScroll); + smoothScrollInProgress = true; + + // start rendering away! note the function given to frame + // is named "render" so we can reference it again further down + function render(now) { + if (!smoothScrollInProgress) { + return; + } + if (!start) { + start = now; + } + + // calculate t, position of animation in [0..1] + t = Math.min(1, Math.max((now - start) / speed, 0)); + // calculate the new scrollTop position (don't forget to smooth) + y = Math.round(initialY + delta * smooth(t)); + // bracket scrollTop so we're never over-scrolling + if (delta > 0 && y > targetY) { + y = targetY; + } + if (delta < 0 && y < targetY) { + y = targetY; + } + + // only actually set scrollTop if there was a change fromt he last frame + if (lastY != y) { + $this.scrollTop(y); + } + + lastY = y; + // if we're not done yet, queue up an other frame to render, + // or clean up + if (y !== targetY) { + cAF(scrollRAF); + scrollRAF = rAF(render); + } else { + cAF(scrollRAF); + abort(); + } + } + + var scrollRAF = rAF(render); + }; + + SmoothScroll.DEFAULTS = { + position: 0 + }; + + $.fn.smoothScroll = function(option) { + return this.each(function() { + new SmoothScroll(this, option); + }); + }; + + // Init code + $(document).on('click.smoothScroll.amui.data-api', '[data-am-smooth-scroll]', + function(e) { + e.preventDefault(); + var options = UI.utils.parseOptions($(this).data('amSmoothScroll')); + + $(window).smoothScroll(options); + }); + + module.exports = SmoothScroll; + + +/***/ }, +/* 24 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var $ = __webpack_require__(1); + var UI = __webpack_require__(2); + // require('./ui.dropdown'); + + // Make jQuery :contains Case-Insensitive + $.expr[':'].containsNC = function(elem, i, match, array) { + return (elem.textContent || elem.innerText || '').toLowerCase(). + indexOf((match[3] || '').toLowerCase()) >= 0; + }; + + /** + * Selected + * @desc HTML select replacer + * @via https://github.com/silviomoreto/bootstrap-select + * @license https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE + * @param element + * @param options + * @constructor + */ + + var Selected = function(element, options) { + this.$element = $(element); + this.options = $.extend({}, Selected.DEFAULTS, { + placeholder: element.getAttribute('placeholder') || + Selected.DEFAULTS.placeholder + }, options); + this.$originalOptions = this.$element.find('option'); + this.multiple = element.multiple; + this.$selector = null; + this.initialized = false; + this.init(); + }; + + Selected.DEFAULTS = { + btnWidth: null, + btnSize: null, + btnStyle: 'default', + dropUp: 0, + maxHeight: null, + maxChecked: null, + placeholder: '点击选择...', + selectedClass: 'am-checked', + disabledClass: 'am-disabled', + searchBox: false, + tpl: '
        ' + + ' ' + + '
        ' + + '

        ' + + '返回

        ' + + ' <% if (searchBox) { %>' + + ' ' + + ' <% } %>' + + '
          ' + + ' <% for (var i = 0; i < options.length; i++) { %>' + + ' <% var option = options[i] %>' + + ' <% if (option.header) { %>' + + '
        • ' + + ' <%= option.text %>
        • ' + + ' <% } else { %>' + + '
        • ' + + ' <%= option.text %>' + + '
        • ' + + ' <% } %>' + + ' <% } %>' + + '
        ' + + '
        ' + + '
        ' + + '
        ', + listTpl: '<% for (var i = 0; i < options.length; i++) { %>' + + ' <% var option = options[i] %>' + + ' <% if (option.header) { %>' + + '
      4. ' + + ' <%= option.text %>
      5. ' + + ' <% } else { %>' + + '
      6. ' + + ' <%= option.text %>' + + '
      7. ' + + ' <% } %>' + + ' <% } %>' + }; + + Selected.prototype.init = function() { + var _this = this; + var $element = this.$element; + var options = this.options; + + $element.hide(); + + var data = { + id: UI.utils.generateGUID('am-selected'), + multiple: this.multiple, + options: [], + searchBox: options.searchBox, + dropUp: options.dropUp, + placeholder: options.placeholder + }; + + this.$selector = $(UI.template(this.options.tpl, data)); + // set select button styles + this.$selector.css({width: this.options.btnWidth}); + + this.$list = this.$selector.find('.am-selected-list'); + this.$searchField = this.$selector.find('.am-selected-search input'); + this.$hint = this.$selector.find('.am-selected-hint'); + + var $selectorBtn = this.$selector.find('.am-selected-btn'); + var btnClassNames = []; + + options.btnSize && btnClassNames.push('am-btn-' + options.btnSize); + options.btnStyle && btnClassNames.push('am-btn-' + options.btnStyle); + $selectorBtn.addClass(btnClassNames.join(' ')); + + this.$selector.dropdown({ + justify: $selectorBtn + }); + + // disable Selected instance if is disabled + // should call .disable() after Dropdown initialed + if ($element[0].disabled) { + this.disable(); + } + + // set list height + if (options.maxHeight) { + this.$selector.find('.am-selected-list').css({ + 'max-height': options.maxHeight, + 'overflow-y': 'scroll' + }); + } + + // set hint text + var hint = []; + var min = $element.attr('minchecked'); + var max = $element.attr('maxchecked') || options.maxChecked; + + this.maxChecked = max || Infinity; + + if ($element[0].required) { + hint.push('必选'); + } + + if (min || max) { + min && hint.push('至少选择 ' + min + ' 项'); + max && hint.push('至多选择 ' + max + ' 项'); + } + + this.$hint.text(hint.join(',')); + + // render dropdown list + this.renderOptions(); + + // append $selector after